Author: jbarrez
Date: 2009-07-28 15:54:58 -0400 (Tue, 28 Jul 2009)
New Revision: 5361
Added:
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/cache/
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/cache/RepositoryCacheTest.java
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.cfg.xml
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.hibernate.cfg.xml
Modified:
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteDeploymentCmd.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCache.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCacheImpl.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java
Log:
JBPM:2360 check and fix deletion of a deployment in cluster
Modified:
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteDeploymentCmd.java
===================================================================
---
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteDeploymentCmd.java 2009-07-28
12:58:30 UTC (rev 5360)
+++
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteDeploymentCmd.java 2009-07-28
19:54:58 UTC (rev 5361)
@@ -89,7 +89,7 @@
session.delete(deployment);
RepositoryCache repositoryCache = environment.get(RepositoryCache.class);
- repositoryCache.set(deploymentId, null);
+ repositoryCache.remove(deploymentId);
return null;
}
Modified:
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCache.java
===================================================================
---
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCache.java 2009-07-28
12:58:30 UTC (rev 5360)
+++
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCache.java 2009-07-28
19:54:58 UTC (rev 5361)
@@ -22,6 +22,7 @@
package org.jbpm.pvm.internal.repository;
import java.util.Map;
+import java.util.Set;
/**
@@ -31,6 +32,7 @@
void set(String deploymentId, Map<String, Object> deployedObjects);
Object get(String deploymentId, String objectName);
+ Set<String> getCachedDeploymentIds();
void remove(String deploymentId);
void clear();
}
Modified:
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCacheImpl.java
===================================================================
---
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCacheImpl.java 2009-07-28
12:58:30 UTC (rev 5360)
+++
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositoryCacheImpl.java 2009-07-28
19:54:58 UTC (rev 5361)
@@ -21,8 +21,10 @@
*/
package org.jbpm.pvm.internal.repository;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
/**
@@ -55,6 +57,13 @@
}
}
}
+
+ public Set<String> getCachedDeploymentIds() {
+ if (deployments != null) {
+ return deployments.keySet();
+ }
+ return Collections.emptySet();
+ }
public void remove(String deploymentDbid) {
if (deployments!=null) {
Modified:
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java
===================================================================
---
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java 2009-07-28
12:58:30 UTC (rev 5360)
+++
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java 2009-07-28
19:54:58 UTC (rev 5361)
@@ -21,6 +21,7 @@
*/
package org.jbpm.pvm.internal.repository;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -148,7 +149,12 @@
if (processDefinition!=null) {
return findProcessDefinitionById(processDefinition.getId());
+ } else {
+ validateRepositoryCache();
}
+
+ // if null -> invalidate cache?
+ System.out.println("---------------->" +
repositoryCache.get("1", "test_process"));
return null;
}
@@ -161,7 +167,12 @@
String objectName = deploymentProperty.getObjectName();
return (ProcessDefinitionImpl) getObject(deploymentId, objectName);
+ } else {
+ validateRepositoryCache();
}
+
+ // ? if null -> delete from cache?
+ System.out.println("---------------->" +
repositoryCache.get("1", "test_process"));
return null;
}
@@ -175,4 +186,28 @@
).setMaxResults(1).uniqueResult();
return deploymentProperty;
}
+
+ /**
+ * Checks if every entry in the repositoryCache is still valid.
+ * If the entry is not found in the database, it is deleted from the cache.
+ */
+ @SuppressWarnings("unchecked")
+ private void validateRepositoryCache() {
+
+ log.trace("Validating repository cache ... ");
+ Set<Long> dbIds = new HashSet<Long>(session.createQuery("select dbid
from " +
+ DeploymentImpl.class.getName() + " as deployment ")
+ .setReadOnly(true)
+ .list());
+
+ Set<String> cachedIds = repositoryCache.getCachedDeploymentIds();
+ for (String cachedId : cachedIds) {
+ if (!dbIds.contains(Long.valueOf(cachedId))) {
+ log.trace("Invalid entry in repositorycache found, removing now deployment
id " + cachedId);
+ repositoryCache.remove(cachedId);
+ }
+ }
+
+ }
+
}
Added:
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/cache/RepositoryCacheTest.java
===================================================================
---
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/cache/RepositoryCacheTest.java
(rev 0)
+++
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/cache/RepositoryCacheTest.java 2009-07-28
19:54:58 UTC (rev 5361)
@@ -0,0 +1,131 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+/**
+ *
+ */
+package org.jbpm.test.cache;
+
+import org.jbpm.api.Configuration;
+import org.jbpm.api.Execution;
+import org.jbpm.api.ExecutionService;
+import org.jbpm.api.JbpmException;
+import org.jbpm.api.ProcessEngine;
+import org.jbpm.api.ProcessInstance;
+import org.jbpm.test.JbpmTestCase;
+
+
+/**
+ * Test case for the correct working of the repositoryCache.
+ *
+ * @author Joram Barrez
+ */
+public class RepositoryCacheTest extends JbpmTestCase {
+
+ private static final String PROCESS_KEY = "test_process";
+
+ private static final String TEST_PROCESS =
+ "<process name='" + PROCESS_KEY + "'>" +
+ " <start>" +
+ " <transition to='a' />" +
+ " </start>" +
+ " <state name='a'>" +
+ " <transition to='theEnd' />" +
+ " </state>" +
+ " <end name='theEnd' />" +
+ "</process>";
+
+ /**
+ * Test for JBPM-2360:
+ *
+ * When a deployment is deleted, the entry is also removed from the
+ * repositoryCache. However, in a clustered environment, the deletion from the
+ * cache is done only on the node on which the deletion operation is invoked.
+ * This means that the other nodes are unaware of the deletion and the
+ * deployment is not deleted from the cache.
+ *
+ * This test emulates this scenario using two process engines which use
+ * the same database. One will delete a deployment. The second one must
+ * throw an exception when it tries to use the deployment.
+ * * When starting a new process
+ * * When signalling an execution which has a deleted deployment
+ */
+ public void testDeleteDeploymentsUsingTwoProcessEngines() {
+
+ ProcessEngine processEngine2 = createProcessEngineFromAlternativeConfig();
+ ExecutionService executionService2 = processEngine2.getExecutionService();
+ assertFalse(processEngine.equals(processEngine2));
+ assertFalse(executionService.equals(executionService2));
+
+ // Deploy the process through the first process engine
+ String deployId = repositoryService.createDeployment()
+ .addResourceFromString("test_process.jpdl.xml",
TEST_PROCESS)
+ .deploy();
+
+ // Start process instance on first process engine
+ ProcessInstance pi1 = executionService.startProcessInstanceByKey(PROCESS_KEY);
+ Execution executionAtWaitState1 = pi1.findActiveExecutionIn("a");
+ assertActivityActive(pi1.getId(), "a");
+
+ // Now start process instance on second process engine
+ ProcessInstance pi2 = executionService2.startProcessInstanceByKey(PROCESS_KEY);
+ Execution executionAtWaitState2 = pi1.findActiveExecutionIn("a");
+ assertActivityActive(pi2.getId(), "a");
+
+ // Delete the deployment through the first process engine
+ repositoryService.deleteDeploymentCascade(deployId);
+
+ // Trying to find the two active process instances should fail now
+ assertNull(executionService.findExecutionById(pi1.getId()));
+ assertNull(executionService.findExecutionById(pi2.getId()));
+
+ // Try to start the process through the first process engine.
+ // This should fail (since the deployment was deleted).
+ try {
+ executionService.startProcessInstanceByKey(PROCESS_KEY);
+ fail();
+ } catch (JbpmException e) { }
+
+ // Try to start the process through the second process engine.
+ // This should also fail (ie caches should be updated on both side).
+ try {
+ executionService2.startProcessInstanceByKey(PROCESS_KEY);
+ fail();
+ } catch (JbpmException e) { }
+
+ // Try to signal a process that was active before the deletion. This should also
fail.
+ try {
+ executionService.signalExecutionById(executionAtWaitState1.getId());
+ fail();
+ } catch (JbpmException e) { }
+ try {
+ executionService2.signalExecutionById(executionAtWaitState2.getId());
+ fail();
+ } catch (JbpmException e) { }
+
+ }
+
+ private ProcessEngine createProcessEngineFromAlternativeConfig() {
+ Configuration configuration = new
Configuration().setResource("org/jbpm/test/cache/jbpm_alternative.cfg.xml");
+ return configuration.buildProcessEngine();
+ }
+
+}
Added:
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.cfg.xml
===================================================================
---
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.cfg.xml
(rev 0)
+++
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.cfg.xml 2009-07-28
19:54:58 UTC (rev 5361)
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+ <!--
+
+ Alternative configuration: * no create-drop for the database
+ -->
+
+<jbpm-configuration>
+
+ <process-engine-context>
+
+ <repository-service />
+ <repository-cache />
+ <execution-service />
+ <history-service />
+ <management-service />
+ <identity-service />
+ <task-service />
+
+ <hibernate-configuration>
+ <cfg resource="org/jbpm/test/cache/jbpm_alternative.hibernate.cfg.xml"
/>
+ </hibernate-configuration>
+
+ <hibernate-session-factory />
+
+ <script-manager default-expression-language="juel"
+ default-script-language="juel">
+ <script-language name="juel"
+ factory="org.jbpm.pvm.internal.script.JuelScriptEngineFactory" />
+ </script-manager>
+
+ <id-generator />
+ <types resource="jbpm.variable.types.xml" />
+
+ <address-resolver />
+
+ </process-engine-context>
+
+ <transaction-context>
+ <repository-session />
+ <db-session />
+
+ <message-session />
+ <timer-session />
+ <history-session />
+ <mail-session>
+ <mail-server>
+ <session-properties resource="jbpm.mail.properties" />
+ </mail-server>
+ </mail-session>
+ </transaction-context>
+
+ <import resource="jbpm.businesscalendar.cfg.xml" />
+ <import resource="jbpm.tx.hibernate.cfg.xml" />
+ <import resource="jbpm.jpdl.cfg.xml" />
+ <import resource="jbpm.identity.cfg.xml" />
+
+</jbpm-configuration>
Added:
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.hibernate.cfg.xml
===================================================================
---
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.hibernate.cfg.xml
(rev 0)
+++
jbpm4/trunk/modules/test-db/src/test/resources/org/jbpm/test/cache/jbpm_alternative.hibernate.cfg.xml 2009-07-28
19:54:58 UTC (rev 5361)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+ <session-factory>
+
+ <!-- HSQLDB -->
+ <property
name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
+ <property
name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
+ <property
name="hibernate.connection.url">jdbc:hsqldb:mem:.</property>
+ <property name="hibernate.connection.username">sa</property>
+ <property name="hibernate.connection.password"></property>
+
+ <!-- Alternative config: no create-drop -->
+ <property name="hibernate.hbm2ddl.auto">update</property>
+ <property name="hibernate.format_sql">true</property>
+
+ <mapping resource="jbpm.repository.hbm.xml" />
+ <mapping resource="jbpm.execution.hbm.xml" />
+ <mapping resource="jbpm.history.hbm.xml" />
+ <mapping resource="jbpm.task.hbm.xml" />
+ <mapping resource="jbpm.identity.hbm.xml" />
+
+ </session-factory>
+</hibernate-configuration>