MT admin - add export/import tenant also expose delete tenant (BETA)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8047 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2008-01-21 16:37:27 +00:00
parent ccef2e7377
commit 990c2d68ec
9 changed files with 401 additions and 72 deletions

View File

@@ -21,7 +21,13 @@
<property name="attributeService" ref="AttributeService"/> <property name="attributeService" ref="AttributeService"/>
<property name="passwordEncoder" ref="passwordEncoder"/> <property name="passwordEncoder" ref="passwordEncoder"/>
<property name="tenantFileContentStore" ref="tenantFileContentStore"/> <property name="tenantFileContentStore" ref="tenantFileContentStore"/>
<property name="workflowService" ref="WorkflowService"/> <property name="workflowService" ref="WorkflowService"/>
<property name="repositoryExporterService" ref="repositoryExporterComponent"/>
<property name="namespaceService" ref="NamespaceService"/>
<property name="searchService" ref="SearchService"/>
<property name="workflowDefinitionType" ref="workflowDefinitionType"/>
<property name="repositoryWorkflowDefsLocations" ref="customWorkflowDefsRepositoryLocation"/>
</bean> </bean>

View File

@@ -32,7 +32,7 @@ ok> show tenant <tenant domain>
ok> create <tenant domain> <tenant admin password> [<root contentstore dir>] ok> create <tenant domain> <tenant admin password> [<root contentstore dir>]
Create tenant. By default the tenant will be enabled. It will have an admin Create empty tenant. By default the tenant will be enabled. It will have an admin
user called "admin@<tenant domain>" with supplied admin password. All users user called "admin@<tenant domain>" with supplied admin password. All users
that the admin creates, will login using "<username>@<tenant domain>". that the admin creates, will login using "<username>@<tenant domain>".
The root of the contentstore directory can be optionally specified, otherwise The root of the contentstore directory can be optionally specified, otherwise
@@ -42,17 +42,7 @@ ok> create <tenant domain> <tenant admin password> [<root contentstore dir>]
Examples: create zzz.com l3tm31n /usr/tenantstores/zzz Examples: create zzz.com l3tm31n /usr/tenantstores/zzz
create yyy.zzz.com g00dby3 /usr/tenantstores/yyy.zzz create yyy.zzz.com g00dby3 /usr/tenantstores/yyy.zzz
create myorg h3ll0 create myorg h3ll0
ok> createWithoutWorkflows <tenant domain> <tenant admin password> [<root contentstore dir>]
Same as create, except the default workflows will not be bootstrapped.
ok> bootstrapWorkflows <tenant domain>
Bootstrap the default workflows.
Examples: bootstrapWorkflows yyy.zzz.com
ok> changeAdminPassword <tenant domain> <tenant admin password> ok> changeAdminPassword <tenant domain> <tenant admin password>
Useful if the tenant's admin (admin@<tenant domain>) has forgotten their password. Useful if the tenant's admin (admin@<tenant domain>) has forgotten their password.
@@ -70,6 +60,31 @@ ok> disable <tenant domain>
Disable tenant so that is inactive. Existing logins will fail on next usage. Disable tenant so that is inactive. Existing logins will fail on next usage.
Example: enable yyy.zzz.com Example: enable yyy.zzz.com
ok> delete <tenant domain>
BETA - Delete tenant.
Note: This currently requires a server restart to clear the index threads. Also
tenant index directories should be deleted manually.
Example: delete yyy.zzz.com
ok> export <tenant domain> <destination directory>
Export tenant to given destination directory. Export filenames will be suffixed with '<tenant domain>_'.
Example: export yyy.zzz.com /usr/exportdir
ok> import <tenant domain> <source directory> [<root contentstore dir>]
BETA - create tenant by importing the tenant files from the given source directory. The import filenames must
be suffixed with '<tenant domain>_'.
Note: If importing into a previously deleted tenant then the server must be stopped after the delete
(and tenant indexes manually deleted) before restarting and performing the import.
Example: import yyy.zzz.com /usr/exportdir /usr/tenantstores/yyy.zzz
## ##
## end ## end

View File

@@ -109,6 +109,15 @@
<!-- Workflow Patch Deployer --> <!-- Workflow Patch Deployer -->
<bean id="workflowPatchDeployer" parent="workflowDeployer" singleton="false"/> <bean id="workflowPatchDeployer" parent="workflowDeployer" singleton="false"/>
<!-- Deploy any additional workflows definitions from repo (used by MT import) -->
<!-- note: needs to match bootstrap-context.xml locations ( customWorkflowDefsSpace.xml) -->
<bean id="customWorkflowDefsRepositoryLocation" class="org.alfresco.repo.dictionary.RepositoryLocation">
<!-- other properties will be defaulted, but can be overriden here -->
<property name="path">
<value>/app:company_home/app:dictionary/app:workflow_defs</value>
</property>
</bean>
<!-- Workflow Definition Type (bpm:workflowDefinition) --> <!-- Workflow Definition Type (bpm:workflowDefinition) -->
<bean id="workflowDefinitionType" class="org.alfresco.repo.workflow.WorkflowDefinitionType" init-method="init"> <bean id="workflowDefinitionType" class="org.alfresco.repo.workflow.WorkflowDefinitionType" init-method="init">
<property name="nodeService" ref="NodeService"/> <property name="nodeService" ref="NodeService"/>

View File

@@ -473,7 +473,13 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda
if ((existingValue != null) && (existingValue.booleanValue() == true)) if ((existingValue != null) && (existingValue.booleanValue() == true))
{ {
String name = (String)nodeService.getProperty(existingNodeRef, ContentModel.PROP_NAME); String name = (String)nodeService.getProperty(existingNodeRef, ContentModel.PROP_NAME);
throw new AlfrescoRuntimeException("Cannot activate '"+modelDefinition.getName()+"' - existing active model: " + name);
// for MT import, model may have been activated by DictionaryRepositoryBootstrap
if (logger.isDebugEnabled())
{
logger.debug("Re-activating '"+modelDefinition.getName()+"' - existing active model: " + name);
}
//throw new AlfrescoRuntimeException("Cannot activate '"+modelDefinition.getName()+"' - existing active model: " + name);
} }
} }
} }

View File

@@ -498,29 +498,40 @@ public class ImporterBootstrap extends AbstractLifecycleBean
*/ */
private File getFile(String view) private File getFile(String view)
{ {
// Get input stream // Try as a file location
InputStream viewStream = getClass().getClassLoader().getResourceAsStream(view); File file = new File(view);
if (viewStream == null) if ((file != null) && (file.exists()))
{ {
throw new ImporterException("Could not find view file " + view); return file;
} }
else
// Create output stream
File tempFile = TempFileProvider.createTempFile("acpImport", ".tmp");
try
{ {
FileOutputStream os = new FileOutputStream(tempFile); // Try as a classpath location
FileCopyUtils.copy(viewStream, os);
// Get input stream
InputStream viewStream = getClass().getClassLoader().getResourceAsStream(view);
if (viewStream == null)
{
throw new ImporterException("Could not find view file " + view);
}
// Create output stream
File tempFile = TempFileProvider.createTempFile("acpImport", ".tmp");
try
{
FileOutputStream os = new FileOutputStream(tempFile);
FileCopyUtils.copy(viewStream, os);
}
catch (FileNotFoundException e)
{
throw new ImporterException("Could not import view " + view, e);
}
catch (IOException e)
{
throw new ImporterException("Could not import view " + view, e);
}
return tempFile;
} }
catch (FileNotFoundException e)
{
throw new ImporterException("Could not import view " + view, e);
}
catch (IOException e)
{
throw new ImporterException("Could not import view " + view, e);
}
return tempFile;
} }

View File

@@ -24,6 +24,7 @@
*/ */
package org.alfresco.repo.tenant; package org.alfresco.repo.tenant;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@@ -45,17 +46,23 @@ import org.alfresco.repo.attributes.MapAttributeValue;
import org.alfresco.repo.attributes.StringAttributeValue; import org.alfresco.repo.attributes.StringAttributeValue;
import org.alfresco.repo.content.TenantRoutingFileContentStore; import org.alfresco.repo.content.TenantRoutingFileContentStore;
import org.alfresco.repo.dictionary.DictionaryComponent; import org.alfresco.repo.dictionary.DictionaryComponent;
import org.alfresco.repo.dictionary.RepositoryLocation;
import org.alfresco.repo.importer.ImporterBootstrap; import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.node.db.DbNodeServiceImpl; import org.alfresco.repo.node.db.DbNodeServiceImpl;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.workflow.WorkflowDefinitionType;
import org.alfresco.repo.workflow.WorkflowDeployer; import org.alfresco.repo.workflow.WorkflowDeployer;
import org.alfresco.service.cmr.admin.RepoAdminService; import org.alfresco.service.cmr.admin.RepoAdminService;
import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.view.RepositoryExporterService;
import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.AbstractLifecycleBean; import org.alfresco.util.AbstractLifecycleBean;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
@@ -85,6 +92,11 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
private TenantRoutingFileContentStore tenantFileContentStore; private TenantRoutingFileContentStore tenantFileContentStore;
private WorkflowService workflowService; private WorkflowService workflowService;
private RepositoryExporterService repositoryExporterService;
private NamespaceService namespaceService;
private SearchService searchService;
private RepositoryLocation repoWorkflowDefsLocation;
private WorkflowDefinitionType workflowDefinitionType;
protected final static String REGEX_VALID_TENANT_NAME = "^[a-zA-Z0-9]([a-zA-Z0-9]|.[a-zA-Z0-9])*$"; // note: must also be a valid filename protected final static String REGEX_VALID_TENANT_NAME = "^[a-zA-Z0-9]([a-zA-Z0-9]|.[a-zA-Z0-9])*$"; // note: must also be a valid filename
@@ -139,6 +151,32 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
this.workflowService = workflowService; this.workflowService = workflowService;
} }
public void setRepositoryExporterService(RepositoryExporterService repositoryExporterService)
{
this.repositoryExporterService = repositoryExporterService;
}
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public void setRepositoryWorkflowDefsLocations(RepositoryLocation repoWorkflowDefsLocation)
{
this.repoWorkflowDefsLocation = repoWorkflowDefsLocation;
}
public void setWorkflowDefinitionType(WorkflowDefinitionType workflowDefinitionType)
{
this.workflowDefinitionType = workflowDefinitionType;
}
public static final String PROTOCOL_STORE_USER = "user"; public static final String PROTOCOL_STORE_USER = "user";
public static final String PROTOCOL_STORE_WORKSPACE = "workspace"; public static final String PROTOCOL_STORE_WORKSPACE = "workspace";
public static final String PROTOCOL_STORE_SYSTEM = "system"; public static final String PROTOCOL_STORE_SYSTEM = "system";
@@ -154,6 +192,9 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
private static final String TENANT_ROOT_CONTENT_STORE_DIR = "rootContentStoreDir"; private static final String TENANT_ROOT_CONTENT_STORE_DIR = "rootContentStoreDir";
private static final String ADMIN_BASENAME = TenantService.ADMIN_BASENAME; private static final String ADMIN_BASENAME = TenantService.ADMIN_BASENAME;
public final static String CRITERIA_ALL = "/*"; // immediate children only
public final static String defaultSubtypeOfWorkflowDefinitionType = "subtypeOf('bpm:workflowDefinition')";
private List<TenantDeployer> tenantDeployers = new ArrayList<TenantDeployer>(); private List<TenantDeployer> tenantDeployers = new ArrayList<TenantDeployer>();
@@ -275,11 +316,20 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
tenantFileContentStore.init(); tenantFileContentStore.init();
// create tenant-specific stores // create tenant-specific stores
bootstrapUserTenantStore(tenantDomain, tenantAdminRawPassword); ImporterBootstrap userImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("userBootstrap");
bootstrapSystemTenantStore(tenantDomain); bootstrapUserTenantStore(userImporterBootstrap, tenantDomain, tenantAdminRawPassword);
bootstrapVersionTenantStore(tenantDomain);
bootstrapSpacesArchiveTenantStore(tenantDomain); ImporterBootstrap systemImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("systemBootstrap");
bootstrapSpacesTenantStore(tenantDomain); bootstrapSystemTenantStore(systemImporterBootstrap, tenantDomain);
ImporterBootstrap versionImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("versionBootstrap");
bootstrapVersionTenantStore(versionImporterBootstrap, tenantDomain);
ImporterBootstrap spacesArchiveImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("spacesArchiveBootstrap");
bootstrapSpacesArchiveTenantStore(spacesArchiveImporterBootstrap, tenantDomain);
ImporterBootstrap spacesImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("spacesBootstrap");
bootstrapSpacesTenantStore(spacesImporterBootstrap, tenantDomain);
// notify listeners that tenant has been created & hence enabled // notify listeners that tenant has been created & hence enabled
for (TenantDeployer tenantDeployer : tenantDeployers) for (TenantDeployer tenantDeployer : tenantDeployers)
@@ -295,6 +345,82 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
logger.info("Tenant created: " + tenantDomain); logger.info("Tenant created: " + tenantDomain);
} }
/**
* Export tenant - equivalent to the tenant admin running a 'complete repo' export from the Web Client Admin
*/
public void exportTenant(final String tenantDomain, final File directoryDestination)
{
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
repositoryExporterService.export(directoryDestination, tenantDomain);
return null;
}
}, getTenantAdminUser(tenantDomain));
logger.info("Tenant exported: " + tenantDomain);
}
/**
* Create tenant by restoring from a complete repository export. This is equivalent to a bootstrap import using restore-context.xml.
*/
public void importTenant(final String tenantDomain, final File directorySource, String rootContentStoreDir)
{
// Check that all the passed values are not null
ParameterCheck.mandatory("tenantDomain", tenantDomain);
if (! Pattern.matches(REGEX_VALID_TENANT_NAME, tenantDomain))
{
throw new IllegalArgumentException(tenantDomain + " is not a valid tenant name (must match " + REGEX_VALID_TENANT_NAME + ")");
}
if (existsTenant(tenantDomain))
{
throw new AlfrescoRuntimeException("Tenant already exists: " + tenantDomain);
}
else
{
authenticationComponent.setSystemUserAsCurrentUser();
if (rootContentStoreDir == null)
{
rootContentStoreDir = tenantFileContentStore.getDefaultRootDir();
}
// init - need to enable tenant (including tenant service) before stores bootstrap
Tenant tenant = new Tenant(tenantDomain, true, rootContentStoreDir);
putTenantAttributes(tenantDomain, tenant);
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
dictionaryComponent.init();
tenantFileContentStore.init();
// import tenant-specific stores
importBootstrapUserTenantStore(tenantDomain, directorySource);
importBootstrapSystemTenantStore(tenantDomain, directorySource);
importBootstrapVersionTenantStore(tenantDomain, directorySource);
importBootstrapSpacesArchiveTenantStore(tenantDomain, directorySource);
importBootstrapSpacesModelsTenantStore(tenantDomain, directorySource);
importBootstrapSpacesTenantStore(tenantDomain, directorySource);
// notify listeners that tenant has been created & hence enabled
for (TenantDeployer tenantDeployer : tenantDeployers)
{
tenantDeployer.onEnableTenant();
}
return null;
}
}, getTenantAdminUser(tenantDomain));
}
logger.info("Tenant imported: " + tenantDomain);
}
public boolean existsTenant(String tenantDomain) public boolean existsTenant(String tenantDomain)
{ {
// Check that all the passed values are not null // Check that all the passed values are not null
@@ -477,6 +603,21 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
throw new AlfrescoRuntimeException("Failed to find workflow process def: " + resourceClasspath); throw new AlfrescoRuntimeException("Failed to find workflow process def: " + resourceClasspath);
} }
// in case of import, also deploy any custom workflow definitions defined in the repo
// TODO refactor/review repository bootstrap order of undeployed workflow definitions
StoreRef storeRef = repoWorkflowDefsLocation.getStoreRef();
NodeRef rootNode = nodeService.getRootNode(storeRef);
List<NodeRef> nodeRefs = searchService.selectNodes(rootNode, repoWorkflowDefsLocation.getPath()+CRITERIA_ALL+"["+defaultSubtypeOfWorkflowDefinitionType+"]", null, namespaceService, false);
if (nodeRefs.size() > 0)
{
for (NodeRef nodeRef : nodeRefs)
{
workflowDefinitionType.deploy(nodeRef);
}
}
logger.info("Tenant workflows bootstrapped: " + tenantService.getCurrentUserDomain()); logger.info("Tenant workflows bootstrapped: " + tenantService.getCurrentUserDomain());
} }
@@ -585,33 +726,28 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
return tenants; // list of tenants or empty list return tenants; // list of tenants or empty list
} }
private void bootstrapUserTenantStore(String tenantDomain, char[] tenantAdminRawPassword) private void importBootstrapSystemTenantStore(String tenantDomain, File directorySource)
{ {
// Bootstrap Tenant-Specific User Store // Import Bootstrap (restore) Tenant-Specific Version Store
StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_USER, tenantService.getName(STORE_BASE_ID_USER, tenantDomain)); Properties bootstrapView = new Properties();
bootstrapView.put("path", "/");
bootstrapView.put("location", directorySource.getPath()+"/"+tenantDomain+"_system.acp");
List<Properties> bootstrapViews = new ArrayList<Properties>(1);
bootstrapViews.add(bootstrapView);
ImporterBootstrap userImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("userBootstrap"); ImporterBootstrap systemImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("systemBootstrap");
userImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString()); systemImporterBootstrap.setBootstrapViews(bootstrapViews);
systemImporterBootstrap.setLog(true);
// override admin username property
String salt = null; // GUID.generate(); bootstrapSystemTenantStore(systemImporterBootstrap, tenantDomain);
Properties props = userImporterBootstrap.getConfiguration();
props.put("alfresco_user_store.adminusername", getTenantAdminUser(tenantDomain));
props.put("alfresco_user_store.adminpassword", passwordEncoder.encodePassword(new String(tenantAdminRawPassword), salt));
userImporterBootstrap.bootstrap();
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
} }
private void bootstrapSystemTenantStore(String tenantDomain) private void bootstrapSystemTenantStore(ImporterBootstrap systemImporterBootstrap, String tenantDomain)
{ {
// Bootstrap Tenant-Specific System Store // Bootstrap Tenant-Specific System Store
StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_SYSTEM, tenantService.getName(STORE_BASE_ID_SYSTEM, tenantDomain)); StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_SYSTEM, tenantService.getName(STORE_BASE_ID_SYSTEM, tenantDomain));
ImporterBootstrap systemImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("systemBootstrap");
systemImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString()); systemImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString());
// override default property (workspace://SpacesStore) // override default property (workspace://SpacesStore)
@@ -624,12 +760,65 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef)); logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
} }
private void bootstrapVersionTenantStore(String tenantDomain) private void importBootstrapUserTenantStore(String tenantDomain, File directorySource)
{
// Import Bootstrap (restore) Tenant-Specific User Store
Properties bootstrapView = new Properties();
bootstrapView.put("path", "/");
bootstrapView.put("location", directorySource.getPath()+"/"+tenantDomain+"_users.acp");
List<Properties> bootstrapViews = new ArrayList<Properties>(1);
bootstrapViews.add(bootstrapView);
ImporterBootstrap userImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("userBootstrap");
userImporterBootstrap.setBootstrapViews(bootstrapViews);
userImporterBootstrap.setLog(true);
bootstrapUserTenantStore(userImporterBootstrap, tenantDomain, null);
}
private void bootstrapUserTenantStore(ImporterBootstrap userImporterBootstrap, String tenantDomain, char[] tenantAdminRawPassword)
{
// Bootstrap Tenant-Specific User Store
StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_USER, tenantService.getName(STORE_BASE_ID_USER, tenantDomain));
userImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString());
// override admin username property
Properties props = userImporterBootstrap.getConfiguration();
props.put("alfresco_user_store.adminusername", getTenantAdminUser(tenantDomain));
if (tenantAdminRawPassword != null)
{
String salt = null; // GUID.generate();
props.put("alfresco_user_store.adminpassword", passwordEncoder.encodePassword(new String(tenantAdminRawPassword), salt));
}
userImporterBootstrap.bootstrap();
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
}
private void importBootstrapVersionTenantStore(String tenantDomain, File directorySource)
{
// Import Bootstrap (restore) Tenant-Specific Version Store
Properties bootstrapView = new Properties();
bootstrapView.put("path", "/");
bootstrapView.put("location", directorySource.getPath()+"/"+tenantDomain+"_versions.acp");
List<Properties> bootstrapViews = new ArrayList<Properties>(1);
bootstrapViews.add(bootstrapView);
ImporterBootstrap versionImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("versionBootstrap");
versionImporterBootstrap.setBootstrapViews(bootstrapViews);
versionImporterBootstrap.setLog(true);
bootstrapVersionTenantStore(versionImporterBootstrap, tenantDomain);
}
private void bootstrapVersionTenantStore(ImporterBootstrap versionImporterBootstrap, String tenantDomain)
{ {
// Bootstrap Tenant-Specific Version Store // Bootstrap Tenant-Specific Version Store
StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_WORKSPACE, tenantService.getName(STORE_BASE_ID_VERSION, tenantDomain)); StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_WORKSPACE, tenantService.getName(STORE_BASE_ID_VERSION, tenantDomain));
ImporterBootstrap versionImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("versionBootstrap");
versionImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString()); versionImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString());
versionImporterBootstrap.bootstrap(); versionImporterBootstrap.bootstrap();
@@ -637,12 +826,27 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef)); logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
} }
private void bootstrapSpacesArchiveTenantStore(String tenantDomain) private void importBootstrapSpacesArchiveTenantStore(String tenantDomain, File directorySource)
{ {
// Bootstrap Tenant-Specific Spaces Store // Import Bootstrap (restore) Tenant-Specific Spaces Archive Store
StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_ARCHIVE, tenantService.getName(STORE_BASE_ID_SPACES, tenantDomain)); Properties bootstrapView = new Properties();
bootstrapView.put("path", "/");
bootstrapView.put("location", directorySource.getPath()+"/"+tenantDomain+"_spaces_archive.acp");
List<Properties> bootstrapViews = new ArrayList<Properties>(1);
bootstrapViews.add(bootstrapView);
ImporterBootstrap spacesArchiveImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("spacesArchiveBootstrap"); ImporterBootstrap spacesArchiveImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("spacesArchiveBootstrap");
spacesArchiveImporterBootstrap.setBootstrapViews(bootstrapViews);
spacesArchiveImporterBootstrap.setLog(true);
bootstrapSpacesArchiveTenantStore(spacesArchiveImporterBootstrap, tenantDomain);
}
private void bootstrapSpacesArchiveTenantStore(ImporterBootstrap spacesArchiveImporterBootstrap, String tenantDomain)
{
// Bootstrap Tenant-Specific Spaces Archive Store
StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_ARCHIVE, tenantService.getName(STORE_BASE_ID_SPACES, tenantDomain));
spacesArchiveImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString()); spacesArchiveImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString());
// override default property (archive://SpacesStore) // override default property (archive://SpacesStore)
@@ -655,12 +859,47 @@ public class MultiTAdminServiceImpl extends AbstractLifecycleBean implements Ten
logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef)); logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef));
} }
private void bootstrapSpacesTenantStore(String tenantDomain) private void importBootstrapSpacesModelsTenantStore(String tenantDomain, File directorySource)
{
// Import Bootstrap (restore) Tenant-Specific Spaces Store
Properties bootstrapView = new Properties();
bootstrapView.put("path", "/");
bootstrapView.put("location", directorySource.getPath()+"/"+tenantDomain+"_models.acp");
List<Properties> bootstrapViews = new ArrayList<Properties>(1);
bootstrapViews.add(bootstrapView);
ImporterBootstrap spacesImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("spacesBootstrap");
spacesImporterBootstrap.setBootstrapViews(bootstrapViews);
spacesImporterBootstrap.setLog(true);
bootstrapSpacesTenantStore(spacesImporterBootstrap, tenantDomain);
}
private void importBootstrapSpacesTenantStore(String tenantDomain, File directorySource)
{
// Import Bootstrap (restore) Tenant-Specific Spaces Store
Properties bootstrapView = new Properties();
bootstrapView.put("path", "/");
bootstrapView.put("location", directorySource.getPath()+"/"+tenantDomain+"_spaces.acp");
bootstrapView.put("uuidBinding", "UPDATE_EXISTING");
List<Properties> bootstrapViews = new ArrayList<Properties>(1);
bootstrapViews.add(bootstrapView);
ImporterBootstrap spacesImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("spacesBootstrap");
spacesImporterBootstrap.setBootstrapViews(bootstrapViews);
spacesImporterBootstrap.setLog(true);
spacesImporterBootstrap.setUseExistingStore(true);
bootstrapSpacesTenantStore(spacesImporterBootstrap, tenantDomain);
}
private void bootstrapSpacesTenantStore(ImporterBootstrap spacesImporterBootstrap, String tenantDomain)
{ {
// Bootstrap Tenant-Specific Spaces Store // Bootstrap Tenant-Specific Spaces Store
StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_WORKSPACE, tenantService.getName(STORE_BASE_ID_SPACES, tenantDomain)); StoreRef bootstrapStoreRef = new StoreRef(PROTOCOL_STORE_WORKSPACE, tenantService.getName(STORE_BASE_ID_SPACES, tenantDomain));
final ImporterBootstrap spacesImporterBootstrap = (ImporterBootstrap)getApplicationContext().getBean("spacesBootstrap");
spacesImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString()); spacesImporterBootstrap.setStoreUrl(bootstrapStoreRef.toString());
// override admin username property // override admin username property

View File

@@ -24,6 +24,7 @@
*/ */
package org.alfresco.repo.tenant; package org.alfresco.repo.tenant;
import java.io.File;
import java.util.List; import java.util.List;
@@ -40,6 +41,10 @@ public interface TenantAdminService extends TenantDeployerService
public void createTenant(String tenantDomain, char[] adminRawPassword, String rootContentStoreDir); public void createTenant(String tenantDomain, char[] adminRawPassword, String rootContentStoreDir);
public void exportTenant(String tenantDomain, File directoryDestination);
public void importTenant(String tenantDomain, File directorySource, String rootContentStoreDir);
public boolean existsTenant(String tenantDomain); public boolean existsTenant(String tenantDomain);
public void bootstrapWorkflows(); public void bootstrapWorkflows();

View File

@@ -25,6 +25,7 @@
package org.alfresco.repo.tenant; package org.alfresco.repo.tenant;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintStream; import java.io.PrintStream;
@@ -208,8 +209,8 @@ public class TenantInterpreter extends BaseInterpreter
out.print(executeCommand("createWithoutWorkflows " + createTenantArgs)); out.print(executeCommand("createWithoutWorkflows " + createTenantArgs));
out.print(executeCommand("bootstrapWorkflows " + newTenant)); out.print(executeCommand("bootstrapWorkflows " + newTenant));
} }
else if (command[0].equals("createWithoutWorkflows")) else if (command[0].equals("createWithoutWorkflows"))
{ {
if ((command.length != 3) && (command.length != 4)) if ((command.length != 3) && (command.length != 4))
@@ -228,8 +229,8 @@ public class TenantInterpreter extends BaseInterpreter
tenantAdminService.createTenant(newTenant, tenantAdminRawPassword, rootContentStoreDir); tenantAdminService.createTenant(newTenant, tenantAdminRawPassword, rootContentStoreDir);
out.println("created tenant: " + newTenant); out.println("created tenant: " + newTenant);
} }
else if (command[0].equals("bootstrapWorkflows")) else if (command[0].equals("bootstrapWorkflows"))
{ {
if (command.length != 2) if (command.length != 2)
@@ -252,6 +253,43 @@ public class TenantInterpreter extends BaseInterpreter
out.println("bootstrap workflows deployed for tenant: " + newTenant); out.println("bootstrap workflows deployed for tenant: " + newTenant);
} }
else if (command[0].equals("import"))
{
if ((command.length != 3) && (command.length != 4))
{
return "Syntax Error, try 'help'.\n";
}
String newTenant = new String(command[1]).toLowerCase();
File directorySource = new File(command[2]);
String rootContentStoreDir = null;
if (command.length == 4)
{
rootContentStoreDir = new String(command[3]);
}
tenantAdminService.importTenant(newTenant, directorySource, rootContentStoreDir);
out.println("imported tenant: " + newTenant);
out.print(executeCommand("bootstrapWorkflows " + newTenant));
}
else if (command[0].equals("export"))
{
if (command.length != 3)
{
return "Syntax Error, try 'help'.\n";
}
String tenant = new String(command[1]).toLowerCase();
File directoryDestination = new File(command[2]);
tenantAdminService.exportTenant(tenant, directoryDestination);
out.println("exported tenant: " + tenant);
}
// TODO - not fully working yet // TODO - not fully working yet
else if (command[0].equals("delete")) else if (command[0].equals("delete"))
{ {

View File

@@ -171,7 +171,7 @@ public class WorkflowDefinitionType implements ContentServicePolicies.OnContentU
undeploy(nodeRef); undeploy(nodeRef);
} }
private void deploy(NodeRef nodeRef) public void deploy(NodeRef nodeRef)
{ {
// Ignore if the node is a working copy // Ignore if the node is a working copy
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == false) if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == false)