diff --git a/config/alfresco/dbscripts/upgrade/4.0/org.hibernate.dialect.Dialect/AclChangeSet-Tracking2.sql b/config/alfresco/dbscripts/upgrade/4.0/org.hibernate.dialect.Dialect/AclChangeSet-Tracking2.sql
index 5a862266b0..4d3ad56922 100644
--- a/config/alfresco/dbscripts/upgrade/4.0/org.hibernate.dialect.Dialect/AclChangeSet-Tracking2.sql
+++ b/config/alfresco/dbscripts/upgrade/4.0/org.hibernate.dialect.Dialect/AclChangeSet-Tracking2.sql
@@ -8,13 +8,17 @@
--
-- Migrate data
+
+--ASSIGN:min_tx_ms=min_tx_ms
+SELECT min(commit_time_ms) as min_tx_ms from alf_transaction;
+
--FOREACH alf_acl_change_set.id system.upgrade.alf_acl_change_set.batchsize
UPDATE alf_acl_change_set
SET
- commit_time_ms = ((select min(t.commit_time_ms) from alf_transaction t) + id)
+ commit_time_ms = ${min_tx_ms} + id
WHERE
id >= ${LOWERBOUND} AND id <= ${UPPERBOUND}
- AND commit_time_ms < (select min(t.commit_time_ms) from alf_transaction t)
+ AND commit_time_ms < ${min_tx_ms}
;
diff --git a/config/alfresco/extension/hazelcastConfig.xml.sample b/config/alfresco/extension/hazelcastConfig.xml.sample
new file mode 100644
index 0000000000..5cd2991026
--- /dev/null
+++ b/config/alfresco/extension/hazelcastConfig.xml.sample
@@ -0,0 +1,192 @@
+
+
+
+ dev
+ dev-pass
+
+
+ 5701
+
+
+ 224.2.2.3
+ 54327
+
+
+ 127.0.0.1
+
+
+
+ 192.168.56.1
+
+
+
+ PBEWithMD5AndDES
+
+ thesalt
+
+ thepass
+
+ 19
+
+
+
+ RSA/NONE/PKCS1PADDING
+
+ thekeypass
+
+ local
+
+ JKS
+
+ thestorepass
+
+ keystore
+
+
+
+ 16
+ 64
+ 60
+
+
+
+ 0
+
+ 0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/messages/patch-service_de.properties b/config/alfresco/messages/patch-service_de.properties
index ca54d72ba8..b328dd8a15 100755
--- a/config/alfresco/messages/patch-service_de.properties
+++ b/config/alfresco/messages/patch-service_de.properties
@@ -161,6 +161,8 @@ patch.wcmFolders.webprojects.result.created=The Web Projects folder was successf
patch.wcmFolders.webforms.result.exists=The Web Forms folder already exists: {0}
patch.wcmFolders.webforms.result.created=The Web Forms folder was successfully created: {0}
+patch.wcmDeployed.description=Adds the 'WCM Deployed' space to the company home folder.
+
patch.linkNodeExtension.description=Fixes link node file extensions to have a .url extension.
patch.linkNodeExtension.result=Fixed {0} link node file extensions. See file {1} for details.
patch.linkNodeExtension.err.unable_to_fix=Auto-fixing of link node file extensions failed. See file {0} for details.
@@ -470,3 +472,8 @@ patch.migrateTenantsFromAttrsToTable.result=Processed {0} tenants
patch.remoteCredentialsContainer.description=Patch to add the root folder for Shared Remote Credentials
patch.syncSetDefinitionsContainer.description=Patch to add the root folder for SyncSet Definitions
+
+patch.swsdpPatch.description=Patch to fix up the Sample: Web Site Design Project.
+patch.swsdpPatch.success=Successfully patched the Sample: Web Site Design Project.
+patch.swsdpPatch.skipped=Skipped, not required.
+patch.swsdpPatch.missingSurfConfig=surf-config folder is not present in Sample: Web Site Design Project.
\ No newline at end of file
diff --git a/config/alfresco/messages/patch-service_it.properties b/config/alfresco/messages/patch-service_it.properties
index ca54d72ba8..b328dd8a15 100755
--- a/config/alfresco/messages/patch-service_it.properties
+++ b/config/alfresco/messages/patch-service_it.properties
@@ -161,6 +161,8 @@ patch.wcmFolders.webprojects.result.created=The Web Projects folder was successf
patch.wcmFolders.webforms.result.exists=The Web Forms folder already exists: {0}
patch.wcmFolders.webforms.result.created=The Web Forms folder was successfully created: {0}
+patch.wcmDeployed.description=Adds the 'WCM Deployed' space to the company home folder.
+
patch.linkNodeExtension.description=Fixes link node file extensions to have a .url extension.
patch.linkNodeExtension.result=Fixed {0} link node file extensions. See file {1} for details.
patch.linkNodeExtension.err.unable_to_fix=Auto-fixing of link node file extensions failed. See file {0} for details.
@@ -470,3 +472,8 @@ patch.migrateTenantsFromAttrsToTable.result=Processed {0} tenants
patch.remoteCredentialsContainer.description=Patch to add the root folder for Shared Remote Credentials
patch.syncSetDefinitionsContainer.description=Patch to add the root folder for SyncSet Definitions
+
+patch.swsdpPatch.description=Patch to fix up the Sample: Web Site Design Project.
+patch.swsdpPatch.success=Successfully patched the Sample: Web Site Design Project.
+patch.swsdpPatch.skipped=Skipped, not required.
+patch.swsdpPatch.missingSurfConfig=surf-config folder is not present in Sample: Web Site Design Project.
\ No newline at end of file
diff --git a/config/alfresco/messages/patch-service_ja.properties b/config/alfresco/messages/patch-service_ja.properties
index ca54d72ba8..b328dd8a15 100755
--- a/config/alfresco/messages/patch-service_ja.properties
+++ b/config/alfresco/messages/patch-service_ja.properties
@@ -161,6 +161,8 @@ patch.wcmFolders.webprojects.result.created=The Web Projects folder was successf
patch.wcmFolders.webforms.result.exists=The Web Forms folder already exists: {0}
patch.wcmFolders.webforms.result.created=The Web Forms folder was successfully created: {0}
+patch.wcmDeployed.description=Adds the 'WCM Deployed' space to the company home folder.
+
patch.linkNodeExtension.description=Fixes link node file extensions to have a .url extension.
patch.linkNodeExtension.result=Fixed {0} link node file extensions. See file {1} for details.
patch.linkNodeExtension.err.unable_to_fix=Auto-fixing of link node file extensions failed. See file {0} for details.
@@ -470,3 +472,8 @@ patch.migrateTenantsFromAttrsToTable.result=Processed {0} tenants
patch.remoteCredentialsContainer.description=Patch to add the root folder for Shared Remote Credentials
patch.syncSetDefinitionsContainer.description=Patch to add the root folder for SyncSet Definitions
+
+patch.swsdpPatch.description=Patch to fix up the Sample: Web Site Design Project.
+patch.swsdpPatch.success=Successfully patched the Sample: Web Site Design Project.
+patch.swsdpPatch.skipped=Skipped, not required.
+patch.swsdpPatch.missingSurfConfig=surf-config folder is not present in Sample: Web Site Design Project.
\ No newline at end of file
diff --git a/config/alfresco/messages/patch-service_nl.properties b/config/alfresco/messages/patch-service_nl.properties
index ca54d72ba8..b328dd8a15 100755
--- a/config/alfresco/messages/patch-service_nl.properties
+++ b/config/alfresco/messages/patch-service_nl.properties
@@ -161,6 +161,8 @@ patch.wcmFolders.webprojects.result.created=The Web Projects folder was successf
patch.wcmFolders.webforms.result.exists=The Web Forms folder already exists: {0}
patch.wcmFolders.webforms.result.created=The Web Forms folder was successfully created: {0}
+patch.wcmDeployed.description=Adds the 'WCM Deployed' space to the company home folder.
+
patch.linkNodeExtension.description=Fixes link node file extensions to have a .url extension.
patch.linkNodeExtension.result=Fixed {0} link node file extensions. See file {1} for details.
patch.linkNodeExtension.err.unable_to_fix=Auto-fixing of link node file extensions failed. See file {0} for details.
@@ -470,3 +472,8 @@ patch.migrateTenantsFromAttrsToTable.result=Processed {0} tenants
patch.remoteCredentialsContainer.description=Patch to add the root folder for Shared Remote Credentials
patch.syncSetDefinitionsContainer.description=Patch to add the root folder for SyncSet Definitions
+
+patch.swsdpPatch.description=Patch to fix up the Sample: Web Site Design Project.
+patch.swsdpPatch.success=Successfully patched the Sample: Web Site Design Project.
+patch.swsdpPatch.skipped=Skipped, not required.
+patch.swsdpPatch.missingSurfConfig=surf-config folder is not present in Sample: Web Site Design Project.
\ No newline at end of file
diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml
index b55cc790f8..b79259f006 100644
--- a/config/alfresco/patch/patch-services-context.xml
+++ b/config/alfresco/patch/patch-services-context.xml
@@ -3066,6 +3066,9 @@
+
+
+
diff --git a/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml b/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml
index eff8c4eaf7..013f56e5f5 100644
--- a/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml
+++ b/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml
@@ -36,6 +36,13 @@
2
+
+
+
+ ${ooo.exe}
+
+
+
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/ImapUnsubscribedAspectPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/ImapUnsubscribedAspectPatch.java
index fd18573e32..da098033eb 100644
--- a/source/java/org/alfresco/repo/admin/patch/impl/ImapUnsubscribedAspectPatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/impl/ImapUnsubscribedAspectPatch.java
@@ -21,9 +21,7 @@ package org.alfresco.repo.admin.patch.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ImapModel;
@@ -33,6 +31,7 @@ import org.alfresco.repo.batch.BatchProcessor;
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback;
+import org.alfresco.repo.domain.patch.PatchDAO;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.PersonService;
@@ -45,27 +44,21 @@ public class ImapUnsubscribedAspectPatch extends AbstractPatch
{
private static final String MSG_NONSUBSCRIBED_ASPECT_REMOVED = "patch.imapUnsubscribedAspect.result.removed";
private static final QName ASPECT_NON_SUBSCRIBED = QName.createQName("{http://www.alfresco.org/model/imap/1.0}nonSubscribed");
- private static final String PROP_MIN_ID = "minNodeId";
private NodeDAO nodeDAO;
+ private PatchDAO patchDAO;
private PersonService personService;
- private final Map properties = new HashMap();
+ private final int batchThreads = 3;
+ private final int batchSize = 40;
+ private final long count = batchThreads * batchSize;
+ private long minSearchNodeId = 1;
- private int batchThreads = 3;
- private int batchSize = 40;
- private long count = batchThreads * batchSize;
-
- @Override
- public void init()
- {
- super.init();
- properties.put(PROP_MIN_ID, 1L);
- }
@Override
protected String applyInternal() throws Exception
{
final List users = nodeService.getChildAssocs(personService.getPeopleContainer(), ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL);
+ final long maxNodeId = patchDAO.getMaxAdmNodeID();
BatchProcessWorkProvider workProvider = new BatchProcessWorkProvider()
{
@@ -79,17 +72,21 @@ public class ImapUnsubscribedAspectPatch extends AbstractPatch
public Collection getNextWork()
{
result.clear();
- nodeDAO.getNodesWithAspects(Collections.singleton(ASPECT_NON_SUBSCRIBED), properties.get(PROP_MIN_ID), count, new NodeRefQueryCallback()
+ while (result.isEmpty() && minSearchNodeId < maxNodeId)
{
+ nodeDAO.getNodesWithAspects(Collections.singleton(ASPECT_NON_SUBSCRIBED), minSearchNodeId,
+ minSearchNodeId + count, new NodeRefQueryCallback()
+ {
- public boolean handle(Pair nodePair)
- {
- properties.put(PROP_MIN_ID, nodePair.getFirst());
- result.add(nodePair.getSecond());
- return true;
- }
+ public boolean handle(Pair nodePair)
+ {
+ result.add(nodePair.getSecond());
+ return true;
+ }
- });
+ });
+ minSearchNodeId = minSearchNodeId + count + 1;
+ }
return result;
}
@@ -137,6 +134,11 @@ public class ImapUnsubscribedAspectPatch extends AbstractPatch
this.nodeDAO = nodeDAO;
}
+ public void setPatchDAO(PatchDAO patchDAO)
+ {
+ this.patchDAO = patchDAO;
+ }
+
public void setPersonService(PersonService personService)
{
this.personService = personService;
diff --git a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
index 08cc2e7186..ea6db37f68 100644
--- a/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
+++ b/source/java/org/alfresco/repo/content/transform/TransformerDebug.java
@@ -613,7 +613,7 @@ public class TransformerDebug
}
if (frame != null)
{
- sb.append(spaces(9-sb.length()+lengthOfFirstId)); // Try to pad to level 5
+ sb.append(spaces(11-sb.length()+lengthOfFirstId)); // Try to pad to level 7
}
return sb.toString();
}
diff --git a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
index b7439acafc..7e1a2e9993 100644
--- a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
+++ b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
@@ -940,6 +940,20 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
return nodePair.getSecond().getNodeStatus();
}
}
+
+ public Status getNodeIdStatus(Long nodeId)
+ {
+ Pair nodePair = nodesCache.getByKey(nodeId);
+ // The nodesCache gets both live and deleted nodes.
+ if (nodePair == null)
+ {
+ return null;
+ }
+ else
+ {
+ return nodePair.getSecond().getNodeStatus();
+ }
+ }
public Pair getNodePair(NodeRef nodeRef)
{
diff --git a/source/java/org/alfresco/repo/domain/node/NodeDAO.java b/source/java/org/alfresco/repo/domain/node/NodeDAO.java
index bd0043725d..5669e7ee99 100644
--- a/source/java/org/alfresco/repo/domain/node/NodeDAO.java
+++ b/source/java/org/alfresco/repo/domain/node/NodeDAO.java
@@ -146,6 +146,16 @@ public interface NodeDAO extends NodeBulkLoader
*/
public NodeRef.Status getNodeRefStatus(NodeRef nodeRef);
+ /**
+ * Get the current status of the node, including deleted nodes.
+ *
+ * @param nodeId the node id
+ * @return Returns the current status of the reference.
+ * This will only be null if the node never existed or has been
+ * purged following deletion.
+ */
+ public NodeRef.Status getNodeIdStatus(Long nodeId);
+
public Pair getNodePair(NodeRef nodeRef);
public Pair getNodePair(Long nodeId);
diff --git a/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java b/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java
index 17f6d20eac..55e35b338d 100644
--- a/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java
+++ b/source/java/org/alfresco/repo/search/impl/solr/SolrQueryHTTPClient.java
@@ -188,11 +188,10 @@ public class SolrQueryHTTPClient implements BeanFactoryAware
}
url.append("/").append(languageUrlFragment);
- // duplicate the query in the URL
- url.append("?q=");
-
- url.append(encoder.encode(searchParameters.getQuery(), "UTF-8"));
- url.append("&wt=").append(encoder.encode("json", "UTF-8"));
+ // Send the query in JSON only
+ // url.append("?q=");
+ // url.append(encoder.encode(searchParameters.getQuery(), "UTF-8"));
+ url.append("?wt=").append(encoder.encode("json", "UTF-8"));
url.append("&fl=").append(encoder.encode("DBID,score", "UTF-8"));
if (searchParameters.getMaxItems() >= 0)
diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
index 1df3de8633..53461085f3 100644
--- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
+++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java
@@ -760,6 +760,17 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
// Create a prefixed zone ID for use with the authority service
final String zoneId = AuthorityService.ZONE_AUTH_EXT_PREFIX + zone;
+ // Ensure that the zoneId exists before multiple threads start using it
+ this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback()
+ {
+ @Override
+ public Void execute() throws Throwable
+ {
+ authorityService.getOrCreateZone(zoneId);
+ return null;
+ }
+ }, false, splitTxns);
+
// The set of zones we associate with new objects (default plus registry specific)
final Set zoneSet = getZones(zoneId);
@@ -1856,7 +1867,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
* the zone id
* @return the zone set
*/
- private Set getZones(String zoneId)
+ private Set getZones(final String zoneId)
{
Set zones = new HashSet(5);
zones.add(AuthorityService.ZONE_APP_DEFAULT);
diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java
index f60725b401..c85ef42406 100644
--- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java
+++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java
@@ -922,7 +922,8 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic
// Only search for "st:site" nodes.
final Set searchTypeQNames = new HashSet(1);
searchTypeQNames.add(SiteModel.TYPE_SITE);
-// searchTypeQNames.addAll(dictionaryService.getSubTypes(SiteModel.TYPE_SITE, true));
+ // ... and all subtypes of st:site
+ searchTypeQNames.addAll(dictionaryService.getSubTypes(SiteModel.TYPE_SITE, true));
// get canned query
final String cQBeanName = "siteGetChildrenCannedQueryFactory";
diff --git a/source/java/org/alfresco/repo/site/SiteServiceImplMoreTest.java b/source/java/org/alfresco/repo/site/SiteServiceImplMoreTest.java
new file mode 100644
index 0000000000..4144e459ce
--- /dev/null
+++ b/source/java/org/alfresco/repo/site/SiteServiceImplMoreTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.repo.site;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.query.PagingRequest;
+import org.alfresco.query.PagingResults;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
+import org.alfresco.service.cmr.site.SiteInfo;
+import org.alfresco.service.cmr.site.SiteService;
+import org.alfresco.service.cmr.site.SiteVisibility;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.test.junitrules.ApplicationContextInit;
+import org.alfresco.util.test.junitrules.RunAsFullyAuthenticatedRule;
+import org.alfresco.util.test.junitrules.TemporarySites;
+import org.alfresco.util.test.junitrules.TemporarySitesTest;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.springframework.extensions.webscripts.GUID;
+
+/**
+ * This class contains some tests for the {@link SiteServiceImpl} - in addition to those already
+ * included in {@link SiteServiceImplTest}. This uses JUnit 4 annotations and JUnit Rules.
+ *
+ * TODO Refactor the two classes together into one common approach.
+ *
+ * @author Neil Mc Erlean
+ * @since 4.0.3
+ */
+public class SiteServiceImplMoreTest
+{
+ // Rule to initialise the default Alfresco spring configuration
+ public static ApplicationContextInit APP_CONTEXT_INIT = ApplicationContextInit.createStandardContextWithOverrides("classpath:sites/test-"
+ + TemporarySitesTest.class.getSimpleName() + "-context.xml");
+
+ // A rule to manage test nodes reused across all the test methods
+ public static TemporarySites STATIC_TEST_SITES = new TemporarySites(APP_CONTEXT_INIT);
+
+ // Tie them together in a static Rule Chain
+ @ClassRule public static RuleChain ruleChain = RuleChain.outerRule(APP_CONTEXT_INIT)
+ .around(STATIC_TEST_SITES);
+
+ @Rule public RunAsFullyAuthenticatedRule runAllTestsAsAdmin = new RunAsFullyAuthenticatedRule(AuthenticationUtil.getAdminUserName());
+
+ // Various services
+ private static NamespaceService NAMESPACE_SERVICE;
+ private static SiteService SITE_SERVICE;
+ private static RetryingTransactionHelper TRANSACTION_HELPER;
+
+ private static String TEST_SITE_NAME, TEST_SUB_SITE_NAME;
+
+ @BeforeClass public static void initStaticData() throws Exception
+ {
+ NAMESPACE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("namespaceService", NamespaceService.class);
+ SITE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("siteService", SiteService.class);
+ TRANSACTION_HELPER = APP_CONTEXT_INIT.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
+
+ // We'll create this test content as admin.
+ final String admin = AuthenticationUtil.getAdminUserName();
+
+ TEST_SITE_NAME = GUID.generate();
+ TEST_SUB_SITE_NAME = GUID.generate();
+
+ final QName subSiteType = QName.createQName("testsite", "testSubsite", NAMESPACE_SERVICE);
+
+ STATIC_TEST_SITES.createSite("sitePreset", TEST_SITE_NAME, "siteTitle", "siteDescription", SiteVisibility.PUBLIC, admin);
+ STATIC_TEST_SITES.createSite("sitePreset", TEST_SUB_SITE_NAME, "siteTitle", "siteDescription", SiteVisibility.PUBLIC, subSiteType, admin);
+ }
+
+ /**
+ * This method ensures that {@link SiteService#listSites(String)} includes content subtypes of {@link SiteModel#TYPE_SITE st:site}.
+ */
+ @Test public void listSitesIncludingSubTypesOfSite() throws Exception
+ {
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ PagingResults sites = SITE_SERVICE.listSites(null, null, new PagingRequest(0, 1024));
+
+ Map sitesByName = new HashMap();
+ for (SiteInfo site : sites.getPage())
+ {
+ sitesByName.put(site.getShortName(), site);
+ }
+
+ assertNotNull("st:site missing.", sitesByName.get(TEST_SITE_NAME));
+ assertNotNull("subtype of st:site missing.", sitesByName.get(TEST_SUB_SITE_NAME));
+
+ return null;
+ }
+ });
+ }
+}
diff --git a/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java b/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
index 370e9534c9..cef153790f 100644
--- a/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
+++ b/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
@@ -52,6 +52,7 @@ import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeRef.Status;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.OwnableService;
@@ -381,9 +382,40 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
return false;
}
- private Collection> getCategoryPaths(NodeRef nodeRef, Set aspects, Map properties)
+ static class CategoryPaths
+ {
+ Collection> paths;
+ List categoryParents;
+
+ CategoryPaths( Collection> paths, List categoryParents)
+ {
+ this.paths = paths;
+ this.categoryParents = categoryParents;
+ }
+
+ /**
+ * @return the paths
+ */
+ public Collection> getPaths()
+ {
+ return paths;
+ }
+
+ /**
+ * @return the categoryParents
+ */
+ public List getCategoryParents()
+ {
+ return categoryParents;
+ }
+
+
+ }
+
+ private CategoryPaths getCategoryPaths(NodeRef nodeRef, Set aspects, Map properties)
{
ArrayList> categoryPaths = new ArrayList>();
+ ArrayList categoryParents = new ArrayList();
nodeDAO.setCheckNodeConsistency();
for (QName classRef : aspects)
@@ -439,13 +471,16 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
{
Path.ChildAssocElement cae = (Path.ChildAssocElement) pair.getFirst().last();
ChildAssociationRef assocRef = cae.getRef();
- pair.getFirst().append(new Path.ChildAssocElement(new ChildAssociationRef(assocRef.getTypeQName(), assocRef.getChildRef(), QName.createQName("member"), nodeRef)));
+ ChildAssociationRef categoryParentRef = new ChildAssociationRef(assocRef.getTypeQName(), assocRef.getChildRef(), QName.createQName("member"), nodeRef);
+ pair.getFirst().append(new Path.ChildAssocElement(categoryParentRef));
+ categoryParents.add(categoryParentRef);
}
}
- return categoryPaths;
+ return new CategoryPaths(categoryPaths, categoryParents);
}
+
private List preCacheNodes(NodeMetaDataParameters nodeMetaDataParameters)
{
nodeDAO.setCheckNodeConsistency();
@@ -536,26 +571,33 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
for(Long nodeId : nodeIds)
{
- Map props = null;
- Set aspects = null;
-
- if (!nodeDAO.exists(nodeId))
- {
- // Deleted nodes have no metadata
- continue;
- }
-
+ Status status = nodeDAO.getNodeIdStatus(nodeId);
+ NodeRef nodeRef = status.getNodeRef();
+
NodeMetaData nodeMetaData = new NodeMetaData();
nodeMetaData.setNodeId(nodeId);
-
- Pair pair = nodeDAO.getNodePair(nodeId);
- nodeMetaData.setAclId(nodeDAO.getNodeAclId(nodeId));
-
+
+ if(includeNodeRef)
+ {
+ nodeMetaData.setNodeRef(tenantService.getBaseName(nodeRef, true));
+ }
+
if(includeTxnId)
{
- nodeMetaData.setTxnId(nodeDAO.getNodeRefStatus(pair.getSecond()).getDbTxnId());
+ nodeMetaData.setTxnId(status.getDbTxnId());
}
+ if(status.isDeleted())
+ {
+ rowHandler.processResult(nodeMetaData);
+ continue;
+ }
+
+ Map props = null;
+ Set aspects = null;
+
+ nodeMetaData.setAclId(nodeDAO.getNodeAclId(nodeId));
+
if(includeType)
{
QName nodeType = nodeDAO.getNodeType(nodeId);
@@ -572,7 +614,10 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
if(includeProperties)
{
- props = getProperties(nodeId);
+ if(props == null)
+ {
+ props = getProperties(nodeId);
+ }
nodeMetaData.setProperties(props);
}
else
@@ -580,7 +625,7 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
nodeMetaData.setProperties(Collections.emptyMap());
}
- if(includeAspects)
+ if(includeAspects || includePaths || includeParentAssociations)
{
aspects = new HashSet();
Set sourceAspects = nodeDAO.getNodeAspects(nodeId);
@@ -595,35 +640,38 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
}
nodeMetaData.setAspects(aspects);
+ CategoryPaths categoryPaths = new CategoryPaths(new ArrayList>(), new ArrayList());
+ if(includePaths || includeParentAssociations)
+ {
+ if(props == null)
+ {
+ props = getProperties(nodeId);
+ }
+ categoryPaths = getCategoryPaths(status.getNodeRef(), aspects, props);
+ }
+
if(includePaths)
{
if(props == null)
{
props = getProperties(nodeId);
}
- Collection> categoryPaths = getCategoryPaths(pair.getSecond(), aspects, props);
- List directPaths = nodeDAO.getPaths(pair, false);
- Collection> paths = new ArrayList>(directPaths.size() + categoryPaths.size());
+ List directPaths = nodeDAO.getPaths(new Pair(nodeId, status.getNodeRef()), false);
+
+ Collection> paths = new ArrayList>(directPaths.size() + categoryPaths.getPaths().size());
for (Path path : directPaths)
{
paths.add(new Pair(path.getBaseNamePath(tenantService), null));
}
- for(Pair catPair : categoryPaths)
+ for(Pair catPair : categoryPaths.getPaths())
{
paths.add(new Pair(catPair.getFirst().getBaseNamePath(tenantService), catPair.getSecond()));
}
nodeMetaData.setPaths(paths);
}
-
- NodeRef nodeRef = pair.getSecond();
-
- if(includeNodeRef)
- {
- nodeMetaData.setNodeRef(tenantService.getBaseName(nodeRef, true));
- }
-
+
nodeMetaData.setTenantDomain(tenantService.getDomain(nodeRef.getStoreRef().getIdentifier()));
if(includeChildAssociations)
@@ -722,6 +770,10 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
{
}
});
+ for(ChildAssociationRef ref : categoryPaths.getCategoryParents())
+ {
+ parentAssocs.add(tenantService.getBaseName(ref, true));
+ }
CRC32 crc = new CRC32();
for(ChildAssociationRef car : parentAssocs)
@@ -747,7 +799,7 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
if(includeOwner)
{
// cached in OwnableService
- nodeMetaData.setOwner(ownableService.getOwner(pair.getSecond()));
+ nodeMetaData.setOwner(ownableService.getOwner(status.getNodeRef()));
}
rowHandler.processResult(nodeMetaData);
diff --git a/source/java/org/alfresco/util/OpenOfficeCommandEnv.java b/source/java/org/alfresco/util/OpenOfficeCommandEnv.java
new file mode 100644
index 0000000000..f8b7d758aa
--- /dev/null
+++ b/source/java/org/alfresco/util/OpenOfficeCommandEnv.java
@@ -0,0 +1,62 @@
+/* Copyright (C) 2005-2012 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.util.OpenOfficeURI;
+import org.alfresco.util.exec.RuntimeExec;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A map giving the environment openoffice or libreoffice commands require to start.
+ *
+ * @author Alan Davis
+ */
+public class OpenOfficeCommandEnv extends AbstractMap
+{
+ private static final Log logger = LogFactory.getLog(OpenOfficeCommandLine.class);
+ private static final String DYLD_LIBRARY_PATH = "DYLD_LIBRARY_PATH";
+
+ private Map map = new HashMap(System.getenv());
+ private OpenOfficeVariant variant = new OpenOfficeVariant();
+
+ public OpenOfficeCommandEnv(String exe) throws IOException
+ {
+ if (variant.isMac())
+ {
+ map.remove(DYLD_LIBRARY_PATH);
+ logger.debug("Removing $DYLD_LIBRARY_PATH from the environment so that LibreOffice/OpenOffice will start on Mac.");
+ }
+ }
+
+ @Override
+ public Set> entrySet()
+ {
+ return map.entrySet();
+ }
+}
diff --git a/source/java/org/alfresco/util/OpenOfficeCommandLine.java b/source/java/org/alfresco/util/OpenOfficeCommandLine.java
index ae41d230b8..ea8f36cf17 100644
--- a/source/java/org/alfresco/util/OpenOfficeCommandLine.java
+++ b/source/java/org/alfresco/util/OpenOfficeCommandLine.java
@@ -26,7 +26,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.util.OpenOfficeURI;
import org.alfresco.util.exec.RuntimeExec;
import org.apache.commons.logging.Log;
@@ -40,30 +39,30 @@ import org.apache.commons.logging.LogFactory;
*/
public class OpenOfficeCommandLine extends AbstractMap>
{
- private static final String[] EXTENSIONS = new String[] {"", ".exe", ".com", ".bat", ".cmd"};
-
private static final Log logger = LogFactory.getLog(OpenOfficeCommandLine.class);
-
- private static final String OS_NAME = System.getProperty("os.name").toLowerCase();
-
private Map> map = new HashMap>();
-
- private boolean windows;
+ private OpenOfficeVariant variant = new OpenOfficeVariant();
public OpenOfficeCommandLine(String exe, String port, String user) throws IOException
{
- windows = isWindows();
- File executable = findExecutable(exe);
- File officeHome = getOfficeHome(executable);
+ File executable = variant.findExecutable(exe);
+ File officeHome = variant.getOfficeHome(executable);
List command = new ArrayList();
String acceptValue = "socket,host=127.0.0.1,port="+port+";urp;StarOffice.ServiceManager";
String userInstallation = new OpenOfficeURI(user).toString();
command.add(executable == null ? exe : executable.getAbsolutePath());
- if (isLibreOffice3Dot5(officeHome))
+ if (variant.isLibreOffice3Dot5(officeHome))
{
command.add("--accept=" + acceptValue);
- command.add("-env:UserInstallation=" + userInstallation);
+ if (variant.isMac())
+ {
+ command.add("--env:UserInstallation=" + userInstallation);
+ }
+ else
+ {
+ command.add("-env:UserInstallation=" + userInstallation);
+ }
command.add("--headless");
command.add("--nocrashreport");
//command.add("--nodefault"); included by JOD
@@ -71,7 +70,7 @@ public class OpenOfficeCommandLine extends AbstractMap>
//command.add("--nolockcheck"); included by JOD
command.add("--nologo");
command.add("--norestore");
- logger.info("Using GNU based LibreOffice command: "+command);
+ logger.info("Using GNU based LibreOffice command"+(variant.isMac() ? " on Mac" : "")+": "+command);
}
else
{
@@ -89,100 +88,6 @@ public class OpenOfficeCommandLine extends AbstractMap>
map.put(RuntimeExec.KEY_OS_DEFAULT, command);
}
- private File getOfficeHome(File executable)
- {
- // Get the grandparent
- File officeHome = executable;
- for (int i=1; officeHome != null && i <= 2; i++)
- {
- officeHome = officeHome.getParentFile();
- }
-
- if (officeHome == null && executable != null)
- {
- throw new AlfrescoRuntimeException("Did not find OppenOffice home from executable "+executable.getAbsolutePath());
- }
-
- return officeHome;
- }
-
- private File findExecutable(String executableName)
- {
- File file = new File(executableName);
- if (file.isAbsolute())
- {
- file = canExecute(file);
- }
- else
- {
- file = findExecutableOnPath(executableName);
- }
- return file;
- }
-
- private File findExecutableOnPath(String executableName)
- {
- String systemPath = System.getenv("PATH");
- systemPath = systemPath == null ? System.getenv("path") : systemPath;
- String[] pathDirs = systemPath.split(File.pathSeparator);
-
- File fullyQualifiedExecutable = null;
- for (String pathDir : pathDirs)
- {
- File file = canExecute(new File(pathDir, executableName));
- if (file != null)
- {
- fullyQualifiedExecutable = file;
- break;
- }
- }
- return fullyQualifiedExecutable;
- }
-
- private File canExecute(File file)
- {
- File fullyQualifiedExecutable = null;
- File dir = file.getParentFile();
- String name = file.getName();
- for (String ext: EXTENSIONS)
- {
- file = new File(dir, name+ext);
- if (file.canExecute())
- {
- fullyQualifiedExecutable = file;
- break;
- }
- if (!windows)
- {
- break;
- }
- }
- return fullyQualifiedExecutable;
- }
-
- private boolean isLibreOffice3Dot5(File officeHome)
- {
- return
- officeHome != null &&
- !new File(officeHome, "basis-link").isFile() &&
- new File(officeHome, "ure-link").isFile();
- }
-
- private static boolean isLinux()
- {
- return OS_NAME.startsWith("linux");
- }
-
- private static boolean isMac()
- {
- return OS_NAME.startsWith("mac");
- }
-
- private static boolean isWindows()
- {
- return OS_NAME.startsWith("windows");
- }
-
@Override
public Set>> entrySet()
{
diff --git a/source/java/org/alfresco/util/OpenOfficeVariant.java b/source/java/org/alfresco/util/OpenOfficeVariant.java
new file mode 100644
index 0000000000..d645cc72f6
--- /dev/null
+++ b/source/java/org/alfresco/util/OpenOfficeVariant.java
@@ -0,0 +1,139 @@
+/* Copyright (C) 2005-2012 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.util;
+
+import java.io.File;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Provides OpenOffice and LibreOffice variant information.
+ *
+ * @author Alan Davis
+ */
+public class OpenOfficeVariant
+{
+ private static final String[] EXTENSIONS = new String[] {"", ".exe", ".com", ".bat", ".cmd"};
+ private static final Log logger = LogFactory.getLog(OpenOfficeCommandLine.class);
+ private static final String OS_NAME = System.getProperty("os.name").toLowerCase();
+
+ private final boolean windows = isWindows();
+
+ public File getOfficeHome(File executable)
+ {
+ // Get the grandparent
+ File officeHome = executable;
+ for (int i=1; officeHome != null && i <= 2; i++)
+ {
+ officeHome = officeHome.getParentFile();
+ }
+
+ if (officeHome == null && executable != null)
+ {
+ throw new AlfrescoRuntimeException("Did not find OppenOffice home from executable "+executable.getAbsolutePath());
+ }
+
+ return officeHome;
+ }
+
+ public File findExecutable(String executableName)
+ {
+ File file = new File(executableName);
+ if (file.isAbsolute())
+ {
+ file = canExecute(file);
+ }
+ else
+ {
+ file = findExecutableOnPath(executableName);
+ }
+ return file;
+ }
+
+ private File findExecutableOnPath(String executableName)
+ {
+ String systemPath = System.getenv("PATH");
+ systemPath = systemPath == null ? System.getenv("path") : systemPath;
+ String[] pathDirs = systemPath.split(File.pathSeparator);
+
+ File fullyQualifiedExecutable = null;
+ for (String pathDir : pathDirs)
+ {
+ File file = canExecute(new File(pathDir, executableName));
+ if (file != null)
+ {
+ fullyQualifiedExecutable = file;
+ break;
+ }
+ }
+ return fullyQualifiedExecutable;
+ }
+
+ private File canExecute(File file)
+ {
+ File fullyQualifiedExecutable = null;
+ File dir = file.getParentFile();
+ String name = file.getName();
+ for (String ext: EXTENSIONS)
+ {
+ file = new File(dir, name+ext);
+ if (file.canExecute())
+ {
+ fullyQualifiedExecutable = file;
+ break;
+ }
+ if (!windows)
+ {
+ break;
+ }
+ }
+ return fullyQualifiedExecutable;
+ }
+
+ public boolean isLibreOffice3Dot5(File officeHome)
+ {
+ logger.debug("System.getProperty(\"os.name\")="+System.getProperty("os.name"));
+ logger.debug("officeHome="+(officeHome == null ? null : "'"+officeHome.getAbsolutePath()+"'"));
+ logger.debug("basis-link:"+new File(officeHome, "basis-link").isFile());
+ logger.debug(" ure-link:"+new File(officeHome, "ure-link").isFile());
+ logger.debug("basis-link:"+new File(officeHome, "basis-link").isDirectory());
+ logger.debug(" ure-link:"+new File(officeHome, "ure-link").isDirectory());
+
+ return
+ officeHome != null &&
+ !new File(officeHome, "basis-link").isFile() &&
+ (new File(officeHome, "ure-link").isFile() || new File(officeHome, "ure-link").isDirectory());
+ }
+
+ public boolean isLinux()
+ {
+ return OS_NAME.startsWith("linux");
+ }
+
+ public boolean isMac()
+ {
+ return OS_NAME.startsWith("mac");
+ }
+
+ public boolean isWindows()
+ {
+ return OS_NAME.startsWith("windows");
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/util/test/junitrules/TemporarySites.java b/source/java/org/alfresco/util/test/junitrules/TemporarySites.java
new file mode 100644
index 0000000000..2b4a66c9c2
--- /dev/null
+++ b/source/java/org/alfresco/util/test/junitrules/TemporarySites.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2005-2012
+ Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.util.test.junitrules;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
+import org.alfresco.repo.site.SiteModel;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
+import org.alfresco.service.cmr.site.SiteInfo;
+import org.alfresco.service.cmr.site.SiteService;
+import org.alfresco.service.cmr.site.SiteVisibility;
+import org.alfresco.service.namespace.QName;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.rules.ExternalResource;
+
+/**
+ * A JUnit rule designed to help with the automatic cleanup of temporary st:site nodes.
+ *
+ * @author Neil Mc Erlean
+ * @since 4.0.3
+ */
+public class TemporarySites extends ExternalResource
+{
+ private static final Log log = LogFactory.getLog(TemporarySites.class);
+
+ private final ApplicationContextInit appContextRule;
+ private List temporarySites = new ArrayList();
+
+ /**
+ * Constructs the rule with a reference to a {@link ApplicationContextInit rule} which can be used to retrieve the ApplicationContext.
+ *
+ * @param appContextRule a rule which can be used to retrieve the spring app context.
+ */
+ public TemporarySites(ApplicationContextInit appContextRule)
+ {
+ this.appContextRule = appContextRule;
+ }
+
+
+ @Override protected void before() throws Throwable
+ {
+ // Intentionally empty
+ }
+
+ @Override protected void after()
+ {
+ final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) appContextRule.getApplicationContext().getBean("retryingTransactionHelper");
+ final SiteService siteService = appContextRule.getApplicationContext().getBean("siteService", SiteService.class);
+
+ // Run as admin to ensure all sites can be deleted irrespective of which user created them.
+ AuthenticationUtil.runAs(new RunAsWork()
+ {
+ @Override public Void doWork() throws Exception
+ {
+ transactionHelper.doInTransaction(new RetryingTransactionCallback()
+ {
+ @Override public Void execute() throws Throwable
+ {
+ for (SiteInfo site : temporarySites)
+ {
+ final String shortName = site.getShortName();
+ if (siteService.getSite(shortName) != null)
+ {
+ log.debug("Deleting temporary site " + shortName);
+ siteService.deleteSite(shortName);
+ }
+ }
+
+ return null;
+ }
+ });
+ return null;
+ }
+ }, AuthenticationUtil.getAdminUserName());
+ }
+
+ /**
+ * Add a specified site to the list of SiteInfos to be deleted by this rule.
+ *
+ * @param temporarySite a SiteInfo
+ */
+ public void addSite(SiteInfo temporarySite)
+ {
+ this.temporarySites.add(temporarySite);
+ }
+
+ /**
+ * This method creates a Share Site and adds it to the internal list of NodeRefs to be tidied up by the rule.
+ * This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
+ * thus ensuring the named user is the creator of the new site.
+ *
+ * @param sitePreset the site preset
+ * @param siteShortName the short name of the new site
+ * @param siteTitle the title of the new site
+ * @param siteDescription the description of the new site
+ * @param visibility the visibility
+ * @param siteCreator the username of the person who will create the site
+ * @return the newly created SiteInfo (will be of type st:site).
+ */
+ public SiteInfo createSite(final String sitePreset, final String siteShortName, final String siteTitle, final String siteDescription,
+ final SiteVisibility visibility, final String siteCreator)
+ {
+ return this.createSite(sitePreset, siteShortName, siteTitle, siteDescription, visibility, SiteModel.TYPE_SITE, siteCreator);
+ }
+
+ /**
+ * This method creates a Share Site (or subtype) and adds it to the internal list of NodeRefs to be tidied up by the rule.
+ * This method will be run in its own transaction and will be run with the specified user as the fully authenticated user,
+ * thus ensuring the named user is the creator of the new site.
+ *
+ * @param sitePreset the site preset
+ * @param siteShortName the short name of the new site
+ * @param siteTitle the title of the new site
+ * @param siteDescription the description of the new site
+ * @param visibility the visibility
+ * @param node type the node type of the site (must be st:site or subtype)
+ * @param siteCreator the username of the person who will create the site
+ * @return the newly created SiteInfo.
+ */
+ public SiteInfo createSite(final String sitePreset, final String siteShortName, final String siteTitle, final String siteDescription,
+ final SiteVisibility visibility, final QName siteType, final String siteCreator)
+ {
+ final RetryingTransactionHelper transactionHelper = appContextRule.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
+
+ AuthenticationUtil.pushAuthentication();
+ AuthenticationUtil.setFullyAuthenticatedUser(siteCreator);
+
+ SiteInfo newSite = transactionHelper.doInTransaction(new RetryingTransactionCallback()
+ {
+ public SiteInfo execute() throws Throwable
+ {
+ final SiteService siteService = appContextRule.getApplicationContext().getBean("siteService", SiteService.class);
+
+ return siteService.createSite(sitePreset, siteShortName, siteTitle, siteDescription, visibility, siteType);
+ }
+ });
+
+ AuthenticationUtil.popAuthentication();
+
+ this.temporarySites.add(newSite);
+ return newSite;
+ }
+}
diff --git a/source/java/org/alfresco/util/test/junitrules/TemporarySitesTest.java b/source/java/org/alfresco/util/test/junitrules/TemporarySitesTest.java
new file mode 100644
index 0000000000..46cfb5fe89
--- /dev/null
+++ b/source/java/org/alfresco/util/test/junitrules/TemporarySitesTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+
+package org.alfresco.util.test.junitrules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
+import org.alfresco.service.cmr.site.SiteInfo;
+import org.alfresco.service.cmr.site.SiteService;
+import org.alfresco.service.cmr.site.SiteVisibility;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+/**
+ * Test class for {@link TemporarySites}.
+ *
+ * @author Neil McErlean
+ * @since 4.0.3
+ */
+public class TemporarySitesTest
+{
+ // Rule to initialise the default Alfresco spring configuration
+ public static ApplicationContextInit APP_CONTEXT_INIT =
+ ApplicationContextInit.createStandardContextWithOverrides("classpath:sites/test-"
+ + TemporarySitesTest.class.getSimpleName() + "-context.xml");
+
+ // A rule to manage test sites reused across all the test methods
+ public static TemporaryNodes STATIC_TEST_SITES = new TemporaryNodes(APP_CONTEXT_INIT);
+
+ // Tie them together in a static Rule Chain
+ @ClassRule public static RuleChain ruleChain = RuleChain.outerRule(APP_CONTEXT_INIT)
+ .around(STATIC_TEST_SITES);
+
+ // A rule to manage test sites use in each test method
+ @Rule public TemporarySites testSites = new TemporarySites(APP_CONTEXT_INIT);
+
+ // A rule to allow individual test methods all to be run as "admin".
+ @Rule public RunAsFullyAuthenticatedRule runAsRule = new RunAsFullyAuthenticatedRule(AuthenticationUtil.getAdminUserName());
+
+ // Various services
+ private static NamespaceService NAMESPACE_SERVICE;
+ private static SiteService SITE_SERVICE;
+ private static RetryingTransactionHelper TRANSACTION_HELPER;
+
+ // These SiteInfos are used by the test methods.
+ private SiteInfo testSite1, testSite2;
+
+ @BeforeClass public static void initStaticData() throws Exception
+ {
+ NAMESPACE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("namespaceService", NamespaceService.class);
+ SITE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("siteService", SiteService.class);
+ TRANSACTION_HELPER = APP_CONTEXT_INIT.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class);
+ }
+
+ @Before public void createTestContent()
+ {
+ // Create some test content
+ testSite1 = testSites.createSite("sitePreset", "testSite1", "t", "d", SiteVisibility.PUBLIC, AuthenticationUtil.getAdminUserName());
+ final QName subSiteType = QName.createQName("testsite", "testSubsite", NAMESPACE_SERVICE);
+ testSite2 = testSites.createSite("sitePreset", "testSite2", "T", "D", SiteVisibility.PUBLIC, subSiteType, AuthenticationUtil.getAdminUserName());
+ }
+
+ @Test public void ensureTestSitesWereCreatedOk() throws Exception
+ {
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ final SiteInfo recoveredSite1 = SITE_SERVICE.getSite(testSite1.getShortName());
+ final SiteInfo recoveredSite2 = SITE_SERVICE.getSite(testSite2.getShortName());
+
+ assertNotNull("Test site does not exist", recoveredSite1);
+ assertNotNull("Test site does not exist", recoveredSite2);
+
+ assertEquals("cm:title was wrong", "t", recoveredSite1.getTitle());
+ assertEquals("cm:description was wrong", "d", recoveredSite1.getDescription());
+ assertEquals("preset was wrong", "sitePreset", recoveredSite1.getSitePreset());
+
+ assertEquals("site visibility was wrong", SiteVisibility.PUBLIC, recoveredSite1.getVisibility());
+
+ return null;
+ }
+ });
+ }
+}
diff --git a/source/test-resources/sites/test-TemporarySitesTest-context.xml b/source/test-resources/sites/test-TemporarySitesTest-context.xml
new file mode 100644
index 0000000000..6bebc9cd1b
--- /dev/null
+++ b/source/test-resources/sites/test-TemporarySitesTest-context.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ sites/testSiteModel.xml
+
+
+
+
+
diff --git a/source/test-resources/sites/testSiteModel.xml b/source/test-resources/sites/testSiteModel.xml
new file mode 100644
index 0000000000..ea7f2a0db8
--- /dev/null
+++ b/source/test-resources/sites/testSiteModel.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ Test Site Model
+ Alfresco
+ 1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test Sub-site
+ st:site
+
+
+
\ No newline at end of file