Index: main/plugin-workflow/plugin.xml
===================================================================
--- main/plugin-workflow/plugin.xml	(revision 40268)
+++ main/plugin-workflow/plugin.xml	(working copy)
@@ -27,13 +27,22 @@
 		</components>
 	</feature>
 
-	<feature name="workflow-store">
+	<feature name="workflow-store-jcr">
 		<components>
-		    <!-- Component for storing workflow instances -->
+		    <!-- Component for storing workflow instances with JCR-->
 			<component role="com.opensymphony.workflow.spi.WorkflowStore"
                        class="org.ametys.plugins.workflow.store.AvalonJackrabbitWorkflowStore"/>
 		</components>
 	</feature>
+    
+    <feature name="workflow-store-jdbc">
+        <components>
+            <!-- Component for storing workflow instances with JDBC-->
+            <component role="org.ametys.plugins.workflow.store.JdbcWorkflowStore"
+                       class="org.ametys.plugins.workflow.store.JdbcWorkflowStore"
+                       logger="org.ametys.plugins.workflow.store.JdbcWorkflowStore"/>
+       </components>
+    </feature>	
 	
 	<feature name="condition.check.rights">
 	  <components>
Index: main/plugin-workflow/scripts/derby/workflow.sql
===================================================================
--- main/plugin-workflow/scripts/derby/workflow.sql	(revision 0)
+++ main/plugin-workflow/scripts/derby/workflow.sql	(revision 0)
@@ -0,0 +1,111 @@
+--
+--  Copyright 2009 Anyware Services
+--
+--  Licensed under the Apache License, Version 2.0 (the "License");
+--  you may not use this file except in compliance with the License.
+--  You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+
+--_ignore_exceptions_=on
+DROP TABLE OS_PROPERTYENTRY;
+DROP TABLE OS_CURRENTSTEP_PREV;
+DROP TABLE OS_HISTORYSTEP_PREV;
+DROP TABLE OS_CURRENTSTEP;
+DROP TABLE OS_HISTORYSTEP;
+DROP TABLE OS_WFENTRY;
+DROP TABLE OS_STEPIDS;
+DROP TABLE OS_ENTRYIDS;
+--_ignore_exceptions_=off
+
+CREATE TABLE OS_PROPERTYENTRY
+(
+    GLOBAL_KEY VARCHAR(250) NOT NULL,
+    ITEM_KEY VARCHAR(250) NOT NULL,
+    ITEM_TYPE SMALLINT,
+    STRING_VALUE VARCHAR(255),
+    DATE_VALUE TIMESTAMP,
+    DATA_VALUE VARCHAR (32672) FOR BIT DATA,
+    FLOAT_VALUE FLOAT,
+    NUMBER_VALUE NUMERIC,
+    PRIMARY KEY (GLOBAL_KEY, ITEM_KEY)
+);
+
+CREATE TABLE OS_WFENTRY
+(
+    ID BIGINT NOT NULL,
+    NAME VARCHAR(255),
+    STATE INTEGER,
+    PRIMARY KEY (ID)
+);
+
+CREATE TABLE OS_CURRENTSTEP
+(
+    ID BIGINT NOT NULL,
+    ENTRY_ID BIGINT,
+    STEP_ID INTEGER,
+    ACTION_ID INTEGER,
+    OWNER VARCHAR(35),
+    START_DATE TIMESTAMP,
+    FINISH_DATE TIMESTAMP,
+    DUE_DATE TIMESTAMP,
+    STATUS VARCHAR(40),
+    CALLER VARCHAR(35),
+
+    PRIMARY KEY (ID),
+    FOREIGN KEY (ENTRY_ID) REFERENCES OS_WFENTRY(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE OS_HISTORYSTEP
+(
+    ID BIGINT NOT NULL,
+    ENTRY_ID BIGINT,
+    STEP_ID INTEGER,
+    ACTION_ID INTEGER,
+    OWNER VARCHAR(35),
+    START_DATE TIMESTAMP,
+    FINISH_DATE TIMESTAMP,
+    DUE_DATE TIMESTAMP,
+    STATUS VARCHAR(40),
+    CALLER VARCHAR(35),
+
+    PRIMARY KEY (ID),
+    FOREIGN KEY (ENTRY_ID) REFERENCES OS_WFENTRY(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE OS_CURRENTSTEP_PREV
+(
+    ID BIGINT NOT NULL,
+    PREVIOUS_ID BIGINT NOT NULL,
+    PRIMARY KEY (ID, PREVIOUS_ID),
+    FOREIGN KEY (ID) REFERENCES OS_CURRENTSTEP(ID) ON DELETE CASCADE,
+    FOREIGN KEY (PREVIOUS_ID) REFERENCES OS_HISTORYSTEP(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE OS_HISTORYSTEP_PREV
+(
+    ID BIGINT NOT NULL,
+    PREVIOUS_ID BIGINT NOT NULL,
+    PRIMARY KEY (ID, PREVIOUS_ID),
+    FOREIGN KEY (ID) REFERENCES OS_HISTORYSTEP(ID) ON DELETE CASCADE,
+    FOREIGN KEY (PREVIOUS_ID) REFERENCES OS_HISTORYSTEP(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE OS_STEPIDS
+(
+	ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
+	PRIMARY KEY (ID)
+);
+
+CREATE TABLE OS_ENTRYIDS
+(
+	ID BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
+	PRIMARY KEY (ID)
+);
Index: main/plugin-workflow/src/org/ametys/plugins/workflow/Workflow.java
===================================================================
--- main/plugin-workflow/src/org/ametys/plugins/workflow/Workflow.java	(revision 40268)
+++ main/plugin-workflow/src/org/ametys/plugins/workflow/Workflow.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -58,11 +58,11 @@
 /**
  * Singleton for manipulating workflow instances.
  */
-public final class Workflow extends AbstractWorkflow implements Component, LogEnabled, Serviceable, Initializable, Disposable
+public class Workflow extends AbstractWorkflow implements Component, LogEnabled, Serviceable, Initializable, Disposable
 {
     /** Avalon role. */
     public static final String ROLE = Workflow.class.getName();
-    
+
     /** Logger available to subclasses. */
     protected Logger _logger;
     /** Service manager. */
@@ -108,7 +108,7 @@
             }
         };
 
-        WorkflowStore store = (WorkflowStore) _manager.lookup(WorkflowStore.class.getName());
+        WorkflowStore store = _getWorkflowStore();
         WorkflowFactory factory = new XmlWorkflowFactory(_manager);
 
         try
@@ -507,4 +507,13 @@
         return complete;
     }
     
+    /**
+     * Get the {@link WorkflowStore}
+     * @return the {@link WorkflowStore}
+     * @throws ServiceException if an error occurs while looking up the workflow store
+     */
+    protected WorkflowStore _getWorkflowStore() throws ServiceException
+    {
+        return (WorkflowStore) _manager.lookup(WorkflowStore.class.getName());
+    }
 }
Index: main/plugin-workflow/src/org/ametys/plugins/workflow/store/JdbcWorkflowStore.java
===================================================================
--- main/plugin-workflow/src/org/ametys/plugins/workflow/store/JdbcWorkflowStore.java	(revision 0)
+++ main/plugin-workflow/src/org/ametys/plugins/workflow/store/JdbcWorkflowStore.java	(revision 0)
@@ -0,0 +1,405 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.ametys.plugins.workflow.store;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.avalon.framework.component.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.ametys.plugins.workflow.JDBCPropertySet;
+import org.ametys.plugins.workflow.PropertySetExpression;
+import org.ametys.runtime.config.Config;
+import org.ametys.runtime.datasource.ConnectionHelper;
+import org.ametys.runtime.datasource.ConnectionHelper.DatabaseType;
+
+import com.opensymphony.module.propertyset.PropertySet;
+import com.opensymphony.workflow.StoreException;
+import com.opensymphony.workflow.query.Expression;
+import com.opensymphony.workflow.query.NestedExpression;
+import com.opensymphony.workflow.query.WorkflowExpressionQuery;
+import com.opensymphony.workflow.spi.jdbc.JDBCWorkflowStore;
+
+/**
+ * Ametys JDBC workflow store
+ */
+public class JdbcWorkflowStore extends JDBCWorkflowStore implements Component, NoHistoryWorkflowStore 
+{   
+    /** Avalon role. */
+    public static final String ROLE = JdbcWorkflowStore.class.getName();
+    
+    /** Logger */
+    protected Logger _logger = LoggerFactory.getLogger(JdbcWorkflowStore.class);
+    
+    /** Configured data source type */
+    protected DatabaseType _databaseType;
+    
+    /** from com.opensymphony.workflow.spi.jdbc.MySQLWorkflowStore */
+    protected String _entrySequenceIncrement;
+    /** from com.opensymphony.workflow.spi.jdbc.MySQLWorkflowStore */
+    protected String _entrySequenceRetrieve;
+    /** from com.opensymphony.workflow.spi.jdbc.MySQLWorkflowStore */
+    protected String _stepSequenceIncrement;
+    /** from com.opensymphony.workflow.spi.jdbc.MySQLWorkflowStore */
+    protected String _stepSequenceRetrieve;
+    
+    @Override
+    public void init(Map props) throws StoreException
+    {
+        // Copier les bons paramètres pour JDBCWorkflowStore
+        entryTable = "OS_WFENTRY";
+        entryId = "ID";
+        entryName = "NAME";
+        entryState = "STATE";
+        historyTable = "OS_HISTORYSTEP";
+        historyPrevTable = "OS_HISTORYSTEP_PREV";
+        currentTable = "OS_CURRENTSTEP";
+        currentPrevTable = "OS_CURRENTSTEP_PREV";
+        stepId = "ID";
+        stepEntryId = "ENTRY_ID";
+        stepStepId = "STEP_ID";
+        stepActionId = "ACTION_ID";
+        stepOwner = "OWNER";
+        stepCaller = "CALLER";
+        stepStartDate = "START_DATE";
+        stepFinishDate = "FINISH_DATE";
+        stepDueDate = "DUE_DATE";
+        stepStatus = "STATUS";
+        stepPreviousId = "PREVIOUS_ID";
+        
+        DatabaseType databaseType;
+        try
+        {
+            databaseType = getDatabaseType();
+        }
+        catch (SQLException e)
+        {
+            throw new StoreException("Unable to retrieve database type", e);
+        }
+        
+        // DATABASE_MYSQL
+        if (DatabaseType.DATABASE_MYSQL.equals(databaseType))
+        {
+            _entrySequenceIncrement = "INSERT INTO OS_ENTRYIDS (ID) values (null)";
+            _entrySequenceRetrieve = "SELECT LAST_INSERT_ID()";
+            _stepSequenceIncrement = "INSERT INTO OS_STEPIDS (ID) values (null)";
+            _stepSequenceRetrieve = "SELECT LAST_INSERT_ID()";
+        }
+        
+        // DATABASE_DERBY
+        else if (DatabaseType.DATABASE_DERBY.equals(databaseType))
+        {
+            _entrySequenceIncrement = "INSERT INTO OS_ENTRYIDS values (DEFAULT)";
+            _entrySequenceRetrieve = "VALUES IDENTITY_VAL_LOCAL()";
+            _stepSequenceIncrement = "INSERT INTO OS_STEPIDS values (DEFAULT)";
+            _stepSequenceRetrieve = "VALUES IDENTITY_VAL_LOCAL()";
+        }
+        
+        // DATABASE_POSTGRES
+        else if (DatabaseType.DATABASE_POSTGRES.equals(databaseType))
+        {
+            entrySequence = "SELECT nextval('seq_os_wfentry')";
+            stepSequence = "SELECT nextval('seq_os_currentsteps')";
+        }
+        
+        // DATABASE_ORACLE
+        else if (DatabaseType.DATABASE_ORACLE.equals(databaseType))
+        {
+            entrySequence = "SELECT seq_os_wfentry.nextval from dual";
+            stepSequence = "SELECT seq_os_currentsteps.nextval from dual";
+        }
+        
+        // DATABASE_HSQLDB
+        else if (DatabaseType.DATABASE_HSQLDB.equals(databaseType))
+        {
+            entrySequence = "call next value for seq_os_wfentry";
+            stepSequence = "call next value for seq_os_currentsteps";
+        }
+        else
+        {
+            throw new IllegalArgumentException(String.format("Unsupported database type '%s'", databaseType));
+        }
+    }
+    
+    @Override
+    protected Connection getConnection() throws SQLException
+    {
+        // Si faux consomme tout le pool de connexions
+        closeConnWhenDone = true;
+
+        // Ne pas utiliser JNDI mais un pool de connexions de cocoon
+        return ConnectionHelper.getConnection(ConnectionHelper.CORE_POOL_NAME);
+    }
+
+    
+    /**
+     * Database type getter
+     * @return The database type
+     * @throws SQLException on error
+     */
+    protected DatabaseType getDatabaseType() throws SQLException
+    {
+        if (_databaseType == null)
+        {
+            String databaseURL = Config.getInstance().getValueAsString("runtime.datasource.core.jdbc.url");
+            _databaseType = ConnectionHelper.getDatabaseType(databaseURL);
+        }
+        
+        return _databaseType;
+    }
+    
+    @Override
+    public PropertySet getPropertySet(long id)
+    {
+        // Utiliser notre propre property set (cocoon connection pool)
+        Map<String, String> args = new HashMap<String, String>(1);
+        args.put("globalKey", JDBCPropertySet.OSWF_PREFIX + id);
+        
+        Map<String, Object> config = new HashMap<String, Object>();
+        
+        PropertySet ps = new JDBCPropertySet();
+        ps.init(config, args);
+        return ps;
+    }
+    
+    @Override
+    protected void cleanup(Connection connection, Statement statement, ResultSet result)
+    {
+        try
+        {
+            if (result != null)
+            {
+                try
+                {
+                    result.close();
+                }
+                catch (SQLException e)
+                {
+                    _logger.error("Error closing result resource", e);
+                }
+            }
+
+            if (statement != null)
+            {
+                try
+                {
+                    statement.close();
+                }
+                catch (SQLException e)
+                {
+                    _logger.error("Error closing statement resource", e);
+                }
+            }
+
+            if (connection != null && closeConnWhenDone)
+            {
+                // Committer la transaction lors de la fermeture
+                if (!connection.getAutoCommit())
+                {
+                    try
+                    {
+                        connection.commit();
+                    }
+                    catch (SQLException e)
+                    {
+                        _logger.error("Error while commiting connection", e);
+                    }
+                }
+
+                connection.close();
+            }
+        }
+        catch (SQLException e)
+        {
+            _logger.error("Error closing databases resources", e);
+        }
+    }
+
+    @Override
+    public void deleteInstance(long idWorkflow)
+    {
+        Connection c = null;
+        PreparedStatement stmt = null;
+
+        try
+        {
+            // Récupérer la connexion du pool
+            c = getConnection();
+            // Supprimer les entrées récursivement grâce aux "ON DELETE CASCADE"
+            // Supprime dans l'ordre les lignes correspondantes des tables
+            // OS_HISTORYSTEP_PREV, OS_CURRENTSTEP_PREV, OS_HISTORYSTEP,
+            // OS_CURRENTSTEP
+            String sql = "DELETE FROM " + entryTable + " WHERE " + entryId + " = ?";
+            // Exécuter la requête
+            stmt = c.prepareStatement(sql);
+            // Positionner l'identifiant de l'instance du workflow
+            stmt.setLong(1, idWorkflow);
+
+            // Logger la requête
+            _logger.debug(sql);
+
+            // Vérifier si une ligne a bien été supprimée
+            if (stmt.executeUpdate() != 1)
+            {
+                _logger.error("Unable to remove a workflow instance in database");
+            }
+        }
+        catch (SQLException ex)
+        {
+            _logger.error("Error while removing a workflow instance", ex);
+        }
+        finally
+        {
+            cleanup(c, stmt, null);
+        }
+    }
+
+    public void clearHistory(long idWorkflow)
+    {
+        Connection c = null;
+        PreparedStatement stmt = null;
+
+        try
+        {
+            // Récupérer la connexion du pool
+            c = getConnection();
+            // Supprimer les entrées récursivement grâce aux "ON DELETE CASCADE"
+            // Supprime dans l'ordre les lignes correspondantes des tables
+            // OS_HISTORYSTEP_PREV, OS_CURRENTSTEP_PREV, OS_HISTORYSTEP
+            String sql = "DELETE FROM " + historyTable + " WHERE " + stepEntryId + " = ?";
+            // Exécuter la requête
+            stmt = c.prepareStatement(sql);
+            // Positionner l'identifiant de l'instance du workflow
+            stmt.setLong(1, idWorkflow);
+
+            // Logger la requête
+            _logger.debug(sql);
+
+            // Supprimer les éventuelles lignes
+            stmt.executeUpdate();
+        }
+        catch (SQLException e)
+        {
+            _logger.error("Error while clearing history steps from an workflow instance", e);
+        }
+        finally
+        {
+            cleanup(c, stmt, null);
+        }
+    }
+
+    @Override
+    public List query(WorkflowExpressionQuery e) throws StoreException
+    {
+        Expression expression = e.getExpression();
+
+        if (expression instanceof PropertySetExpression)
+        {
+            return JDBCPropertySet.query(expression);
+        }
+        else if (expression instanceof NestedExpression)
+        {
+            NestedExpression expr = (NestedExpression) expression;
+
+            // Vérifier qu'il n'y ait pas autre chose que du PropertySet
+            // imbriqué avant de l'envoyer au JDBCPropertySet
+            if (JDBCPropertySet.isPropertySetExpressionsNested(expr))
+            {
+                return JDBCPropertySet.query(expression);
+            }
+
+            return super.query(e);
+        }
+        else
+        {
+            return super.query(e);
+        }
+    }
+    
+    @Override
+    protected long getNextEntrySequence(Connection c) throws SQLException
+    {
+        // DATABASE_MYSQL - DATABASE_DERBY
+        DatabaseType databaseType = getDatabaseType();
+        if (DatabaseType.DATABASE_MYSQL.equals(databaseType) || DatabaseType.DATABASE_DERBY.equals(databaseType))
+        {
+            PreparedStatement stmt = null;
+            ResultSet rset = null;
+            
+            try
+            {
+                stmt = c.prepareStatement(_entrySequenceIncrement);
+                stmt.executeUpdate();
+                rset = c.createStatement().executeQuery(_entrySequenceRetrieve);
+                
+                rset.next();
+                
+                long id = rset.getLong(1);
+                
+                return id;
+            }
+            finally
+            {
+                cleanup(null, stmt, rset);
+            }
+        }
+        else
+        {
+            return super.getNextEntrySequence(c);
+        }
+    }
+
+    @Override
+    protected long getNextStepSequence(Connection c) throws SQLException
+    {
+        // DATABASE_MYSQL - DATABASE_DERBY
+        DatabaseType databaseType = getDatabaseType();
+        if (DatabaseType.DATABASE_MYSQL.equals(databaseType) || DatabaseType.DATABASE_DERBY.equals(databaseType))
+        {
+            PreparedStatement stmt = null;
+            ResultSet rset = null;
+            
+            try
+            {
+                stmt = c.prepareStatement(_stepSequenceIncrement);
+                stmt.executeUpdate();
+                rset = c.createStatement().executeQuery(_stepSequenceRetrieve);
+                
+                rset.next();
+                
+                long id = rset.getLong(1);
+                
+                return id;
+            }
+            finally
+            {
+                cleanup(null, stmt, rset);
+            }
+        }
+        else
+        {
+            return super.getNextEntrySequence(c);
+        }
+    }
+}
Index: test/environment/config-derby.xml
===================================================================
--- test/environment/config-derby.xml	(revision 0)
+++ test/environment/config-derby.xml	(revision 0)
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2016 Anyware Services
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   -->
+<config>
+    <runtime.datasource.core.jdbc.driver>org.apache.derby.jdbc.EmbeddedDriver</runtime.datasource.core.jdbc.driver>
+    <runtime.datasource.core.jdbc.url>jdbc:derby:tmp/derby;create=true</runtime.datasource.core.jdbc.url>
+    <runtime.datasource.core.jdbc.user/>
+    <runtime.datasource.core.jdbc.passwd/>
+    <runtime.authentication.basic.realm>realm</runtime.authentication.basic.realm>
+    <runtime.upload.max-size>10000000</runtime.upload.max-size>
+    <runtime.upload.dir>WEB-INF/data/uploads</runtime.upload.dir>
+    <content.unlocktimer.activate>false</content.unlocktimer.activate>
+	<content.unlocktimer.period>2</content.unlocktimer.period>
+	<org.ametys.plugins.repository.home>WEB-INF/data/repository</org.ametys.plugins.repository.home>
+	<org.ametys.plugins.repository.cache>16777216</org.ametys.plugins.repository.cache>
+	<repository.default.sort>document</repository.default.sort>
+	<runtime.debug.ui>true</runtime.debug.ui>
+	<runtime.cache.xslt>false</runtime.cache.xslt>
+</config>
Index: test/src/org/ametys/plugins/workflow/AllTests.java
===================================================================
--- test/src/org/ametys/plugins/workflow/AllTests.java	(revision 40268)
+++ test/src/org/ametys/plugins/workflow/AllTests.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -15,14 +15,14 @@
  */
 package org.ametys.plugins.workflow;
 
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
+import org.ametys.plugins.workflow.store.DerbyWorkflowStoreTestCase;
 import org.ametys.plugins.workflow.store.JackrabbitWorkflowStoreTestCase;
 import org.ametys.plugins.workflow.store.MysqlWorkflowStoreTestCase;
 import org.ametys.plugins.workflow.store.OracleWorkflowStoreTestCase;
 import org.ametys.plugins.workflow.store.PostgresWorkflowStoreTestCase;
 
+import junit.framework.Test;
+import junit.framework.TestSuite;
 
 /**
  * {@link TestSuite} grouping all workflow tests.
@@ -42,6 +42,7 @@
         suite.addTestSuite(MysqlWorkflowStoreTestCase.class);
         suite.addTestSuite(OracleWorkflowStoreTestCase.class);
         suite.addTestSuite(PostgresWorkflowStoreTestCase.class);
+        suite.addTestSuite(DerbyWorkflowStoreTestCase.class);
         
         return suite;
     }
Index: test/src/org/ametys/plugins/workflow/store/AbstractJdbcNoHistoryWorkflowStoreTestCase.java
===================================================================
--- test/src/org/ametys/plugins/workflow/store/AbstractJdbcNoHistoryWorkflowStoreTestCase.java	(revision 40268)
+++ test/src/org/ametys/plugins/workflow/store/AbstractJdbcNoHistoryWorkflowStoreTestCase.java	(working copy)
@@ -16,12 +16,13 @@
 package org.ametys.plugins.workflow.store;
 
 import java.io.FileInputStream;
-
-import junit.framework.TestCase;
+import java.util.Collections;
 
-import org.ametys.plugins.workflow.store.NoHistoryWorkflowStore;
+import org.ametys.runtime.test.Init;
 import org.ametys.runtime.test.ScriptRunner;
 
+import junit.framework.TestCase;
+
 /**
  * Abstract {@link TestCase} for validating a JDBC {@link NoHistoryWorkflowStore}.
  */
@@ -56,5 +57,10 @@
      * @return the workflow store to test.
      * @throws Exception if an error occurs.
      */
-    protected abstract NoHistoryWorkflowStore _internalCreateWorkflowStore() throws Exception;
+    protected NoHistoryWorkflowStore _internalCreateWorkflowStore() throws Exception
+    {
+        JdbcWorkflowStore workflowStore = (JdbcWorkflowStore) Init.getPluginServiceManager().lookup(JdbcWorkflowStore.ROLE);
+        workflowStore.init(Collections.EMPTY_MAP);
+        return workflowStore;
+    }
 }
Index: test/src/org/ametys/plugins/workflow/store/DerbyWorkflowStoreTestCase.java
===================================================================
--- test/src/org/ametys/plugins/workflow/store/DerbyWorkflowStoreTestCase.java	(revision 0)
+++ test/src/org/ametys/plugins/workflow/store/DerbyWorkflowStoreTestCase.java	(revision 0)
@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2016 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.ametys.plugins.workflow.store;
+
+import junit.framework.TestCase;
+
+/**
+ * {@link TestCase} for validating the {@link DerbyWorkflowStoreTestCase}.
+ */
+public class DerbyWorkflowStoreTestCase extends AbstractJdbcNoHistoryWorkflowStoreTestCase
+{
+    /**
+     * Creates the test case.
+     * @param name the test case name.
+     */
+    public DerbyWorkflowStoreTestCase(String name)
+    {
+        super(name);
+    }
+    
+    @Override
+    protected String _getConfigFilename()
+    {
+        return "config-derby.xml";
+    }
+    
+    @Override
+    protected String _getRDBMName()
+    {
+        return "derby";
+    }
+}
Index: test/src/org/ametys/plugins/workflow/store/MysqlWorkflowStoreTestCase.java
===================================================================
--- test/src/org/ametys/plugins/workflow/store/MysqlWorkflowStoreTestCase.java	(revision 40268)
+++ test/src/org/ametys/plugins/workflow/store/MysqlWorkflowStoreTestCase.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -15,11 +15,6 @@
  */
 package org.ametys.plugins.workflow.store;
 
-import java.util.Collections;
-
-import org.ametys.plugins.workflow.store.MysqlWorkflowStore;
-import org.ametys.plugins.workflow.store.NoHistoryWorkflowStore;
-
 import junit.framework.TestCase;
 
 /**
@@ -41,12 +36,4 @@
     {
         return "mysql";
     }
-    
-    @Override
-    protected NoHistoryWorkflowStore _internalCreateWorkflowStore() throws Exception
-    {
-        MysqlWorkflowStore workflowStore = new MysqlWorkflowStore();
-        workflowStore.init(Collections.EMPTY_MAP);
-        return workflowStore;
-    }
 }
Index: test/src/org/ametys/plugins/workflow/store/OracleWorkflowStoreTestCase.java
===================================================================
--- test/src/org/ametys/plugins/workflow/store/OracleWorkflowStoreTestCase.java	(revision 40268)
+++ test/src/org/ametys/plugins/workflow/store/OracleWorkflowStoreTestCase.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -15,11 +15,6 @@
  */
 package org.ametys.plugins.workflow.store;
 
-import java.util.Collections;
-
-import org.ametys.plugins.workflow.store.NoHistoryWorkflowStore;
-import org.ametys.plugins.workflow.store.OracleWorkflowStore;
-
 import junit.framework.TestCase;
 
 /**
@@ -49,14 +44,6 @@
     }
     
     @Override
-    protected NoHistoryWorkflowStore _internalCreateWorkflowStore() throws Exception
-    {
-        OracleWorkflowStore workflowStore = new OracleWorkflowStore();
-        workflowStore.init(Collections.EMPTY_MAP);
-        return workflowStore;
-    }
-    
-    @Override
     public void testWorkflowExpressionQuery() throws Exception
     {
         // Temporary disabled till http://jira.opensymphony.com/browse/WF-489 is fixed
Index: test/src/org/ametys/plugins/workflow/store/PostgresWorkflowStoreTestCase.java
===================================================================
--- test/src/org/ametys/plugins/workflow/store/PostgresWorkflowStoreTestCase.java	(revision 40268)
+++ test/src/org/ametys/plugins/workflow/store/PostgresWorkflowStoreTestCase.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2016 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -15,11 +15,6 @@
  */
 package org.ametys.plugins.workflow.store;
 
-import java.util.Collections;
-
-import org.ametys.plugins.workflow.store.NoHistoryWorkflowStore;
-import org.ametys.plugins.workflow.store.PostgresWorkflowStore;
-
 import junit.framework.TestCase;
 
 /**
@@ -47,12 +42,4 @@
     {
         return "postgresql";
     }
-    
-    @Override
-    protected NoHistoryWorkflowStore _internalCreateWorkflowStore() throws Exception
-    {
-        PostgresWorkflowStore workflowStore = new PostgresWorkflowStore();
-        workflowStore.init(Collections.EMPTY_MAP);
-        return workflowStore;
-    }
 }
