diff --git a/.externalToolBuilders/JibX.launch b/.externalToolBuilders/JibX.launch
index 186d90d901..209a3cdd97 100644
--- a/.externalToolBuilders/JibX.launch
+++ b/.externalToolBuilders/JibX.launch
@@ -1,34 +1,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/activiti-context.xml b/config/alfresco/activiti-context.xml
index c91dc97b24..691440e49a 100644
--- a/config/alfresco/activiti-context.xml
+++ b/config/alfresco/activiti-context.xml
@@ -60,6 +60,9 @@
+
+ ${system.workflow.deployWorkflowsInTenant}
+
@@ -90,7 +93,7 @@
-
+
@@ -123,13 +126,12 @@
-
+
-
-
+
@@ -228,12 +230,6 @@
factory-method="getManagementService" />
-
-
-
-
-
-
+
diff --git a/config/alfresco/application-context.xml b/config/alfresco/application-context.xml
index 4506f69de6..3c046a0300 100644
--- a/config/alfresco/application-context.xml
+++ b/config/alfresco/application-context.xml
@@ -16,6 +16,9 @@
-->
+
+
+
diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml
index a58806787c..43008c4aef 100644
--- a/config/alfresco/bootstrap-context.xml
+++ b/config/alfresco/bootstrap-context.xml
@@ -835,4 +835,10 @@
+
+
+
+
+
diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml
index 155df3f97a..92ea231226 100644
--- a/config/alfresco/content-services-context.xml
+++ b/config/alfresco/content-services-context.xml
@@ -367,7 +367,7 @@
-
+
cm:expiryDate
sys:clientVisibilityMask
+ cm:lastThumbnailModification
+ cm:likesRatingSchemeTotal
+ cm:likesRatingSchemeCount
+ cm:fiveStarRatingSchemeCount
+ cm:fiveStarRatingSchemeTotal
+
+ fm:commentCount
diff --git a/config/alfresco/hazelcast/hazelcast-ec2.xml b/config/alfresco/hazelcast/hazelcast-ec2.xml
new file mode 100644
index 0000000000..b4a3f8b7bd
--- /dev/null
+++ b/config/alfresco/hazelcast/hazelcast-ec2.xml
@@ -0,0 +1,183 @@
+
+
+
+ ${alfresco.cluster.name}
+ ${alfresco.hazelcast.password}
+
+
+ 5701
+
+
+ 224.2.2.3
+ 54327
+
+
+ 127.0.0.1
+
+
+ ${alfresco.hazelcast.ec2.accesskey}
+ ${alfresco.hazelcast.ec2.secretkey}
+
+ ${alfresco.hazelcast.ec2.region}
+
+ ${alfresco.hazelcast.ec2.securitygroup}
+ ${alfresco.hazelcast.ec2.tagkey}
+ ${alfresco.hazelcast.ec2.tagvalue}
+
+
+
+ 10.10.1.*
+
+
+
+ PBEWithMD5AndDES
+
+ thesalt
+
+ thepass
+
+ 19
+
+
+
+ RSA/NONE/PKCS1PADDING
+
+ thekeypass
+
+ local
+
+ JKS
+
+ thestorepass
+
+ keystore
+
+
+
+ 16
+ 64
+ 60
+
+
+
+ 0
+
+ default
+
+
+
+
+
+
+
+
+
+
+
+ log4j
+ false
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/hazelcast/hazelcast-tcp.xml b/config/alfresco/hazelcast/hazelcast-tcp.xml
new file mode 100644
index 0000000000..8fa5a13238
--- /dev/null
+++ b/config/alfresco/hazelcast/hazelcast-tcp.xml
@@ -0,0 +1,180 @@
+
+
+
+ ${alfresco.cluster.name}
+ ${alfresco.hazelcast.password}
+
+
+ 5701
+
+
+ 224.2.2.3
+ 54327
+
+
+ ${alfresco.hazelcast.tcp.config}
+ 127.0.0.1
+
+
+ my-access-key
+ my-secret-key
+
+ us-west-1
+
+ hazelcast-sg
+ type
+ hz-nodes
+
+
+
+ 10.10.1.*
+
+
+
+ PBEWithMD5AndDES
+
+ thesalt
+
+ thepass
+
+ 19
+
+
+
+ RSA/NONE/PKCS1PADDING
+
+ thekeypass
+
+ local
+
+ JKS
+
+ thestorepass
+
+ keystore
+
+
+
+ 16
+ 64
+ 60
+
+
+
+ 0
+
+ default
+
+
+
+
+
+
+
+
+
+
+
+ log4j
+
+
\ No newline at end of file
diff --git a/config/alfresco/hazelcast/hazelcast-udp.xml b/config/alfresco/hazelcast/hazelcast-udp.xml
new file mode 100644
index 0000000000..4b6765eda9
--- /dev/null
+++ b/config/alfresco/hazelcast/hazelcast-udp.xml
@@ -0,0 +1,179 @@
+
+
+
+ ${alfresco.cluster.name}
+ ${alfresco.hazelcast.password}
+
+
+ 5701
+
+
+ 224.2.2.3
+ 54327
+
+
+ 127.0.0.1
+
+
+ my-access-key
+ my-secret-key
+
+ us-west-1
+
+ hazelcast-sg
+ type
+ hz-nodes
+
+
+
+ 10.10.1.*
+
+
+
+ PBEWithMD5AndDES
+
+ thesalt
+
+ thepass
+
+ 19
+
+
+
+ RSA/NONE/PKCS1PADDING
+
+ thekeypass
+
+ local
+
+ JKS
+
+ thestorepass
+
+ keystore
+
+
+
+ 16
+ 64
+ 60
+
+
+
+ 0
+
+ default
+
+
+
+
+
+
+
+
+
+
+
+ log4j
+
+
\ No newline at end of file
diff --git a/config/alfresco/mt/mt-base-context.xml b/config/alfresco/mt/mt-base-context.xml
index 562a9fb310..2983ce4ccc 100644
--- a/config/alfresco/mt/mt-base-context.xml
+++ b/config/alfresco/mt/mt-base-context.xml
@@ -33,10 +33,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -213,12 +66,136 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/tx-cache-context.xml b/config/alfresco/tx-cache-context.xml
index 7c0699742b..fc9fc48918 100644
--- a/config/alfresco/tx-cache-context.xml
+++ b/config/alfresco/tx-cache-context.xml
@@ -575,7 +575,7 @@
- org.alfresco.tenantsTransactionalCache
+ org.alfresco.cache.tenantEntityTransactionalCache
diff --git a/config/alfresco/webdav-context.xml b/config/alfresco/webdav-context.xml
index 5d938f577e..a45954e5ae 100644
--- a/config/alfresco/webdav-context.xml
+++ b/config/alfresco/webdav-context.xml
@@ -25,7 +25,38 @@
-
+
+
+
+
+
+
+
+
+
+
+ ${alfresco.cluster.name}
+ ${alfresco.hazelcast.password}
+ ${alfresco.hazelcast.specify.interface}
+ ${alfresco.hazelcast.bind.interface}
+
+ ${alfresco.hazelcast.tcp.config}
+
+ ${alfresco.hazelcast.ec2.accesskey}
+ ${alfresco.hazelcast.ec2.secretkey}
+ ${alfresco.hazelcast.ec2.region}
+ ${alfresco.hazelcast.ec2.securitygroup}
+ ${alfresco.hazelcast.ec2.tagkey}
+ ${alfresco.hazelcast.ec2.tagvalue}
+
+ ${alfresco.conccurrentusers.timeToLive}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml
index ea9d1f7018..a1f9c6068b 100644
--- a/config/alfresco/workflow-context.xml
+++ b/config/alfresco/workflow-context.xml
@@ -37,6 +37,9 @@
${system.workflow.maxPooledTasks}
+
+ ${system.workflow.deployWorkflowsInTenant}
+
diff --git a/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java
index f7728011f7..3a32bfb062 100644
--- a/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java
+++ b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java
@@ -19,6 +19,8 @@
package org.alfresco.opencmis;
import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.math.BigInteger;
@@ -69,6 +71,7 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.Pair;
+import org.alfresco.util.TempFileProvider;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.AllowableActions;
@@ -156,78 +159,6 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
objectInfoMap = new HashMap();
}
- @Override
- public void beforeCall()
- {
- AuthenticationUtil.pushAuthentication();
- if (authentication != null)
- {
- // Use the previously-obtained authentication
- AuthenticationUtil.setFullAuthentication(authentication);
- }
- else
- {
- if (context == null)
- {
- // Service not opened, yet
- return;
- }
- // Sticky sessions?
- if (connector.openHttpSession())
- {
- // create a session -> set a cookie
- // if the CMIS client supports cookies that might help in clustered environments
- ((HttpServletRequest) getContext().get(CallContext.HTTP_SERVLET_REQUEST)).getSession();
- }
-
- // Authenticate
- if (authentication != null)
- {
- // We have already authenticated; just reuse the authentication
- AuthenticationUtil.setFullAuthentication(authentication);
- }
- else
- {
- // First check if we already are authenticated
- if (AuthenticationUtil.getFullyAuthenticatedUser() == null)
- {
- // We have to go to the repo and authenticate
- String user = getContext().getUsername();
- String password = getContext().getPassword();
- Authorization auth = new Authorization(user, password);
- if (auth.isTicket())
- {
- connector.getAuthenticationService().validate(auth.getTicket());
- }
- else
- {
- connector.getAuthenticationService().authenticate(auth.getUserName(), auth.getPasswordCharArray());
- }
- }
- this.authentication = AuthenticationUtil.getFullAuthentication();
- }
-
-// // TODO: How is the proxy user working.
-// // Until we know what it is meant to do, it's not available
-// String currentUser = connector.getAuthenticationService().getCurrentUserName();
-// String user = getContext().getUsername();
-// String password = getContext().getPassword();
-// if (currentUser != null && currentUser.equals(connector.getProxyUser()))
-// {
-// if (user != null && user.length() > 0)
-// {
-// AuthenticationUtil.setFullyAuthenticatedUser(user);
-// }
-// }
- }
- }
-
- @Override
- public void afterCall()
- {
- AuthenticationUtil.popAuthentication();
- }
-
@Override
public void open(CallContext context)
{
@@ -571,10 +502,10 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
{
try
{
- if(connector.filter(child.getNodeRef()))
- {
- continue;
- }
+ if(connector.filter(child.getNodeRef()))
+ {
+ continue;
+ }
// create a child CMIS object
CMISNodeInfo ni = createNodeInfo(child.getNodeRef());
@@ -711,19 +642,19 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
if(isFolder && type.getAlfrescoClass().equals(ContentModel.TYPE_SYSTEM_FOLDER))
{
- continue;
+ continue;
}
- if(connector.isHidden(child.getChildRef()))
- {
- continue;
- }
+ if(connector.isHidden(child.getChildRef()))
+ {
+ continue;
+ }
- if(connector.filter(child.getChildRef()))
- {
- continue;
- }
-
+ if(connector.filter(child.getChildRef()))
+ {
+ continue;
+ }
+
// create a child CMIS object
ObjectInFolderDataImpl object = new ObjectInFolderDataImpl();
CMISNodeInfo ni = createNodeInfo(child.getChildRef());
@@ -1000,11 +931,11 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
{
for (NodeRef nodeRef : nodeRefs)
{
- // TODO - perhaps filter by path in the query instead?
- if(connector.filter(nodeRef))
- {
- continue;
- }
+ // TODO - perhaps filter by path in the query instead?
+ if(connector.filter(nodeRef))
+ {
+ continue;
+ }
if (skipCounter > 0)
{
@@ -1197,7 +1128,10 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
throw new CmisConstraintException("This document type is not versionable!");
}
- final Charset encoding = getEncoding(contentStream);
+ // copy stream to temp file
+ // OpenCMIS does this for us ....
+ final File tempFile = copyToTempFile(contentStream);
+ final Charset encoding = (tempFile == null ? null : getEncoding(tempFile, contentStream.getMimeType()));
FileInfo fileInfo = connector.getFileFolderService().create(
parentInfo.getNodeRef(), name, type.getAlfrescoClass());
@@ -1214,7 +1148,7 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
String mimeType = stripEncoding(contentStream.getMimeType());
writer.setMimetype(mimeType);
writer.setEncoding(encoding.name());
- writer.putContent(contentStream.getStream());
+ writer.putContent(tempFile);
}
connector.extractMetadata(nodeRef);
@@ -1224,6 +1158,8 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
connector.applyVersioningState(nodeRef, versioningState);
+ removeTempFile(tempFile);
+
String objectId = connector.createObjectId(nodeRef);
connector.getActivityPoster().postFileFolderAdded(fileInfo);
@@ -1406,12 +1342,21 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
throw new CmisInvalidArgumentException("No content!");
}
- final Charset encoding = getEncoding(contentStream);
+ // copy stream to temp file
+ final File tempFile = copyToTempFile(contentStream);
+ final Charset encoding = getEncoding(tempFile, contentStream.getMimeType());
- ContentWriter writer = connector.getFileFolderService().getWriter(nodeRef);
- writer.setMimetype(contentStream.getMimeType());
- writer.setEncoding(encoding.name());
- writer.putContent(contentStream.getStream());
+ try
+ {
+ ContentWriter writer = connector.getFileFolderService().getWriter(nodeRef);
+ writer.setMimetype(contentStream.getMimeType());
+ writer.setEncoding(encoding.name());
+ writer.putContent(tempFile);
+ }
+ finally
+ {
+ removeTempFile(tempFile);
+ }
objectId.setValue(connector.createObjectId(nodeRef));
@@ -1583,9 +1528,9 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
if(info.hasPWC())
{
- // is a checked out document. If a delete, don't allow unless checkout is canceled. If a cancel
- // checkout, not allowed.
- throw new CmisConstraintException(
+ // is a checked out document. If a delete, don't allow unless checkout is canceled. If a cancel
+ // checkout, not allowed.
+ throw new CmisConstraintException(
"Could not delete/cancel checkout on the original checked out document");
}
@@ -1936,7 +1881,9 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
final NodeRef nodeRef = info.getNodeRef();
final TypeDefinitionWrapper type = info.getType();
- final Charset encoding = getEncoding(contentStream);
+ // copy stream to temp file
+ final File tempFile = copyToTempFile(contentStream);
+ final Charset encoding = (tempFile == null ? null : getEncoding(tempFile, contentStream.getMimeType()));
// check in
// update PWC
@@ -1952,7 +1899,7 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
ContentWriter writer = connector.getFileFolderService().getWriter(nodeRef);
writer.setMimetype(contentStream.getMimeType());
writer.setEncoding(encoding.name());
- writer.putContent(contentStream.getStream());
+ writer.putContent(tempFile);
}
// check aspect
@@ -1979,6 +1926,8 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
connector.getActivityPoster().postFileFolderUpdated(info.isFolder(), newNodeRef);
objectId.setValue(connector.createObjectId(newNodeRef));
+
+ removeTempFile(tempFile);
}
@Override
@@ -2454,15 +2403,15 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
protected String getGuid(String nodeId)
{
- int idx = nodeId.lastIndexOf("/");
- if(idx != -1)
- {
- return nodeId.substring(idx+1);
- }
- else
- {
- return nodeId;
- }
+ int idx = nodeId.lastIndexOf("/");
+ if(idx != -1)
+ {
+ return nodeId.substring(idx+1);
+ }
+ else
+ {
+ return nodeId;
+ }
}
/**
@@ -2693,25 +2642,137 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
}
}
- private Charset getEncoding(ContentStream stream)
+ private Charset getEncoding(File tempFile, String mimeType)
{
Charset encoding = null;
- if(stream != null)
+ try
{
- try
- {
- String mimeType = stream.getMimeType();
- InputStream tfis = new BufferedInputStream(stream.getStream());
- ContentCharsetFinder charsetFinder = connector.getMimetypeService().getContentCharsetFinder();
- encoding = charsetFinder.getCharset(tfis, mimeType);
- tfis.close();
- } catch (Exception e)
- {
- throw new CmisStorageException("Unable to read content: " + e.getMessage(), e);
- }
+ InputStream tfis = new BufferedInputStream(new FileInputStream(tempFile));
+ ContentCharsetFinder charsetFinder = connector.getMimetypeService().getContentCharsetFinder();
+ encoding = charsetFinder.getCharset(tfis, mimeType);
+ tfis.close();
+ } catch (Exception e)
+ {
+ throw new CmisStorageException("Unable to read content: " + e.getMessage(), e);
}
return encoding;
}
+
+ private File copyToTempFile(ContentStream contentStream)
+ {
+ if (contentStream == null)
+ {
+ return null;
+ }
+
+ File result = null;
+ try
+ {
+ result = TempFileProvider.createTempFile(contentStream.getStream(), "cmis", "content");
+ }
+ catch (Exception e)
+ {
+ throw new CmisStorageException("Unable to store content: " + e.getMessage(), e);
+ }
+
+ if ((contentStream.getLength() > -1) && (result == null || contentStream.getLength() != result.length()))
+ {
+ removeTempFile(result);
+ throw new CmisStorageException("Expected " + contentStream.getLength() + " bytes but retrieved " +
+ (result == null ? -1 :result.length()) + " bytes!");
+ }
+
+ return result;
+ }
+
+ private void removeTempFile(File tempFile)
+ {
+ if (tempFile == null)
+ {
+ return;
+ }
+
+ try
+ {
+ tempFile.delete();
+ }
+ catch (Exception e)
+ {
+ // ignore - file will be removed by TempFileProvider
+ }
+ }
+
+ @Override
+ public void beforeCall()
+ {
+ AuthenticationUtil.pushAuthentication();
+ if (authentication != null)
+ {
+ // Use the previously-obtained authentication
+ AuthenticationUtil.setFullAuthentication(authentication);
+ }
+ else
+ {
+ if (context == null)
+ {
+ // Service not opened, yet
+ return;
+ }
+ // Sticky sessions?
+ if (connector.openHttpSession())
+ {
+ // create a session -> set a cookie
+ // if the CMIS client supports cookies that might help in clustered environments
+ ((HttpServletRequest) getContext().get(CallContext.HTTP_SERVLET_REQUEST)).getSession();
+ }
+
+ // Authenticate
+ if (authentication != null)
+ {
+ // We have already authenticated; just reuse the authentication
+ AuthenticationUtil.setFullAuthentication(authentication);
+ }
+ else
+ {
+ // First check if we already are authenticated
+ if (AuthenticationUtil.getFullyAuthenticatedUser() == null)
+ {
+ // We have to go to the repo and authenticate
+ String user = context.getUsername();
+ String password = context.getPassword();
+ Authorization auth = new Authorization(user, password);
+ if (auth.isTicket())
+ {
+ connector.getAuthenticationService().validate(auth.getTicket());
+ }
+ else
+ {
+ connector.getAuthenticationService().authenticate(auth.getUserName(), auth.getPasswordCharArray());
+ }
+ }
+ this.authentication = AuthenticationUtil.getFullAuthentication();
+ }
+
+// // TODO: How is the proxy user working.
+// // Until we know what it is meant to do, it's not available
+// String currentUser = connector.getAuthenticationService().getCurrentUserName();
+// String user = getContext().getUsername();
+// String password = getContext().getPassword();
+// if (currentUser != null && currentUser.equals(connector.getProxyUser()))
+// {
+// if (user != null && user.length() > 0)
+// {
+// AuthenticationUtil.setFullyAuthenticatedUser(user);
+// }
+// }
+ }
+ }
+
+ @Override
+ public void afterCall()
+ {
+ AuthenticationUtil.popAuthentication();
+ }
}
diff --git a/source/java/org/alfresco/opencmis/CMISConnector.java b/source/java/org/alfresco/opencmis/CMISConnector.java
index 1ac4dd6604..57636c0234 100644
--- a/source/java/org/alfresco/opencmis/CMISConnector.java
+++ b/source/java/org/alfresco/opencmis/CMISConnector.java
@@ -71,7 +71,6 @@ import org.alfresco.repo.security.permissions.impl.AccessPermissionImpl;
import org.alfresco.repo.security.permissions.impl.ModelDAO;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.tenant.TenantDeployer;
-import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.repo.thumbnail.ThumbnailHelper;
import org.alfresco.repo.thumbnail.ThumbnailRegistry;
@@ -260,7 +259,6 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
private RenditionService renditionService;
private FileFolderService fileFolderService;
private TenantAdminService tenantAdminService;
- private TenantService tenantService;
private TransactionService transactionService;
private AuthenticationService authenticationService;
private PermissionService permissionService;
@@ -307,15 +305,15 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
private ObjectFilter objectFilter;
+ // --------------------------------------------------------------
+ // Configuration
+ // --------------------------------------------------------------
+
public void setObjectFilter(ObjectFilter objectFilter)
{
this.objectFilter = objectFilter;
}
- // --------------------------------------------------------------
- // Configuration
- // --------------------------------------------------------------
-
/**
* Sets the root store.
*
@@ -342,11 +340,6 @@ public class CMISConnector implements ApplicationContextAware, ApplicationListen
return activityPoster;
}
- public void setTenantService(TenantService tenantService)
- {
- this.tenantService = tenantService;
- }
-
public void setHiddenAspect(HiddenAspect hiddenAspect)
{
this.hiddenAspect = hiddenAspect;
diff --git a/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java b/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java
index ee609d3328..38d690a50b 100644
--- a/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java
+++ b/source/java/org/alfresco/opencmis/CMISNodeInfoImpl.java
@@ -303,8 +303,20 @@ public class CMISNodeInfoImpl implements CMISNodeInfo
{
objecVariant = CMISObjectVariant.CURRENT_VERSION;
}
+
+ // Is it un-versioned, or currently versioned?
+ Version currentVersion = connector.getVersionService().getCurrentVersion(nodeRef);
+ if (currentVersion != null)
+ {
+ versionLabel = currentVersion.getVersionLabel();
+ versionHistory = connector.getVersionService().getVersionHistory(nodeRef);
+ }
+ else
+ {
+ versionLabel = CMISConnector.UNVERSIONED_VERSION_LABEL;
+ }
+
objectId = getGuid(currentNodeId) + CMISConnector.ID_SEPERATOR + CMISConnector.UNVERSIONED_VERSION_LABEL;
- versionLabel = CMISConnector.UNVERSIONED_VERSION_LABEL;
currentObjectId = objectId;
hasPWC = (connector.getLockService().getLockType(nodeRef) == LockType.READ_ONLY_LOCK);
} else
diff --git a/source/java/org/alfresco/repo/action/ActionTestSuite.java b/source/java/org/alfresco/repo/action/ActionTestSuite.java
index e67e08da96..f2fdc2984f 100644
--- a/source/java/org/alfresco/repo/action/ActionTestSuite.java
+++ b/source/java/org/alfresco/repo/action/ActionTestSuite.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -18,9 +18,6 @@
*/
package org.alfresco.repo.action;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluatorTest;
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluatorTest;
import org.alfresco.repo.action.evaluator.HasAspectEvaluatorTest;
@@ -28,50 +25,48 @@ import org.alfresco.repo.action.evaluator.IsSubTypeEvaluatorTest;
import org.alfresco.repo.action.executer.AddFeaturesActionExecuterTest;
import org.alfresco.repo.action.executer.ContentMetadataEmbedderTest;
import org.alfresco.repo.action.executer.ContentMetadataExtracterTest;
+import org.alfresco.repo.action.executer.MailActionExecuterTest;
import org.alfresco.repo.action.executer.RemoveFeaturesActionExecuterTest;
import org.alfresco.repo.action.executer.SetPropertyValueActionExecuterTest;
import org.alfresco.repo.action.executer.SpecialiseTypeActionExecuterTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
/**
- * Version test suite
+ * Action test suite
*
* @author Roy Wetherall
+ * @author Alex Miller
*/
-public class ActionTestSuite extends TestSuite
+@RunWith(Suite.class)
+@SuiteClasses({
+ ParameterDefinitionImplTest.class,
+ ActionDefinitionImplTest.class,
+ ActionConditionDefinitionImplTest.class,
+ ActionImplTest.class,
+ ActionConditionImplTest.class,
+ CompositeActionImplTest.class,
+ ActionServiceImplTest.class,
+ CompositeActionConditionImplTest.class,
+
+ // Test evaluators
+ IsSubTypeEvaluatorTest.class,
+ ComparePropertyValueEvaluatorTest.class,
+ CompareMimeTypeEvaluatorTest.class,
+ HasAspectEvaluatorTest.class,
+
+ // Test executors
+ SetPropertyValueActionExecuterTest.class,
+ AddFeaturesActionExecuterTest.class,
+ ContentMetadataExtracterTest.class,
+ ContentMetadataEmbedderTest.class,
+ SpecialiseTypeActionExecuterTest.class,
+ RemoveFeaturesActionExecuterTest.class,
+ ActionTrackingServiceImplTest.class, // intermittent - pending ALF-9773 & ALF-9774
+ MailActionExecuterTest.class
+})
+public class ActionTestSuite
{
- /**
- * Creates the test suite
- *
- * @return the test suite
- */
- public static Test suite()
- {
- TestSuite suite = new TestSuite();
- suite.addTestSuite(ParameterDefinitionImplTest.class);
- suite.addTestSuite(ActionDefinitionImplTest.class);
- suite.addTestSuite(ActionConditionDefinitionImplTest.class);
- suite.addTestSuite(ActionImplTest.class);
- suite.addTestSuite(ActionConditionImplTest.class);
- suite.addTestSuite(CompositeActionImplTest.class);
- suite.addTestSuite(ActionServiceImplTest.class);
- suite.addTestSuite(CompositeActionConditionImplTest.class);
-
- // Test evaluators
- suite.addTestSuite(IsSubTypeEvaluatorTest.class);
- suite.addTestSuite(ComparePropertyValueEvaluatorTest.class);
- suite.addTestSuite(CompareMimeTypeEvaluatorTest.class);
- suite.addTestSuite(HasAspectEvaluatorTest.class);
-
- // Test executors
- suite.addTestSuite(SetPropertyValueActionExecuterTest.class);
- suite.addTestSuite(AddFeaturesActionExecuterTest.class);
- suite.addTestSuite(ContentMetadataExtracterTest.class);
- suite.addTestSuite(ContentMetadataEmbedderTest.class);
- suite.addTestSuite(SpecialiseTypeActionExecuterTest.class);
- suite.addTestSuite(RemoveFeaturesActionExecuterTest.class);
- suite.addTestSuite(ActionTrackingServiceImplTest.class);
-
- return suite;
- }
}
diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
index 76fc9d5f84..202eea48da 100644
--- a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
@@ -111,7 +111,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
/**
* The java mail sender
*/
- private JavaMailSender javaMailSender;
+ private JavaMailSender mailService;
/**
* The Template service
@@ -196,7 +196,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
*/
public void setMailService(JavaMailSender javaMailSender)
{
- this.javaMailSender = javaMailSender;
+ this.mailService = javaMailSender;
}
/**
@@ -243,7 +243,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
this.authorityService = authorityService;
}
-
+
/**
* @param nodeService the NodeService to set.
*/
@@ -251,7 +251,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
this.nodeService = nodeService;
}
-
+
/**
* @param tenantService the TenantService to set.
*/
@@ -259,7 +259,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
this.tenantService = tenantService;
}
-
+
/**
* @param headerEncoding The mail header encoding to set.
*/
@@ -267,7 +267,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
this.headerEncoding = headerEncoding;
}
-
+
/**
* @param fromAddress The default mail address.
*/
@@ -307,6 +307,12 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
this.sendTestMessage = sendTestMessage;
}
+ /**
+ * This stores an email address which, if it is set, overrides ALL email recipients sent from
+ * this class. It is intended for dev/test usage only !!
+ */
+ private String testModeRecipient;
+
/**
* Send a test message
*
@@ -334,11 +340,8 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
Action ruleAction = serviceRegistry.getActionService().createAction(NAME, params);
- // TODO review & test converged code (and remove comment below) !!
- prepareAndSendEmail(ruleAction, null);
-
- /*
- MimeMessageHelper message = prepareEmail(ruleAction, null);
+ MimeMessageHelper message = prepareEmail(ruleAction, null,
+ new Pair(testMessageTo, getLocaleForUser(testMessageTo)), getFrom(ruleAction));
try
{
mailService.send(message.getMimeMessage());
@@ -362,17 +365,10 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
Object[] args = {testMessageTo, txt.toString()};
throw new AlfrescoRuntimeException("email.outbound.err.send.failed", args, me);
}
- */
return true;
}
- /**
- * This stores an email address which, if it is set, overrides ALL email recipients sent from
- * this class. It is intended for dev/test usage only !!
- */
- private String testModeRecipient;
-
public void setTestModeRecipient(String testModeRecipient)
{
this.testModeRecipient = testModeRecipient;
@@ -503,8 +499,13 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
}
}
- private void prepareAndSendEmail(final Action ruleAction, final NodeRef actionedUponNodeRef, final Pair recipient, final Pair sender)
+ public MimeMessageHelper prepareEmail(final Action ruleAction , final NodeRef actionedUponNodeRef, final Pair recipient, final Pair sender)
{
+ // Create the mime mail message.
+ // Hack: using an array here to get around the fact that inner classes aren't closures.
+ // The MimeMessagePreparator.prepare() signature does not allow us to return a value and yet
+ // we can't set a result on a bare, non-final object reference due to Java language restrictions.
+ final MimeMessageHelper[] messageRef = new MimeMessageHelper[1];
MimeMessagePreparator mailPreparer = new MimeMessagePreparator()
{
@SuppressWarnings("unchecked")
@@ -515,7 +516,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
logger.debug(ruleAction.getParameterValues());
}
- MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
+ messageRef[0] = new MimeMessageHelper(mimeMessage);
// set header encoding if one has been supplied
if (headerEncoding != null && headerEncoding.length() != 0)
@@ -527,7 +528,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
String to = (String)ruleAction.getParameterValue(PARAM_TO);
if (to != null && to.length() != 0)
{
- message.setTo(to);
+ messageRef[0].setTo(to);
}
else
{
@@ -595,7 +596,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
if(recipients.size() > 0)
{
- message.setTo(recipients.toArray(new String[recipients.size()]));
+ messageRef[0].setTo(recipients.toArray(new String[recipients.size()]));
}
else
{
@@ -620,8 +621,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
// from is enabled
if (! authService.isCurrentUserTheSystemUser())
{
- String currentUserName = authService.getCurrentUserName();
- fromPerson = getPerson(currentUserName);
+ fromPerson = personService.getPerson(authService.getCurrentUserName());
}
if(isFromEnabled())
@@ -641,17 +641,17 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
try
{
- message.setFrom(from, fromPersonalName);
+ messageRef[0].setFrom(from, fromPersonalName);
}
catch (UnsupportedEncodingException error)
{
// Uses the JVM's default encoding, can never be unsupported. Just in case, revert to simple email
- message.setFrom(from);
+ messageRef[0].setFrom(from);
}
}
else
{
- message.setFrom(from);
+ messageRef[0].setFrom(from);
}
}
else
@@ -669,14 +669,15 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
logger.debug("looked up email address for :" + fromPerson + " email from " + fromActualUser);
}
- message.setFrom(fromActualUser);
+ messageRef[0].setFrom(fromActualUser);
}
else
{
// from system or user does not have email address
- message.setFrom(fromDefaultAddress);
+ messageRef[0].setFrom(fromDefaultAddress);
}
}
+
}
else
{
@@ -685,17 +686,20 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
logger.debug("from not enabled - sending from default address:" + fromDefaultAddress);
}
// from is not enabled.
- message.setFrom(fromDefaultAddress);
+ messageRef[0].setFrom(fromDefaultAddress);
}
+
+
+
// set subject line
- message.setSubject((String)ruleAction.getParameterValue(PARAM_SUBJECT));
+ messageRef[0].setSubject((String)ruleAction.getParameterValue(PARAM_SUBJECT));
if ((testModeRecipient != null) && (testModeRecipient.length() > 0) && (! testModeRecipient.equals("${dev.email.recipient.address}")))
{
// If we have an override for the email recipient, we'll send the email to that address instead.
// We'll prefix the subject with the original recipient, but leave the email message unchanged in every other way.
- message.setTo(testModeRecipient);
+ messageRef[0].setTo(testModeRecipient);
String emailRecipient = (String)ruleAction.getParameterValue(PARAM_TO);
if (emailRecipient == null)
@@ -709,9 +713,10 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
String recipientPrefixedSubject = "(" + emailRecipient + ") " + (String)ruleAction.getParameterValue(PARAM_SUBJECT);
- message.setSubject(recipientPrefixedSubject);
+ messageRef[0].setSubject(recipientPrefixedSubject);
}
+
// See if an email template has been specified
String text = null;
@@ -767,18 +772,18 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
// If we have an override for the email recipient, we'll send the email to that address instead.
// We'll prefix the subject with the original recipient, but leave the email message unchanged in every other way.
- message.setTo(testModeRecipient);
+ messageRef[0].setTo(testModeRecipient);
String emailRecipient = recipient.getFirst();
String recipientPrefixedSubject = "(" + emailRecipient + ") " + localizedSubject;
- message.setSubject(recipientPrefixedSubject);
+ messageRef[0].setSubject(recipientPrefixedSubject);
}
else
{
- message.setTo(recipient.getFirst());
- message.setSubject(localizedSubject);
+ messageRef[0].setTo(recipient.getFirst());
+ messageRef[0].setSubject(localizedSubject);
}
}
@@ -810,39 +815,50 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
isHTML = true;
}
}
-
+
if (text != null)
{
- message.setText(text, isHTML);
+ messageRef[0].setText(text, isHTML);
}
}
};
+ MimeMessage mimeMessage = mailService.createMimeMessage();
+ try
+ {
+ mailPreparer.prepare(mimeMessage);
+ } catch (Exception e)
+ {
+ // We're forced to catch java.lang.Exception here. Urgh.
+ if (logger.isInfoEnabled())
+ {
+ logger.warn("Unable to prepare mail message. Skipping.", e);
+ }
+ }
+
+ return messageRef[0];
+ }
+
+ private void prepareAndSendEmail(final Action ruleAction, final NodeRef actionedUponNodeRef, final Pair recipient, final Pair sender)
+ {
+ MimeMessageHelper preparedMessage = prepareEmail(ruleAction, actionedUponNodeRef, recipient, sender);
try
{
// Send the message unless we are in "testMode"
- if(!testMode)
+ if (!testMode)
{
- javaMailSender.send(mailPreparer);
+ mailService.send(preparedMessage.getMimeMessage());
+ onSend();
}
else
{
- try {
- MimeMessage mimeMessage = javaMailSender.createMimeMessage();
- mailPreparer.prepare(mimeMessage);
- lastTestMessage = mimeMessage;
- } catch(Exception e) {
- // We're forced to catch java.lang.Exception here. Urgh.
- if (logger.isInfoEnabled())
- {
- logger.warn("Unable to prepare mail message. Skipping.", e);
- }
- }
+ lastTestMessage = preparedMessage.getMimeMessage();
}
}
catch (MailException e)
{
+ onFail();
String to = (String)ruleAction.getParameterValue(PARAM_TO);
if (to == null)
{
@@ -860,7 +876,8 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
Boolean ignoreError = (Boolean)ruleAction.getParameterValue(PARAM_IGNORE_SEND_FAILURE);
if (ignoreError == null || ignoreError.booleanValue() == false)
{
- throw new AlfrescoRuntimeException("Failed to send email to:" + to, e);
+ Object[] args = {to, e.toString()};
+ throw new AlfrescoRuntimeException("email.outbound.err.send.failed", args, e);
}
}
}
@@ -1063,9 +1080,9 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
);
}
}
- return recipients;
- }
-
+ return recipients;
+ }
+
@SuppressWarnings("deprecation")
public boolean personExists(final String user)
{
@@ -1081,6 +1098,10 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
}
}, domain);
}
+ else
+ {
+ exists = personService.personExists(user);
+ }
return exists;
}
@@ -1099,6 +1120,10 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
}
}, domain);
}
+ else
+ {
+ person = personService.getPerson(user);
+ }
return person;
}
@@ -1113,26 +1138,35 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
public Locale doWork() throws Exception
{
- Locale locale = null;
- String localeString = (String)preferenceService.getPreference(user, "locale");
- if (localeString != null)
- {
- locale = StringUtils.parseLocaleString(localeString);
- }
- return locale;
+ return getLocaleForUserImpl(user);
}
}, domain);
}
+ else
+ {
+ return getLocaleForUserImpl(user);
+ }
+ return locale;
+ }
+
+ private Locale getLocaleForUserImpl(String user)
+ {
+ Locale locale = null;
+ String localeString = (String)preferenceService.getPreference(user, "locale");
+ if (localeString != null)
+ {
+ locale = StringUtils.parseLocaleString(localeString);
+ }
return locale;
}
private String getDomain(String user)
{
String[] parts = user.split("@");
- return parts.length == 1 ? "" : parts[1];
+ return parts.length == 1 ? "" : parts[1].toLowerCase(I18NUtil.getLocale());
}
-
- /**
+
+ /**
* Return true if address has valid format
* @param address
* @return
diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuterTest.java
index 49ac060822..0c02183e5a 100644
--- a/source/java/org/alfresco/repo/action/executer/MailActionExecuterTest.java
+++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuterTest.java
@@ -50,11 +50,11 @@ public class MailActionExecuterTest {
public static ApplicationContextInit APP_CONTEXT_INIT = new ApplicationContextInit();
// Rules to create 2 test users.
- public static AlfrescoPerson AUSTRALIAN_USER = new AlfrescoPerson(APP_CONTEXT_INIT, "EnglishUser");
- public static AlfrescoPerson BRITISH_USER = new AlfrescoPerson(APP_CONTEXT_INIT, "EnglishUser");
- public static AlfrescoPerson FRENCH_USER = new AlfrescoPerson(APP_CONTEXT_INIT, "FrenchUser");
- public static AlfrescoPerson UNKNOWN_USER1 = new AlfrescoPerson(APP_CONTEXT_INIT, "UnknownUser1");
- public static AlfrescoPerson UNKNOWN_USER2 = new AlfrescoPerson(APP_CONTEXT_INIT, "UnknowUser2");
+ public static AlfrescoPerson AUSTRALIAN_USER = new AlfrescoPerson(APP_CONTEXT_INIT, "AustralianUser@test.com");
+ public static AlfrescoPerson BRITISH_USER = new AlfrescoPerson(APP_CONTEXT_INIT, "EnglishUser@test.com");
+ public static AlfrescoPerson FRENCH_USER = new AlfrescoPerson(APP_CONTEXT_INIT, "FrenchUser@test.com");
+ public static AlfrescoPerson UNKNOWN_USER1 = new AlfrescoPerson(APP_CONTEXT_INIT, "UnknownUser1@test.com");
+ public static AlfrescoPerson UNKNOWN_USER2 = new AlfrescoPerson(APP_CONTEXT_INIT, "UnknowUser2@test.com");
// Tie them together in a static Rule Chain
@ClassRule public static RuleChain ruleChain = RuleChain.outerRule(APP_CONTEXT_INIT)
@@ -94,7 +94,7 @@ public class MailActionExecuterTest {
preferences.clear();
preferences.put("locale", "en_AU");
- PREFERENCE_SERVICE.setPreferences(BRITISH_USER.getUsername(), preferences);
+ PREFERENCE_SERVICE.setPreferences(AUSTRALIAN_USER.getUsername(), preferences);
}
@@ -161,7 +161,7 @@ public class MailActionExecuterTest {
MimeMessage message = ACTION_EXECUTER.retrieveLastTestMessage();
Assert.assertNotNull(message);
- Assert.assertEquals("G'Day Jan 1, 1970", (String)message.getContent());
+ Assert.assertEquals("G'Day 01/01/1970", (String)message.getContent());
}
}
diff --git a/source/java/org/alfresco/repo/activities/ActivityServiceImpl.java b/source/java/org/alfresco/repo/activities/ActivityServiceImpl.java
index 9dd0bd77f5..519cfb1076 100644
--- a/source/java/org/alfresco/repo/activities/ActivityServiceImpl.java
+++ b/source/java/org/alfresco/repo/activities/ActivityServiceImpl.java
@@ -320,6 +320,9 @@ public class ActivityServiceImpl implements ActivityService, InitializingBean
// is local to the method because we only want to cache per request - there is not point in keeping
// an instance cache because the data will become stale if a user changes their avatar.
Map userIdToAvatarNodeRefCache = new HashMap();
+
+ String currentTenantDomain = tenantService.getCurrentUserDomain();
+
if (logger.isDebugEnabled())
@@ -329,12 +332,9 @@ public class ActivityServiceImpl implements ActivityService, InitializingBean
+ maxFeedItems);
}
- String currentTenantDomain = tenantService.getCurrentUserDomain();
-
for (ActivityFeedEntity activityFeed : activityFeeds)
{
- if (actvityFilter != null && !actvityFilter.contains(activityFeed.getActivityType()))
- {
+ if (actvityFilter != null && !actvityFilter.contains(activityFeed.getActivityType())) {
if (logger.isTraceEnabled())
{
logger.trace("Filtering " + activityFeed.toString() + " \n by the activity filter.");
@@ -342,8 +342,7 @@ public class ActivityServiceImpl implements ActivityService, InitializingBean
continue;
}
- if (userFilter != null && !userFilter.contains(activityFeed.getPostUserId()))
- {
+ if (userFilter != null && !userFilter.contains(activityFeed.getPostUserId())) {
if (logger.isTraceEnabled())
{
logger.trace("Filtering " + activityFeed.toString() + " \n by the user filter.");
@@ -356,10 +355,6 @@ public class ActivityServiceImpl implements ActivityService, InitializingBean
// note: pending requirements for THOR-224, for now assume all activities are within context of site and filter by current tenant
if (! currentTenantDomain.equals(tenantService.getDomain(activityFeed.getSiteNetwork())))
{
- if (logger.isTraceEnabled())
- {
- logger.trace("Filtering " + activityFeed.toString() + " \n by the site/tenant filter.");
- }
continue;
}
}
@@ -392,7 +387,7 @@ public class ActivityServiceImpl implements ActivityService, InitializingBean
{
if (logger.isDebugEnabled())
{
- logger.debug("getUserFeedEntries: person no longer exists: "+postUserId);
+ logger.warn("getUserFeedEntries: person no longer exists: "+postUserId);
}
}
diff --git a/source/java/org/alfresco/repo/activities/feed/FeedNotifierImpl.java b/source/java/org/alfresco/repo/activities/feed/FeedNotifierImpl.java
index fe6a0a497c..e2d40f2705 100644
--- a/source/java/org/alfresco/repo/activities/feed/FeedNotifierImpl.java
+++ b/source/java/org/alfresco/repo/activities/feed/FeedNotifierImpl.java
@@ -38,6 +38,8 @@ import org.alfresco.repo.lock.JobLockService.JobLockRefreshCallback;
import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.repo.search.SearcherException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.tenant.TenantUtil;
+import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.admin.RepoAdminService;
@@ -330,6 +332,7 @@ public class FeedNotifierImpl implements FeedNotifier, ApplicationContextAware
try
{
final String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
+ final String tenantDomain = TenantUtil.getCurrentDomain();
// process the feeds using the batch processor {@link BatchProcessor}
BatchProcessor.BatchProcessWorker worker = new BatchProcessor.BatchProcessWorker()
@@ -355,14 +358,22 @@ public class FeedNotifierImpl implements FeedNotifier, ApplicationContextAware
final RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
txHelper.setMaxRetries(0);
- txHelper.doInTransaction(new RetryingTransactionCallback()
+ TenantUtil.runAsTenant(new TenantRunAsWork()
{
- public Void execute() throws Throwable
+ @Override
+ public Void doWork() throws Exception
{
- processInternal(person);
- return null;
+ txHelper.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ processInternal(person);
+ return null;
+ }
+ }, false, true);
+ return null;
}
- }, false, true);
+ }, tenantDomain);
}
private void processInternal(final PersonInfo person) throws Exception
diff --git a/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java b/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java
index 2ed215ad0d..2013e940ed 100644
--- a/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java
+++ b/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java
@@ -40,7 +40,6 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
-import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
diff --git a/source/java/org/alfresco/repo/cluster/HazelcastConfigFactoryBean.java b/source/java/org/alfresco/repo/cluster/HazelcastConfigFactoryBean.java
new file mode 100644
index 0000000000..405535583c
--- /dev/null
+++ b/source/java/org/alfresco/repo/cluster/HazelcastConfigFactoryBean.java
@@ -0,0 +1,172 @@
+/*
+ * 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.cluster;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.Resource;
+
+import com.hazelcast.config.Config;
+import com.hazelcast.config.InMemoryXmlConfig;
+
+/**
+ * FactoryBean used to create Hazelcast {@link Config} objects. A configuration file is supplied
+ * in the form of a Spring {@link Resource} and a set of {@link Properties} can also be provided. The
+ * XML file is processed so that property placeholders of the form ${property.name} are substitued for
+ * the corresponding property value before the XML is parsed into the Hazelcast configuration object.
+ *
+ * @author Matt Ward
+ */
+public class HazelcastConfigFactoryBean implements InitializingBean, FactoryBean
+{
+ private static final String PLACEHOLDER_END = "}";
+ private static final String PLACEHOLDER_START = "${";
+ private Resource configFile;
+ private Config config;
+ private Properties properties;
+
+
+ /**
+ * Set the Hazelcast XML configuration file to use. This will be merged with the supplied
+ * Properties and parsed to produce a final {@link Config} object.
+ * @param configFile the configFile to set
+ */
+ public void setConfigFile(Resource configFile)
+ {
+ this.configFile = configFile;
+ }
+
+ /**
+ * Used to supply the set of Properties that the configuration file can reference.
+ *
+ * @param properties the properties to set
+ */
+ public void setProperties(Properties properties)
+ {
+ this.properties = properties;
+ }
+
+ /**
+ * Spring {@link InitializingBean} lifecycle method. Substitutes property placeholders for their
+ * corresponding values and creates a {@link Config Hazelcast configuration} with the post-processed
+ * XML file - ready for the {@link #getObject()} factory method to be used to retrieve it.
+ */
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ if (configFile == null)
+ {
+ throw new IllegalArgumentException("No configuration file specified.");
+ }
+ if (properties == null)
+ {
+ properties = new Properties();
+ }
+
+ // These configXML strings will be large and are therefore intended
+ // to be thrown away. We only want to keep the final Config object.
+ String rawConfigXML = getConfigFileContents();
+ String configXML = substituteProperties(rawConfigXML);
+ config = new InMemoryXmlConfig(configXML);
+ }
+
+ /**
+ * For the method parameter text, replaces all occurrences of placeholders having
+ * the form ${property.name} with the value of the property having the key "property.name". The
+ * properties are supplied using {@link #setProperties(Properties)}.
+ *
+ * @param text The String to apply property substitutions to.
+ * @return String after substitutions have been applied.
+ */
+ private String substituteProperties(String text)
+ {
+ for (String propName : properties.stringPropertyNames())
+ {
+ String propValue = properties.getProperty(propName);
+ String quotedPropName = Pattern.quote(PLACEHOLDER_START + propName + PLACEHOLDER_END);
+ text = text.replaceAll(quotedPropName, propValue);
+ }
+
+ return text;
+ }
+
+ /**
+ * Opens the configFile {@link Resource} and reads the contents into a String.
+ *
+ * @return the contents of the configFile resource.
+ */
+ private String getConfigFileContents()
+ {
+ StringWriter writer = new StringWriter();
+ InputStream inputStream = null;
+ try
+ {
+ inputStream = configFile.getInputStream();
+ IOUtils.copy(inputStream, writer, "UTF-8");
+ return writer.toString();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Couldn't read configuration: " + configFile, e);
+ }
+ finally
+ {
+ try
+ {
+ if (inputStream != null)
+ {
+ inputStream.close();
+ }
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Couldn't close stream", e);
+ }
+ }
+ }
+
+ /**
+ * FactoryBean's factory method. Returns the config with the property key/value
+ * substitutions in place.
+ */
+ @Override
+ public Config getObject() throws Exception
+ {
+ return config;
+ }
+
+ @Override
+ public Class> getObjectType()
+ {
+ return Config.class;
+ }
+
+ @Override
+ public boolean isSingleton()
+ {
+ return true;
+ }
+}
diff --git a/source/java/org/alfresco/repo/cluster/HazelcastConfigFactoryBeanTest.java b/source/java/org/alfresco/repo/cluster/HazelcastConfigFactoryBeanTest.java
new file mode 100644
index 0000000000..5a897852cf
--- /dev/null
+++ b/source/java/org/alfresco/repo/cluster/HazelcastConfigFactoryBeanTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.cluster;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Properties;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import com.hazelcast.config.Config;
+
+/**
+ * Tests for the HazelcastConfigFactoryBean class.
+ *
+ * @author Matt Ward
+ */
+public class HazelcastConfigFactoryBeanTest
+{
+ private HazelcastConfigFactoryBean configFactory;
+ private Resource resource;
+ private Properties properties;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ configFactory = new HazelcastConfigFactoryBean();
+ resource = new ClassPathResource("cluster-test/placeholder-test.xml");
+ configFactory.setConfigFile(resource);
+
+ properties = new Properties();
+ properties.setProperty("alfresco.hazelcast.password", "let-me-in");
+ properties.setProperty("alfresco.cluster.name", "cluster-name");
+ configFactory.setProperties(properties);
+
+ // Trigger the spring post-bean creation lifecycle method
+ configFactory.afterPropertiesSet();
+ }
+
+
+ @Test
+ public void testConfigHasNewPropertyValues() throws Exception
+ {
+ // Invoke the factory method.
+ Config config = configFactory.getObject();
+
+ assertEquals("let-me-in", config.getGroupConfig().getPassword());
+ assertEquals("cluster-name", config.getGroupConfig().getName());
+ }
+}
diff --git a/source/java/org/alfresco/repo/cluster/HazelcastInstanceFactory.java b/source/java/org/alfresco/repo/cluster/HazelcastInstanceFactory.java
new file mode 100644
index 0000000000..92652f389c
--- /dev/null
+++ b/source/java/org/alfresco/repo/cluster/HazelcastInstanceFactory.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2005-2013 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.cluster;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.alfresco.util.PropertyCheck;
+
+import com.hazelcast.config.Config;
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+
+/**
+ * Provides a way of lazily creating HazelcastInstances for a given configuration.
+ * The HazelcastInstance will not be created until {@link #getInstance()} is called.
+ *
+ * An intermediary class such as this is required in order to avoid starting
+ * Hazelcast instances when clustering is not configured/required. Otherwise
+ * simply by defining a HazelcastInstance bean clustering would spring into life.
+ *
+ * Please note this class provides non-static access deliberately, and should be
+ * injected into any clients that require its services.
+ *
+ * @author Matt Ward
+ */
+public class HazelcastInstanceFactory
+{
+ private Config config;
+ private HazelcastInstance hazelcastInstance;
+ /** Guards {@link #config} and {@link #hazelcastInstance} */
+ private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
+
+ public HazelcastInstance getInstance()
+ {
+ rwLock.readLock().lock();
+ try
+ {
+ if (hazelcastInstance != null)
+ {
+ return hazelcastInstance;
+ }
+ }
+ finally
+ {
+ rwLock.readLock().unlock();
+ }
+
+ // hazelcastInstance is null, so create it.
+ rwLock.writeLock().lock();
+ try
+ {
+ // Double check condition hasn't changed in between locks.
+ if (hazelcastInstance == null)
+ {
+ hazelcastInstance = Hazelcast.newHazelcastInstance(config);
+ }
+ return hazelcastInstance;
+ }
+ finally
+ {
+ rwLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Checks whether hazelcast has been given a valid cluster name. If so,
+ * then clustering is considered enabled. This condition should be checked
+ * before calling {@link #getInstance()}.
+ *
+ * @return true if clustering is enabled, false otherwise.
+ */
+ public boolean isClusteringEnabled()
+ {
+ rwLock.readLock().lock();
+ try
+ {
+ String clusterName = config.getGroupConfig().getName();
+ return (PropertyCheck.isValidPropertyString(clusterName));
+ }
+ finally
+ {
+ rwLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Retrieve the name of the cluster for the configuration used by this factory.
+ *
+ * @return String - the cluster name.
+ */
+ public String getClusterName()
+ {
+ rwLock.readLock().lock();
+ try
+ {
+ String clusterName = config.getGroupConfig().getName();
+ return clusterName;
+ }
+ finally
+ {
+ rwLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Sets the Hazelcast configuration that will be used by this factory when
+ * creating the HazelcastInstance.
+ *
+ * @param config Hazelcast configuration
+ */
+ public void setConfig(Config config)
+ {
+ rwLock.writeLock().lock();
+ try
+ {
+ this.config = config;
+ }
+ finally
+ {
+ rwLock.writeLock().unlock();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/importer/ImporterComponent.java b/source/java/org/alfresco/repo/importer/ImporterComponent.java
index a3cba3d057..88a7edb45f 100644
--- a/source/java/org/alfresco/repo/importer/ImporterComponent.java
+++ b/source/java/org/alfresco/repo/importer/ImporterComponent.java
@@ -775,6 +775,12 @@ public class ImporterComponent implements ImporterService
String contentUrl = contentData.getContentUrl();
if (contentUrl != null && contentUrl.length() > 0)
{
+ Map propsBefore = null;
+ if (contentUsageImpl != null && contentUsageImpl.getEnabled())
+ {
+ propsBefore = nodeService.getProperties(nodeRef);
+ }
+
if (contentCache != null)
{
// import content from source
@@ -783,27 +789,20 @@ public class ImporterComponent implements ImporterService
}
else
{
- // import the content from the url
+ // import the content from the import source file
InputStream contentStream = streamHandler.importStream(contentUrl);
ContentWriter writer = contentService.getWriter(nodeRef, propertyName, true);
writer.setEncoding(contentData.getEncoding());
writer.setMimetype(contentData.getMimetype());
-
- Map propsBefore = null;
- if (contentUsageImpl != null && contentUsageImpl.getEnabled())
- {
- propsBefore = nodeService.getProperties(nodeRef);
- }
-
writer.putContent(contentStream);
-
- if (contentUsageImpl != null && contentUsageImpl.getEnabled())
- {
- // Since behaviours for content nodes have all been disabled,
- // it is necessary to update the user's usage stats.
- Map propsAfter = nodeService.getProperties(nodeRef);
- contentUsageImpl.onUpdateProperties(nodeRef, propsBefore, propsAfter);
- }
+ }
+
+ if (contentUsageImpl != null && contentUsageImpl.getEnabled())
+ {
+ // Since behaviours for content nodes have all been disabled,
+ // it is necessary to update the user's usage stats.
+ Map propsAfter = nodeService.getProperties(nodeRef);
+ contentUsageImpl.onUpdateProperties(nodeRef, propsBefore, propsAfter);
}
reportContentCreated(nodeRef, contentUrl);
diff --git a/source/java/org/alfresco/repo/mail/AlfrescoJavaMailSender.java b/source/java/org/alfresco/repo/mail/AlfrescoJavaMailSender.java
index 074f47bf56..9857e4c222 100644
--- a/source/java/org/alfresco/repo/mail/AlfrescoJavaMailSender.java
+++ b/source/java/org/alfresco/repo/mail/AlfrescoJavaMailSender.java
@@ -25,7 +25,6 @@ import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.URLName;
-import javax.mail.event.ConnectionListener;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
diff --git a/source/java/org/alfresco/repo/model/Repository.java b/source/java/org/alfresco/repo/model/Repository.java
index eeb0b6adee..aefce2ce89 100644
--- a/source/java/org/alfresco/repo/model/Repository.java
+++ b/source/java/org/alfresco/repo/model/Repository.java
@@ -181,6 +181,7 @@ public class Repository implements ApplicationContextAware
@Override
protected void onShutdown(ApplicationEvent event)
{
+ //NOOP
}
}
@@ -204,7 +205,7 @@ public class Repository implements ApplicationContextAware
}
/**
- * Gets the Company Home
+ * Gets the Company Home. Note this is tenant-aware if the correct Cache is supplied.
*
* @return company home node ref
*/
diff --git a/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java b/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java
index ff18920a17..920c4ee302 100644
--- a/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java
+++ b/source/java/org/alfresco/repo/rendition/RenditionServiceIntegrationTest.java
@@ -203,9 +203,8 @@ public class RenditionServiceIntegrationTest extends BaseAlfrescoSpringTest
nodeService.deleteNode(nodeWithFreeMarkerContent);
nodeService.deleteNode(testTargetFolder);
}
-
- //TODO Fix this failing test.
- public void off_testRenderFreeMarkerTemplate() throws Exception
+
+ public void testRenderFreeMarkerTemplate() throws Exception
{
this.setComplete();
this.endTransaction();
diff --git a/source/java/org/alfresco/repo/security/person/GetPeopleCannedQuery.java b/source/java/org/alfresco/repo/security/person/GetPeopleCannedQuery.java
index 00d2598dd5..f53c9f338d 100644
--- a/source/java/org/alfresco/repo/security/person/GetPeopleCannedQuery.java
+++ b/source/java/org/alfresco/repo/security/person/GetPeopleCannedQuery.java
@@ -63,6 +63,8 @@ public class GetPeopleCannedQuery extends AbstractCannedQuery
public static final int MAX_FILTER_SORT_PROPS = 3;
+ private static final int MAX_EXPECTED_ADMINS = 5; // TODO refine non-admin paging
+
private NodeDAO nodeDAO;
private QNameDAO qnameDAO;
private CannedQueryDAO cannedQueryDAO;
@@ -190,26 +192,35 @@ public class GetPeopleCannedQuery extends AbstractCannedQuery
filterSortPropCnt = setFilterSortParams(sortFilterProps, sortAsc, params);
// filtered and/or sorted - note: permissions not applicable for getPeople
- final List result = new ArrayList(100);
+ List result = new ArrayList(100);
final PersonQueryCallback c = new DefaultPersonQueryCallback(result, paramBean.getIncludeAdministrators());
PersonResultHandler resultHandler = new PersonResultHandler(c);
int offset = parameters.getPageDetails().getSkipResults();
int totalResultCountMax = parameters.getTotalResultCountMax();
- int limit = totalResultCountMax > 0 ? totalResultCountMax : parameters.getPageDetails().getPageSize();
- if (limit != Integer.MAX_VALUE)
+
+ int origOffset = offset;
+ int origLimit = totalResultCountMax > 0 ? totalResultCountMax : parameters.getPageDetails().getPageSize();
+
+ long newLimit = (long)origLimit;
+
+ // to enable hasMore flag
+ newLimit++;
+
+ boolean excludeAdmins = (! paramBean.getIncludeAdministrators());
+ if (excludeAdmins)
{
- // to enable hasMore flag
- limit++;
-
- if ((! paramBean.getIncludeAdministrators()) && (limit != Integer.MAX_VALUE))
- {
- // TODO - only works in case where there is only 1 default admin
- limit++;
- }
+ // TODO refine - non-admin paging
+ offset = 0;
+ newLimit = offset + (long)newLimit + MAX_EXPECTED_ADMINS;
}
- cannedQueryDAO.executeQuery(QUERY_NAMESPACE, QUERY_SELECT_GET_PEOPLE, params, offset, limit, resultHandler);
+ if (newLimit > Integer.MAX_VALUE)
+ {
+ newLimit = Integer.MAX_VALUE;
+ }
+
+ cannedQueryDAO.executeQuery(QUERY_NAMESPACE, QUERY_SELECT_GET_PEOPLE, params, offset, (int)newLimit, resultHandler);
resultHandler.done();
if (start != null)
@@ -217,6 +228,17 @@ public class GetPeopleCannedQuery extends AbstractCannedQuery
logger.debug("Base query: "+result.size()+" in "+(System.currentTimeMillis()-start)+" msecs");
}
+ if (excludeAdmins)
+ {
+ // TODO refine - non-admin paging
+ long max = origOffset + (long)origLimit;
+ if (max > result.size())
+ {
+ max = result.size();
+ }
+ result = result.subList(origOffset, (int)max);
+ }
+
return result;
}
@@ -296,7 +318,9 @@ public class GetPeopleCannedQuery extends AbstractCannedQuery
@Override
protected Pair getTotalResultCount(List results)
{
- return super.getTotalResultCount(results);
+ int offset = super.getParameters().getPageDetails().getSkipResults();
+ Integer size = offset + results.size();
+ return new Pair(size, size);
}
protected interface PersonQueryCallback
@@ -318,9 +342,7 @@ public class GetPeopleCannedQuery extends AbstractCannedQuery
@Override
public boolean handle(NodeRef personRef)
{
- // TODO refine
- // - return username as part of query
- // - can break paging if more than one admin
+ // TODO refine - return username as part of query
if (includeAdministrators == false)
{
String userName = (String) nodeService.getProperty(personRef, ContentModel.PROP_USERNAME);
diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
index ea129f18de..db502a7dea 100644
--- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
@@ -430,14 +430,6 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
return getPerson(userName, true);
}
- /**
- * {@inheritDoc}
- */
- public NodeRef getPersonOrNull(String userName)
- {
- return getPersonImpl(userName, false, false);
- }
-
/**
* {@inheritDoc}
*/
@@ -453,9 +445,8 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
throw new NoSuchPersonException(personRef.toString());
}
- // belts-and-braces
String username = (String)props.get(ContentModel.PROP_USERNAME);
- if (getPersonOrNull(username) == null)
+ if (username == null)
{
throw new NoSuchPersonException(personRef.toString());
}
@@ -466,6 +457,14 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
(String)props.get(ContentModel.PROP_LASTNAME));
}
+ /**
+ * {@inheritDoc}
+ */
+ public NodeRef getPersonOrNull(String userName)
+ {
+ return getPersonImpl(userName, false, false);
+ }
+
/**
* {@inheritDoc}
*/
@@ -474,6 +473,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
return getPersonImpl(userName, autoCreateHomeFolderAndMissingPersonIfAllowed, true);
}
+
private NodeRef getPersonImpl(
final String userName,
final boolean autoCreateHomeFolderAndMissingPersonIfAllowed,
@@ -513,7 +513,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
*/
public boolean personExists(String caseSensitiveUserName)
{
- NodeRef person = getPersonOrNull(caseSensitiveUserName);
+ NodeRef person = getPersonOrNullImpl(caseSensitiveUserName);
if (person != null)
{
// re: THOR-293
diff --git a/source/java/org/alfresco/repo/security/person/PersonTest.java b/source/java/org/alfresco/repo/security/person/PersonTest.java
index eec7733fc9..23a5c81e35 100644
--- a/source/java/org/alfresco/repo/security/person/PersonTest.java
+++ b/source/java/org/alfresco/repo/security/person/PersonTest.java
@@ -636,9 +636,10 @@ public class PersonTest extends TestCase
NodeRef p6 = personService.createPerson(createDefaultProperties("bb", "Bb", "Bb", "bb@bb", "alfresco", rootNodeRef));
NodeRef p7 = personService.createPerson(createDefaultProperties("dd", "Dd", "Dd", "dd@dd", "alfresco", rootNodeRef));
+ int expectedTotalCount = 7;
+ assertEquals(expectedTotalCount, getPeopleCount());
-
- assertEquals(7, getPeopleCount());
+ Pair expectedResultCount = new Pair(expectedTotalCount,expectedTotalCount);
List> sort = new ArrayList>(1);
sort.add(new Pair(ContentModel.PROP_USERNAME, true));
@@ -651,13 +652,16 @@ public class PersonTest extends TestCase
assertEquals(p3, results.get(0).getNodeRef());
assertEquals(p1, results.get(1).getNodeRef());
- // page 2
+ // page 2 (with total count)
pr = new PagingRequest(2, 2, null);
+ pr.setRequestTotalCountMax(Integer.MAX_VALUE);
+
ppr = personService.getPeople(null, true, sort, pr);
results = ppr.getPage();
assertEquals(2, results.size());
assertEquals(p6, results.get(0).getNodeRef());
assertEquals(p4, results.get(1).getNodeRef());
+ assertEquals(expectedResultCount, ppr.getTotalResultCount());
// page 3
pr = new PagingRequest(4, 2, null);
@@ -667,12 +671,76 @@ public class PersonTest extends TestCase
assertEquals(p7, results.get(0).getNodeRef());
assertEquals(p2, results.get(1).getNodeRef());
- // page 4
+ // page 4 (with total count)
pr = new PagingRequest(6, 2, null);
+ pr.setRequestTotalCountMax(Integer.MAX_VALUE);
+
ppr = personService.getPeople(null, true, sort, pr);
results = ppr.getPage();
assertEquals(1, results.size());
assertEquals(p5, results.get(0).getNodeRef());
+ assertEquals(expectedResultCount, ppr.getTotalResultCount());
+ }
+
+ public void testPeopleSortingPaging_NoAdmin()
+ {
+ personService.setCreateMissingPeople(false);
+
+ assertEquals(2, getPeopleCount());
+
+ NodeRef p1 = personService.getPerson(AuthenticationUtil.getAdminUserName()); // admin - by default
+ NodeRef p2 = personService.getPerson(AuthenticationUtil.getGuestUserName()); // guest - by default
+
+ NodeRef p3 = personService.createPerson(createDefaultProperties("aa", "Aa", "Aa", "aa@aa", "alfresco", rootNodeRef));
+ NodeRef p4 = personService.createPerson(createDefaultProperties("cc", "Cc", "Cc", "cc@cc", "alfresco", rootNodeRef));
+ NodeRef p5 = personService.createPerson(createDefaultProperties("hh", "Hh", "Hh", "hh@hh", "alfresco", rootNodeRef));
+ NodeRef p6 = personService.createPerson(createDefaultProperties("bb", "Bb", "Bb", "bb@bb", "alfresco", rootNodeRef));
+ NodeRef p7 = personService.createPerson(createDefaultProperties("dd", "Dd", "Dd", "dd@dd", "alfresco", rootNodeRef));
+
+ int expectedTotalCount = 7;
+ assertEquals(expectedTotalCount, getPeopleCount());
+
+ int expectedTotalCountWithAdmin = expectedTotalCount - 1;
+ Pair expectedResultCount = new Pair(expectedTotalCountWithAdmin,expectedTotalCountWithAdmin);
+
+ List> sort = new ArrayList>(1);
+ sort.add(new Pair(ContentModel.PROP_USERNAME, true));
+
+ // page 1
+ PagingRequest pr = new PagingRequest(0, 2, null);
+ PagingResults ppr = personService.getPeople(null, null, null, null, false, sort, pr);
+ List results = ppr.getPage();
+ assertEquals(2, results.size());
+ assertEquals(p3, results.get(0).getNodeRef());
+ assertEquals(p6, results.get(1).getNodeRef());
+
+ // page 2 (with total count)
+ pr = new PagingRequest(2, 2, null);
+ pr.setRequestTotalCountMax(Integer.MAX_VALUE);
+
+ ppr = personService.getPeople(null, null, null, null, false, sort, pr);
+ results = ppr.getPage();
+ assertEquals(2, results.size());
+ assertEquals(p4, results.get(0).getNodeRef());
+ assertEquals(p7, results.get(1).getNodeRef());
+ assertEquals(expectedResultCount, ppr.getTotalResultCount());
+
+ // page 3
+ pr = new PagingRequest(4, 2, null);
+ ppr = personService.getPeople(null, null, null, null, false, sort, pr);
+ results = ppr.getPage();
+ assertEquals(2, results.size());
+ assertEquals(p2, results.get(0).getNodeRef());
+ assertEquals(p5, results.get(1).getNodeRef());
+
+ // page 4 (with total count)
+ pr = new PagingRequest(6, 2, null);
+ pr.setRequestTotalCountMax(Integer.MAX_VALUE);
+
+ ppr = personService.getPeople(null, null, null, null, false, sort, pr);
+ results = ppr.getPage();
+ assertEquals(0, results.size());
+ assertEquals(expectedResultCount, ppr.getTotalResultCount());
}
// note: this test can be removed as and when we remove the deprecated "getPeople" impl
diff --git a/source/java/org/alfresco/repo/security/person/TestPersonManager.java b/source/java/org/alfresco/repo/security/person/TestPersonManager.java
index c9699a3a86..c4256c478c 100644
--- a/source/java/org/alfresco/repo/security/person/TestPersonManager.java
+++ b/source/java/org/alfresco/repo/security/person/TestPersonManager.java
@@ -78,6 +78,15 @@ public class TestPersonManager
}
private NodeRef makePersonNode(String userName)
+ {
+ PropertyMap personProps = makePersonProperties(userName);
+
+ NodeRef person = personService.createPerson(personProps);
+ people.put(userName, person);
+ return person;
+ }
+
+ public static PropertyMap makePersonProperties(String userName)
{
PropertyMap personProps = new PropertyMap();
personProps.put(ContentModel.PROP_USERNAME, userName);
@@ -86,10 +95,7 @@ public class TestPersonManager
personProps.put(ContentModel.PROP_EMAIL, userName+EMAIL_SUFFIX);
personProps.put(ContentModel.PROP_JOBTITLE, userName+JOB_SUFFIX);
personProps.put(ContentModel.PROP_JOBTITLE, userName+ORGANISATION_SUFFIX);
-
- NodeRef person = personService.createPerson(personProps);
- people.put(userName, person);
- return person;
+ return personProps;
}
public NodeRef get(String userName)
diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java
index 179f4ac776..aa87b9f98b 100644
--- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java
+++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java
@@ -118,7 +118,7 @@ import org.springframework.extensions.surf.util.ParameterCheck;
public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServiceInternal, SiteModel, NodeServicePolicies.OnRestoreNodePolicy
{
/** Logger */
- private static Log logger = LogFactory.getLog(SiteServiceImpl.class);
+ protected static Log logger = LogFactory.getLog(SiteServiceImpl.class);
/** The DM store where site's are kept */
public static final StoreRef SITE_STORE = new StoreRef("workspace://SpacesStore");
@@ -938,8 +938,11 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic
*/
public List listSites(final String userName, final int size)
{
- // MT share - for activity service system callback
- if (tenantService.isEnabled() && (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) && tenantService.isTenantUser(userName))
+ // MT share - for activity service remote system callback (deprecated)
+ if (tenantService.isEnabled() &&
+ TenantUtil.isCurrentDomainDefault() &&
+ (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) &&
+ tenantService.isTenantUser(userName))
{
final String tenantDomain = tenantService.getUserDomain(userName);
@@ -1177,8 +1180,11 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic
*/
public SiteInfo getSite(final String shortName)
{
- // MT share - for activity service system callback
- if (tenantService.isEnabled() && (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) && tenantService.isTenantName(shortName))
+ // MT share - for activity service remote system callback (deprecated)
+ if (tenantService.isEnabled() &&
+ TenantUtil.isCurrentDomainDefault() &&
+ (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) &&
+ tenantService.isTenantName(shortName))
{
final String tenantDomain = tenantService.getDomain(shortName);
final String sName = tenantService.getBaseName(shortName, true);
@@ -1715,8 +1721,11 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic
public Map listMembers(String shortName, final String nameFilter, final String roleFilter, final int size, final boolean collapseGroups)
{
- // MT share - for activity service system callback
- if (tenantService.isEnabled() && (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) && tenantService.isTenantName(shortName))
+ // MT share - for activity service remote system callback (deprecated)
+ if (tenantService.isEnabled() &&
+ TenantUtil.isCurrentDomainDefault() &&
+ (AuthenticationUtil.SYSTEM_USER_NAME.equals(AuthenticationUtil.getRunAsUser())) &&
+ tenantService.isTenantName(shortName))
{
final String tenantDomain = tenantService.getDomain(shortName);
final String sName = tenantService.getBaseName(shortName, true);
diff --git a/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java b/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java
index 30c342e7ce..c43b952a68 100644
--- a/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java
+++ b/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java
@@ -579,10 +579,13 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
tenantDeployer.onEnableTenant();
}
- // bootstrap workflows
- for (WorkflowDeployer workflowDeployer : workflowDeployers)
+ // bootstrap workflows, if needed
+ if(workflowService.isMultiTenantWorkflowDeploymentEnabled())
{
- workflowDeployer.init();
+ for (WorkflowDeployer workflowDeployer : workflowDeployers)
+ {
+ workflowDeployer.init();
+ }
}
// bootstrap modules (if any)
@@ -773,14 +776,17 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo
{
public Object doWork()
{
- List workflowDefs = workflowService.getDefinitions();
- if (workflowDefs != null)
- {
- for (WorkflowDefinition workflowDef : workflowDefs)
- {
- workflowService.undeployDefinition(workflowDef.getId());
- }
- }
+ // Only undeploy tenant-workflows when MT-workflow deployment is enabled
+ if(workflowService.isMultiTenantWorkflowDeploymentEnabled()) {
+ List workflowDefs = workflowService.getDefinitions();
+ if (workflowDefs != null)
+ {
+ for (WorkflowDefinition workflowDef : workflowDefs)
+ {
+ workflowService.undeployDefinition(workflowDef.getId());
+ }
+ }
+ }
List messageResourceBundles = repoAdminService.getMessageBundles();
if (messageResourceBundles != null)
diff --git a/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java b/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java
index 246dc96243..03664211ec 100644
--- a/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java
+++ b/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java
@@ -222,7 +222,7 @@ public class MultiTDemoTest extends TestCase
private void createTenant(final String tenantDomain)
{
// create tenants (if not already created)
- TenantUtil.runAsPrimaryTenant(new TenantRunAsWork