Workspaces can be added dynamically during runtime.
This can be performed in two steps:
Firstly,
          ManageableRepository.configWorkspace(WorkspaceEntry
            wsConfig)
          
          - register a new configuration in
          RepositoryContainer and create a WorkspaceContainer.
        
Secondly, the main step,
          ManageableRepository.createWorkspace(String
            workspaceName)
          
          - creation of a new workspace.
        
Implementing a workspace data container
To implement Workspace data container, you need to do the following:
Read a bit about the contract.
Start a new implementation project pom.xml with
        org.exoplatform.jcr parent. It is not required, but will ease the development.
Update sources of JCR Core and read JavaDoc on org.exoplatform.services.jcr.storage.WorkspaceDataContainer
        and org.exoplatform.services.jcr.storage.WorkspaceStorageConnection
        interfaces. They are the main part for the implementation.
Look at org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager
        sourcecode, check how data manager uses container and its connections
        (see in the save() method)
Create WorkspaceStorageConnection dummy implementation
        class. It is a freeform class, but to be close to the eXo JCR, check how
        to implement JDBC (org.exoplatform.services.jcr.impl.storage.jdbc.JDBCStorageConnection).
        Take into account usage of ValueStoragePluginProvider in both
        implementations. Value storage is a useful option for production
        versions, but leave it to the end of the implementation work.
Create the connection implementation unit tests to play TTD. This step is optional but brings many benefits for the process.
Implement CRUD starting from, for example, the read to write. Test the methods by using the external implementation ways of data read/write in your backend.
When all methods of the connection are done, start WorkspaceDataContainer. Container class is very simple, it is like a factory for the connections only.
Care about the reuseConnection(WorkspaceStorageConnection)
        logic container method. For some backends, it can be same as openConnection();
        but for some others, it is important to reuse physical backend
        connection, for example, to be in the same transaction - see JDBC
        container.
It is almost ready to use in data manager. Start another test.
When the container is ready to run as JCR persistence storage (for example, for this level testing), it should be configured in Repository configuration.
Assuming that the new implementation class name is org.project.jcr.impl.storage.MyWorkspaceDataContainer.
<repository-service default-repository="repository">
<repositories>
<repository name="repository" system-workspace="production" default-workspace="production">
.............
<workspaces>
<workspace name="production">
<container class="org.project.jcr.impl.storage.MyWorkspaceDataContainer">
<properties>
<property name="propertyName1" value="propertyValue1" />
<property name="propertyName2" value="propertyValue2" />
.......
<property name="propertyNameN" value="propertyValueN" />
</properties>
<value-storages>
.......
</value-storages>
</container>
Container can be configured by using set properties.
Value storages are pluggable to the container but if they are used, the container implementation should respect set of interfaces and external storage usage principles.
If the container has ValueStoragePluginProvider (for example, via constructor), it is just a method to manipulate external Values data.
// get channel for ValueData write (add or update)
ValueIOChannel channel = valueStorageProvider.getApplicableChannel(data, i);
if (channel == null) {
// write
channel.write(data.getIdentifier(), vd);
// obtain storage id, id can be used for linkage of external ValueData and PropertyData in main backend
String storageId = channel.getStorageId();
}
....
// delete all Property Values in external storage
ValueIOChannel channel = valueStorageProvider.getChannel(storageId);
channel.delete(propertyData.getIdentifier());
....
// read ValueData from external storage
ValueIOChannel channel = valueStorageProvider.getChannel(storageId);
ValueData vdata = channel.read(propertyData.getIdentifier(), orderNumber, maxBufferSize);
After a sequence of write and/or delete operations on the storage
      channel, the channel should be committed (or rolled back on an error).
      See ValueIOChannel.commit() and
      ValueIOChannel.rollback() and how those
      methods are used in the JDBC container.