From fec1149d8cedd74e74cb4c7296efe0dbd0e34c50 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Fri, 13 Mar 2009 00:51:43 +0000 Subject: [PATCH] Merged V3.1 to HEAD - incl. taking Hibernate libs from 3.1 and adding missing file from earlier merge 13321: Fix ETHREEOH-1407: System error occur during "Undo Selected" action if no items are selected 13322: ETHREEOH-1206: Throwing Alfresco Exception on OnUpdateProperties behaviour resets Encoding field to Big (first entry) 13326: (RECORD ONLY) Removed 'dev' from version label. 13330: Fix ETHREEOH-1408: Incorrect button name at "Manage Task: Submitted" page 13337: Fix for ETHREEOH-1409 and further fix for ETHREEOH-1408 13338: Removed svn:mergeinfo 13346: Make startup bat script check JAVA can be found. 13351: ETHREEOH-1386 validate ASR and FSR hostname. 13359: ETHREEOH-1435: Share doesn't extract document metadata correctly 13360: Fix ETHREEOH-821: SDK dependencies 13369: Fixed distribute-sdk target for when it's run locally 13382: ETHREEOH-1437: Container creation induces an unexpected permission allocation in Share 13391: Shutdown backstop continues if logging throws errors. 13394: Fix ETHREEOH-1457 - MT coci issue with bootstrap (eg. data dictionary) content 13400: Activate JAWS-223: Adobe LC Hibernate Dialect Loading 13401: Support for JAWS-215, mysql and oracle 13413: Fix ETHREEOH-1458 - MT delete->archive ___________________________________________________________________ Modified: svn:mergeinfo Merged /alfresco/BRANCHES/V3.1:r 13321-13322,13326-13327,13330,13337-13339,13341-13347,13351,13354-13355,13358-13363, 13365,13367,13369,13382,13385-13392,13394,13400-13403,13405-13406,13413 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13617 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../activities/activities-SqlMapConfig.xml | 8 +- .../activities/activities-feed-context.xml | 2 +- ...lfrescoSchemaUpdate-2.1-A--to--2.2-ACL.sql | 2 +- .../upgrade-from-2.1.sql | 2 +- .../alfresco/domain/hibernate-cfg.properties | 11 +- config/alfresco/model/bpmModel.xml | 6 + config/alfresco/node-services-context.xml | 3 + config/alfresco/workflow/wcmWorkflowModel.xml | 10 + .../alfresco/repo/node/StoreArchiveMap.java | 29 ++- .../node/archive/ArchiveAndRestoreTest.java | 6 +- .../repo/node/db/DbNodeServiceImpl.java | 4 +- .../repo/node/db/DbNodeServiceImplTest.java | 5 +- .../repo/shutdown/ShutdownBackstop.java | 18 +- .../org/alfresco/repo/site/script/Site.java | 6 +- .../repo/tenant/MultiTAdminServiceImpl.java | 172 +++++++++--------- .../alfresco/repo/tenant/MultiTDemoTest.java | 82 +++++++++ .../alfresco/repo/usage/ContentUsageImpl.java | 47 ++++- .../alfresco/repo/workflow/WorkflowModel.java | 1 + 18 files changed, 297 insertions(+), 117 deletions(-) diff --git a/config/alfresco/activities/activities-SqlMapConfig.xml b/config/alfresco/activities/activities-SqlMapConfig.xml index e3b29239fe..82edb581a9 100644 --- a/config/alfresco/activities/activities-SqlMapConfig.xml +++ b/config/alfresco/activities/activities-SqlMapConfig.xml @@ -5,13 +5,7 @@ "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> - - - - - - - + diff --git a/config/alfresco/activities/activities-feed-context.xml b/config/alfresco/activities/activities-feed-context.xml index 2e10391e66..0e837163b0 100644 --- a/config/alfresco/activities/activities-feed-context.xml +++ b/config/alfresco/activities/activities-feed-context.xml @@ -20,7 +20,7 @@ - + classpath:alfresco/activities/activities-SqlMapConfig.xml diff --git a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.1-A--to--2.2-ACL.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.1-A--to--2.2-ACL.sql index 169c5ae4e4..65553f9f48 100644 --- a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.1-A--to--2.2-ACL.sql +++ b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.1-A--to--2.2-ACL.sql @@ -187,5 +187,5 @@ INSERT INTO alf_applied_patch VALUES ( 'patch.db-V2.2-ACL-From-2.1-A', 'Manually executed script upgrade V2.2: Update acl schema', - 81, 82, -1, 120, null, 'UNKOWN', 1, 1, 'Script completed' + 0, 82, -1, 120, null, 'UNKOWN', 1, 1, 'Script completed' ); \ No newline at end of file diff --git a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql index f62d6a509c..e892c9aa5b 100644 --- a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql +++ b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql @@ -964,7 +964,7 @@ ALTER TABLE t_alf_store RENAME TO alf_store; -- Modify index and constraint names -- -- ------------------------------------- ALTER TABLE alf_attributes DROP INDEX fk_attributes_n_acl, DROP FOREIGN KEY fk_attributes_n_acl; -- (optional) -ALTER TABLE alf_attributes DROP INDEX fk_attr_n_acl; -- (optional) +ALTER TABLE alf_attributes DROP INDEX fk_attr_n_acl, DROP FOREIGN KEY fk_attr_n_acl; -- (optional) ALTER TABLE alf_attributes ADD INDEX fk_alf_attr_acl (acl_id) ; diff --git a/config/alfresco/domain/hibernate-cfg.properties b/config/alfresco/domain/hibernate-cfg.properties index 9ba44d22b8..579a581208 100644 --- a/config/alfresco/domain/hibernate-cfg.properties +++ b/config/alfresco/domain/hibernate-cfg.properties @@ -1,7 +1,11 @@ # # Hibernate configuration # -hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect + +# The Hibernate Dialect: +# As of V3.1, the dialect is automatically detected. +# It is still possible to set the dialect explicitly, for example: +# hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect hibernate.jdbc.use_streams_for_binary=true hibernate.show_sql=false @@ -16,4 +20,9 @@ hibernate.connection.isolation=2 #hibernate.query.substitutions= #hibernate.jdbc.use_get_generated_keys=false + +# Oracle Schema Distinction: +# See https://issues.alfresco.com/jira/browse/ETHREEOH-680 +# Metadata queries to Oracle have to be limited by schema name +# when multiple instances of Alfresco are installed on an Oracle server. #hibernate.default_schema= diff --git a/config/alfresco/model/bpmModel.xml b/config/alfresco/model/bpmModel.xml index 7911884dbf..3a8b30ca78 100644 --- a/config/alfresco/model/bpmModel.xml +++ b/config/alfresco/model/bpmModel.xml @@ -205,6 +205,12 @@ read_package_item_actions + + + d:text + true + + diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml index 8c9bb6de53..53ab6f5e78 100644 --- a/config/alfresco/node-services-context.xml +++ b/config/alfresco/node-services-context.xml @@ -87,6 +87,9 @@ archive://SpacesStore + + + diff --git a/config/alfresco/workflow/wcmWorkflowModel.xml b/config/alfresco/workflow/wcmWorkflowModel.xml index 8c3294cec0..fe08771e35 100644 --- a/config/alfresco/workflow/wcmWorkflowModel.xml +++ b/config/alfresco/workflow/wcmWorkflowModel.xml @@ -157,6 +157,11 @@ wcmwf:workflowTask + + + onsubmit + + bpm:assignees wcmwf:reviewType @@ -167,6 +172,11 @@ wcmwf:workflowTask + + + onsubmit + + wcmwf:submission diff --git a/source/java/org/alfresco/repo/node/StoreArchiveMap.java b/source/java/org/alfresco/repo/node/StoreArchiveMap.java index 0f4c6ce53d..c85a76dad3 100644 --- a/source/java/org/alfresco/repo/node/StoreArchiveMap.java +++ b/source/java/org/alfresco/repo/node/StoreArchiveMap.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.StoreRef; /** @@ -39,14 +40,16 @@ public class StoreArchiveMap { private Map storeArchiveMap; + private TenantService tenantService; + public StoreArchiveMap() { storeArchiveMap = new HashMap(0); } - public Map getArchiveMap() + public void setTenantService(TenantService tenantService) { - return storeArchiveMap; + this.tenantService = tenantService; } public void setArchiveMap(Map archiveMap) @@ -70,4 +73,26 @@ public class StoreArchiveMap storeArchiveMap.put(storeRefKey, storeRefValue); } } + + public StoreRef get(StoreRef storeRef) + { + if (tenantService.isEnabled()) + { + return tenantService.getName(storeArchiveMap.get(tenantService.getBaseName(storeRef))); + } + else + { + return storeArchiveMap.get(storeRef); + } + } + + public void put(StoreRef workStoreRef, StoreRef archiveStoreRef) + { + storeArchiveMap.put(workStoreRef, archiveStoreRef); + } + + public void clear() + { + storeArchiveMap.clear(); + } } diff --git a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java index 46b4b3d7d9..9dd7806192 100644 --- a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java +++ b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -141,7 +141,7 @@ public class ArchiveAndRestoreTest extends TestCase // Map the work store to the archive store. This will already be wired into the NodeService. StoreArchiveMap archiveMap = (StoreArchiveMap) ctx.getBean("storeArchiveMap"); - archiveMap.getArchiveMap().put(workStoreRef, archiveStoreRef); + archiveMap.put(workStoreRef, archiveStoreRef); TestWithUserUtils.createUser(USER_A, USER_A, workStoreRootNodeRef, nodeService, authenticationService); TestWithUserUtils.createUser(USER_B, USER_B, workStoreRootNodeRef, nodeService, authenticationService); @@ -508,7 +508,7 @@ public class ArchiveAndRestoreTest extends TestCase // Now force full deletions and creations StoreArchiveMap archiveMap = (StoreArchiveMap) ctx.getBean("storeArchiveMap"); - archiveMap.getArchiveMap().clear(); + archiveMap.clear(); long cumulatedDeleteTimeNs = 0; long cumulatedCreateTimeNs = 0; for (int i = 0; i < iterations; i++) diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 991606a828..57f0352947 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -748,7 +748,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl else { StoreRef storeRef = nodeRef.getStoreRef(); - archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); + archiveStoreRef = storeArchiveMap.get(storeRef); // get the type and check if we need archiving TypeDefinition typeDef = dictionaryService.getType(nodeTypeQName); if (typeDef == null || !typeDef.isArchive() || archiveStoreRef == null) @@ -2202,7 +2202,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public NodeRef getStoreArchiveNode(StoreRef storeRef) { - StoreRef archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); + StoreRef archiveStoreRef = storeArchiveMap.get(storeRef); if (archiveStoreRef == null) { // no mapping for the given store diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java index 7c1124e8eb..0bb2726153 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -37,7 +37,6 @@ import javax.transaction.UserTransaction; import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.domain.Store; import org.alfresco.repo.node.BaseNodeServiceTest; import org.alfresco.repo.node.StoreArchiveMap; import org.alfresco.repo.node.cleanup.NodeCleanupRegistry; @@ -465,7 +464,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest // Ensure that the archive feature is enabled StoreRef archiveStoreRef = ns.createStore("test", getName() + "-" + System.currentTimeMillis()); - storeArchiveMap.getArchiveMap().put(parentNodeRef.getStoreRef(), archiveStoreRef); + storeArchiveMap.put(parentNodeRef.getStoreRef(), archiveStoreRef); // Delete parent. Cascade is OFF, so children should be left in their current store. ns.deleteNode(parentNodeRef); diff --git a/source/java/org/alfresco/repo/shutdown/ShutdownBackstop.java b/source/java/org/alfresco/repo/shutdown/ShutdownBackstop.java index d3145e286e..f4c24cd625 100644 --- a/source/java/org/alfresco/repo/shutdown/ShutdownBackstop.java +++ b/source/java/org/alfresco/repo/shutdown/ShutdownBackstop.java @@ -128,7 +128,14 @@ public class ShutdownBackstop extends AbstractLifecycleBean // nothing to do here } - log.error("Alfresco terminating via Shutdown Backstop"); + try + { + log.error("Alfresco terminating via Shutdown Backstop"); + } + catch (Throwable t) + { + // Do nothing + } try { @@ -149,7 +156,14 @@ public class ShutdownBackstop extends AbstractLifecycleBean t.printStackTrace(); } - log.error("Alfresco terminated"); + try + { + log.error("Alfresco terminated"); + } + catch (Throwable t) + { + // Do nothing + } System.exit(1); } diff --git a/source/java/org/alfresco/repo/site/script/Site.java b/source/java/org/alfresco/repo/site/script/Site.java index 274ca67b0d..ca0692063a 100644 --- a/source/java/org/alfresco/repo/site/script/Site.java +++ b/source/java/org/alfresco/repo/site/script/Site.java @@ -49,6 +49,7 @@ import org.alfresco.service.cmr.invitation.InvitationSearchCriteria; import org.alfresco.service.cmr.invitation.InvitationService; import org.alfresco.service.cmr.invitation.InvitationSearchCriteria.InvitationType; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; @@ -450,7 +451,10 @@ public class Site implements Serializable } } } - } + } + + // Make the "admin" the owner of the node + serviceRegistry.getOwnableService().setOwner(containerNodeRef, AuthenticationUtil.getAdminUserName()); return containerNodeRef; } diff --git a/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java b/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java index a01e933d91..4ae010d79e 100755 --- a/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java +++ b/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java @@ -51,6 +51,8 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.site.SiteAVMBootstrap; +import org.alfresco.repo.usage.UserUsageBootstrapJob; +import org.alfresco.repo.usage.UserUsageTrackingComponent; import org.alfresco.repo.workflow.WorkflowDeployer; import org.alfresco.service.cmr.admin.RepoAdminService; import org.alfresco.service.cmr.attributes.AttributeService; @@ -344,53 +346,56 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo initTenant(tenantDomain, rootContentStoreDir); - AuthenticationUtil.runAs(new RunAsWork() - { - public Object doWork() - { - dictionaryComponent.init(); - tenantFileContentStore.init(); - - // create tenant-specific stores - ImporterBootstrap userImporterBootstrap = (ImporterBootstrap)ctx.getBean("userBootstrap"); - bootstrapUserTenantStore(userImporterBootstrap, tenantDomain, tenantAdminRawPassword); - - ImporterBootstrap systemImporterBootstrap = (ImporterBootstrap)ctx.getBean("systemBootstrap"); - bootstrapSystemTenantStore(systemImporterBootstrap, tenantDomain); + try + { + // note: runAs would cause auditable property "creator" to be "admin" instead of "System@xxx" + AuthenticationUtil.pushAuthentication(); + AuthenticationUtil.setFullyAuthenticatedUser(getSystemUser(tenantDomain)); + + dictionaryComponent.init(); + tenantFileContentStore.init(); + + // create tenant-specific stores + ImporterBootstrap userImporterBootstrap = (ImporterBootstrap)ctx.getBean("userBootstrap"); + bootstrapUserTenantStore(userImporterBootstrap, tenantDomain, tenantAdminRawPassword); + + ImporterBootstrap systemImporterBootstrap = (ImporterBootstrap)ctx.getBean("systemBootstrap"); + bootstrapSystemTenantStore(systemImporterBootstrap, tenantDomain); - // deprecated - ImporterBootstrap versionImporterBootstrap = (ImporterBootstrap)ctx.getBean("versionBootstrap"); - bootstrapVersionTenantStore(versionImporterBootstrap, tenantDomain); - - ImporterBootstrap version2ImporterBootstrap = (ImporterBootstrap)ctx.getBean("version2Bootstrap"); - bootstrapVersionTenantStore(version2ImporterBootstrap, tenantDomain); + // deprecated + ImporterBootstrap versionImporterBootstrap = (ImporterBootstrap)ctx.getBean("versionBootstrap"); + bootstrapVersionTenantStore(versionImporterBootstrap, tenantDomain); + + ImporterBootstrap version2ImporterBootstrap = (ImporterBootstrap)ctx.getBean("version2Bootstrap"); + bootstrapVersionTenantStore(version2ImporterBootstrap, tenantDomain); - ImporterBootstrap spacesArchiveImporterBootstrap = (ImporterBootstrap)ctx.getBean("spacesArchiveBootstrap"); - bootstrapSpacesArchiveTenantStore(spacesArchiveImporterBootstrap, tenantDomain); - - ImporterBootstrap spacesImporterBootstrap = (ImporterBootstrap)ctx.getBean("spacesBootstrap"); - bootstrapSpacesTenantStore(spacesImporterBootstrap, tenantDomain); - - siteAVMBootstrap.bootstrap(); - - // notify listeners that tenant has been created & hence enabled - for (TenantDeployer tenantDeployer : tenantDeployers) - { - tenantDeployer.onEnableTenant(); - } - - // bootstrap workflows - for (WorkflowDeployer workflowDeployer : workflowDeployers) - { - workflowDeployer.init(); - } - - // bootstrap modules (if any) - moduleService.startModules(); - - return null; - } - }, getSystemUser(tenantDomain)); + ImporterBootstrap spacesArchiveImporterBootstrap = (ImporterBootstrap)ctx.getBean("spacesArchiveBootstrap"); + bootstrapSpacesArchiveTenantStore(spacesArchiveImporterBootstrap, tenantDomain); + + ImporterBootstrap spacesImporterBootstrap = (ImporterBootstrap)ctx.getBean("spacesBootstrap"); + bootstrapSpacesTenantStore(spacesImporterBootstrap, tenantDomain); + + siteAVMBootstrap.bootstrap(); + + // notify listeners that tenant has been created & hence enabled + for (TenantDeployer tenantDeployer : tenantDeployers) + { + tenantDeployer.onEnableTenant(); + } + + // bootstrap workflows + for (WorkflowDeployer workflowDeployer : workflowDeployers) + { + workflowDeployer.init(); + } + + // bootstrap modules (if any) + moduleService.startModules(); + } + finally + { + AuthenticationUtil.popAuthentication(); + } logger.info("Tenant created: " + tenantDomain); } @@ -419,39 +424,42 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo { initTenant(tenantDomain, rootContentStoreDir); - AuthenticationUtil.runAs(new RunAsWork() - { - 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(); - } - - // bootstrap workflows - for (WorkflowDeployer workflowDeployer : workflowDeployers) - { - workflowDeployer.init(); - } - - // bootstrap modules (if any) - moduleService.startModules(); - - return null; - } - }, getSystemUser(tenantDomain)); + try + { + // note: runAs would cause auditable property "creator" to be "admin" instead of "System@xxx" + AuthenticationUtil.pushAuthentication(); + AuthenticationUtil.setFullyAuthenticatedUser(getSystemUser(tenantDomain)); + + 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(); + } + + // bootstrap workflows + for (WorkflowDeployer workflowDeployer : workflowDeployers) + { + workflowDeployer.init(); + } + + // bootstrap modules (if any) + moduleService.startModules(); + } + finally + { + AuthenticationUtil.popAuthentication(); + } logger.info("Tenant imported: " + tenantDomain); } @@ -919,11 +927,9 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo spacesImporterBootstrap.bootstrap(); - /* TODO - pending fix for ETHREEOH-283 // calculate any missing usages UserUsageTrackingComponent userUsageTrackingComponent = (UserUsageTrackingComponent)ctx.getBean(UserUsageBootstrapJob.KEY_COMPONENT); userUsageTrackingComponent.bootstrapInternal(); - */ logger.debug("Bootstrapped store: " + tenantService.getBaseName(bootstrapStoreRef)); } @@ -968,8 +974,7 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo { try { - // switch to admin in order to deploy within context of tenant domain - // assumes each tenant has default "admin" user + // deploy within context of tenant domain AuthenticationUtil.runAs(new RunAsWork() { public Object doWork() @@ -1036,8 +1041,7 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo { try { - // switch to admin in order to deploy within context of tenant domain - // assumes each tenant has default "admin" user + // undeploy within context of tenant domain AuthenticationUtil.runAs(new RunAsWork() { public Object doWork() diff --git a/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java b/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java index 856178ea05..ec547b93d3 100644 --- a/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java +++ b/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java @@ -42,6 +42,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; @@ -85,6 +86,7 @@ public class MultiTDemoTest extends TestCase private TenantService tenantService; private AuthorityService authorityService; private CategoryService categoryService; + private CheckOutCheckInService cociService; public static int NUM_TENANTS = 11; @@ -140,6 +142,7 @@ public class MultiTDemoTest extends TestCase ownableService = (OwnableService) ctx.getBean("OwnableService"); authorityService = (AuthorityService) ctx.getBean("AuthorityService"); categoryService = (CategoryService) ctx.getBean("CategoryService"); + cociService = (CheckOutCheckInService) ctx.getBean("CheckoutCheckinService"); } @Override @@ -572,6 +575,85 @@ public class MultiTDemoTest extends TestCase } } + public void testCOCIandSearch() + { + logger.info("Test checkout/checkin and search"); + + for (final String tenantDomain : tenants) + { + final String tenantAdminName = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + // search for local copy of bootstrapped file 'invite_user_email.ftl' (see email_templates.acp) + String origText = "You have been invited to"; + String query = "+PATH:\"/app:company_home/app:dictionary/app:email_templates/*\" +TEXT:\""+origText+"\""; + ResultSet resultSet = searchService.query(SPACES_STORE, SearchService.LANGUAGE_LUCENE, query); + assertEquals(1, resultSet.length()); + + NodeRef nodeRef = resultSet.getNodeRef(0); + + // checkout, update and checkin + + NodeRef workingCopyNodeRef = cociService.checkout(nodeRef); + + ContentWriter writer = contentService.getWriter(workingCopyNodeRef, ContentModel.PROP_CONTENT, true); + + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + + String updateText = "Updated by "+tenantAdminName; + writer.putContent(updateText); + + cociService.checkin(workingCopyNodeRef, null); + + query = "+PATH:\"/app:company_home/app:dictionary/app:email_templates/*\" +TEXT:\""+origText+"\""; + resultSet = searchService.query(SPACES_STORE, SearchService.LANGUAGE_LUCENE, query); + assertEquals(0, resultSet.length()); + + query = "+PATH:\"/app:company_home/app:dictionary/app:email_templates/*\" +TEXT:\""+updateText+"\""; + resultSet = searchService.query(SPACES_STORE, SearchService.LANGUAGE_LUCENE, query); + assertEquals(1, resultSet.length()); + + return null; + } + }, tenantAdminName); + } + } + + public void testDeleteArchiveAndRestoreContent() + { + logger.info("test delete/archive & restore content"); + + for (final String tenantDomain : tenants) + { + final String tenantUserName = tenantService.getDomainUser(TEST_USER1, tenantDomain); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + NodeRef homeSpaceRef = getHomeSpaceFolderNode(tenantUserName); + NodeRef contentRef = addTextContent(homeSpaceRef, tenantUserName+" tqbfjotld.txt", "The quick brown fox jumps over the lazy dog (tenant " + tenantDomain + ")"); + + NodeRef storeArchiveNode = nodeService.getStoreArchiveNode(contentRef.getStoreRef()); + + nodeService.deleteNode(contentRef); + + // deduce archived nodeRef + StoreRef archiveStoreRef = storeArchiveNode.getStoreRef(); + NodeRef archivedContentRef = new NodeRef(archiveStoreRef, contentRef.getId()); + + nodeService.restoreNode(archivedContentRef, null, null, null); + + return null; + } + }, tenantUserName); + } + } + private void createGroup(String shortName, String parentShortName) { // create new Group using authority Service diff --git a/source/java/org/alfresco/repo/usage/ContentUsageImpl.java b/source/java/org/alfresco/repo/usage/ContentUsageImpl.java index 2c05f9d42b..8536abc602 100644 --- a/source/java/org/alfresco/repo/usage/ContentUsageImpl.java +++ b/source/java/org/alfresco/repo/usage/ContentUsageImpl.java @@ -344,7 +344,7 @@ public class ContentUsageImpl implements ContentUsageService, private void incrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef) { - if (! userName.equals(authenticationComponent.getSystemUserName())) + if (! authenticationComponent.isSystemUserName(userName)) { // increment usage - add positive delta if (logger.isDebugEnabled()) logger.debug("incrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef); @@ -366,14 +366,17 @@ public class ContentUsageImpl implements ContentUsageService, throw new ContentQuotaException("User quota exceeded"); } - NodeRef personNodeRef = personService.getPerson(userName); - usageService.insertDelta(personNodeRef, contentSize); + NodeRef personNodeRef = getPerson(userName); + if (personNodeRef != null) + { + usageService.insertDelta(personNodeRef, contentSize); + } } } private void decrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef) { - if (! userName.equals(authenticationComponent.getSystemUserName())) + if (! authenticationComponent.isSystemUserName(userName)) { // decrement usage - add negative delta if (logger.isDebugEnabled()) logger.debug("decrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef); @@ -390,8 +393,11 @@ public class ContentUsageImpl implements ContentUsageService, } } - NodeRef personNodeRef = personService.getPerson(userName); - usageService.insertDelta(personNodeRef, (-contentSize)); + NodeRef personNodeRef = getPerson(userName); + if (personNodeRef != null) + { + usageService.insertDelta(personNodeRef, (-contentSize)); + } } } @@ -424,7 +430,7 @@ public class ContentUsageImpl implements ContentUsageService, { long currentUsage = -1; - NodeRef personNodeRef = personService.getPerson(userName); + NodeRef personNodeRef = getPerson(userName); if (personNodeRef != null) { currentUsage = getUserStoredUsage(personNodeRef); @@ -457,7 +463,7 @@ public class ContentUsageImpl implements ContentUsageService, */ public void setUserQuota(String userName, long currentQuota) { - NodeRef personNodeRef = personService.getPerson(userName); + NodeRef personNodeRef = getPerson(userName); if (personNodeRef != null) { nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA, new Long(currentQuota)); @@ -468,7 +474,7 @@ public class ContentUsageImpl implements ContentUsageService, { Long currentQuota = null; - NodeRef personNodeRef = personService.getPerson(userName); + NodeRef personNodeRef = getPerson(userName); if (personNodeRef != null) { currentQuota = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA); @@ -481,4 +487,27 @@ public class ContentUsageImpl implements ContentUsageService, { return enabled; } + + private NodeRef getPerson(String userName) + { + NodeRef personNodeRef = null; + try + { + personNodeRef = personService.getPerson(userName); + } + catch (RuntimeException e) + { + // workaround for ETHREEOH-1457 where existing tenants (created using 3.0.1) may have been bootstrapped with creator set + // to super admin (eg. "admin") rather than "System@xxx". This workaround should remain until we patch any such existing tenants + if (tenantService.isEnabled()) + { + personNodeRef = null; + } + else + { + throw e; + } + } + return personNodeRef; + } } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowModel.java b/source/java/org/alfresco/repo/workflow/WorkflowModel.java index b914a2d362..736e0fff51 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowModel.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowModel.java @@ -58,6 +58,7 @@ public interface WorkflowModel static final QName PROP_OUTCOME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "outcome"); static final QName PROP_PACKAGE_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageActionGroup"); static final QName PROP_PACKAGE_ITEM_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageItemActionGroup"); + static final QName PROP_HIDDEN_TRANSITIONS = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "hiddenTransitions"); static final QName ASSOC_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package"); // workflow task contstants