mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
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:
@@ -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>
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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"/>
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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();
|
||||||
|
@@ -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"))
|
||||||
{
|
{
|
||||||
|
@@ -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)
|
||||||
|
Reference in New Issue
Block a user