diff --git a/config/alfresco/activiti-context.xml b/config/alfresco/activiti-context.xml
index 22686656ec..82398e88c7 100644
--- a/config/alfresco/activiti-context.xml
+++ b/config/alfresco/activiti-context.xml
@@ -64,6 +64,8 @@
+
+
diff --git a/config/alfresco/comment-services-context.xml b/config/alfresco/comment-services-context.xml
index 33977de89a..ffaf07b707 100644
--- a/config/alfresco/comment-services-context.xml
+++ b/config/alfresco/comment-services-context.xml
@@ -2,6 +2,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/model/bpmModel.xml b/config/alfresco/model/bpmModel.xml
index 78cb147d52..bef305f030 100644
--- a/config/alfresco/model/bpmModel.xml
+++ b/config/alfresco/model/bpmModel.xml
@@ -260,7 +260,7 @@
bpm:workflowPackage
- true
+ false
false
diff --git a/config/alfresco/opencmis-context.xml b/config/alfresco/opencmis-context.xml
index aab15f62bb..ff9c5d1dae 100644
--- a/config/alfresco/opencmis-context.xml
+++ b/config/alfresco/opencmis-context.xml
@@ -2,7 +2,6 @@
-
@@ -79,7 +78,10 @@
-
+
+
+
+
@@ -111,6 +113,7 @@
+
@@ -152,5 +155,5 @@
-
+
\ No newline at end of file
diff --git a/config/alfresco/preference-service-context.xml b/config/alfresco/preference-service-context.xml
index abdff02770..ea255b4ae3 100644
--- a/config/alfresco/preference-service-context.xml
+++ b/config/alfresco/preference-service-context.xml
@@ -44,6 +44,7 @@
+
diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml
index 8ae53c972d..37b62593c2 100644
--- a/config/alfresco/public-services-security-context.xml
+++ b/config/alfresco/public-services-security-context.xml
@@ -968,8 +968,10 @@
org.alfresco.service.cmr.site.SiteService.deleteSite=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.findSites=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.service.cmr.site.SiteService.getContainer=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
+ org.alfresco.service.cmr.site.SiteService.listContainers=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.service.cmr.site.SiteService.getMembersRole=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.getMembersRoleInfo=ACL_ALLOW
+ org.alfresco.service.cmr.site.SiteService.resolveSite=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.getSite=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.service.cmr.site.SiteService.getSiteGroup=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.getSiteRoleGroup=ACL_ALLOW
@@ -980,8 +982,11 @@
org.alfresco.service.cmr.site.SiteService.isMember=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.listMembers=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.listMembersInfo=ACL_ALLOW
+ org.alfresco.service.cmr.site.SiteService.listMembersPaged=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.listSites=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
+ org.alfresco.service.cmr.site.SiteService.listSitesPaged=ACL_ALLOW,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.service.cmr.site.SiteService.removeMembership=ACL_ALLOW
+ org.alfresco.service.cmr.site.SiteService.canAddMember=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.setMembership=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.updateSite=ACL_ALLOW
org.alfresco.service.cmr.site.SiteService.*=ACL_DENY
diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties
index 4c571b0117..18904ea076 100644
--- a/config/alfresco/repository.properties
+++ b/config/alfresco/repository.properties
@@ -71,6 +71,7 @@ system.workflow.engine.jbpm.enabled=true
# Determines if the Activiti engine is enabled
system.workflow.engine.activiti.enabled=true
+system.workflow.engine.activiti.idblocksize=100
# The maximum number of groups to check for pooled tasks. For performance
# reasons, this is limited to 100 by default.
@@ -874,7 +875,7 @@ solr.solrUser=solr
solr.solrPassword=solr
# none, https
solr.secureComms=https
-
+solr.cmis.alternativeDictionary=DEFAULT_DICTIONARY
solr.max.total.connections=40
solr.max.host.connections=40
@@ -1020,3 +1021,19 @@ trashcan.MaxSize=1000
#
authority.useBridgeTable=true
+# Oubound Mail
+mail.service.corePoolSize=8
+mail.service.maximumPoolSize=20
+
+# OpenCMIS
+
+# URL generation overrides
+
+# if true, the context path of OpenCMIS generated urls will be set to "opencmis.context.value", otherwise it will be taken from the request url
+opencmis.context.override=false
+opencmis.context.value=
+# if true, the servlet path of OpenCMIS generated urls will be set to "opencmis.servletpath.value", otherwise it will be taken from the request url
+opencmis.servletpath.override=false
+opencmis.servletpath.value=
+opencmis.server.override=false
+opencmis.server.value=
\ No newline at end of file
diff --git a/config/alfresco/site-services-context.xml b/config/alfresco/site-services-context.xml
index c5d0751f00..f46e42608d 100644
--- a/config/alfresco/site-services-context.xml
+++ b/config/alfresco/site-services-context.xml
@@ -21,7 +21,7 @@
-
+
@@ -33,6 +33,7 @@
hasCreateSitePermissions
findSites
listSites
+ listSitesPaged
getSite
listMembers
listMembersInfo
@@ -44,6 +45,11 @@
getSiteGroup
getSiteRoleGroup
getSiteRoot
+ canAddMember
+ listContainers
+ isFavouriteSite
+ getFavouriteSites
+ addFavouriteSite
@@ -130,7 +136,32 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -184,4 +215,5 @@
+
diff --git a/config/alfresco/subsystems/Search/solr/solr-search-context.xml b/config/alfresco/subsystems/Search/solr/solr-search-context.xml
index f6f22a322a..3f967f93da 100644
--- a/config/alfresco/subsystems/Search/solr/solr-search-context.xml
+++ b/config/alfresco/subsystems/Search/solr/solr-search-context.xml
@@ -36,6 +36,7 @@
+
diff --git a/config/alfresco/subsystems/email/OutboundSMTP/outboundSMTP-context.xml b/config/alfresco/subsystems/email/OutboundSMTP/outboundSMTP-context.xml
index e6faa1b2f8..ead56c780b 100755
--- a/config/alfresco/subsystems/email/OutboundSMTP/outboundSMTP-context.xml
+++ b/config/alfresco/subsystems/email/OutboundSMTP/outboundSMTP-context.xml
@@ -13,7 +13,7 @@
${mail.port}
-
+
${mail.protocol}
@@ -26,7 +26,7 @@
${mail.encoding}
-
+
${mail.smtp.auth}
${mail.smtp.debug}
@@ -40,45 +40,44 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${mail.header}
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${mail.header}
+
${mail.validate.addresses}
-
- ${mail.from.default}
-
-
+
+ ${mail.from.default}
+
+
${mail.from.enabled}
-
-
-
+
+
+
${mail.testmessage.send}
@@ -98,7 +97,36 @@
-
+
+
+
+
+
+ mailAsyncAction
+
+
+ ${mail.service.corePoolSize}
+
+
+ ${mail.service.maximumPoolSize}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/thumbnail-service-context.xml b/config/alfresco/thumbnail-service-context.xml
index 222509d785..87d1ccdd1d 100644
--- a/config/alfresco/thumbnail-service-context.xml
+++ b/config/alfresco/thumbnail-service-context.xml
@@ -46,6 +46,7 @@
+
-
-
-
-
-
-
diff --git a/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java b/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java
index 0266b9550c..35264413e9 100644
--- a/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java
+++ b/source/java/org/alfresco/cmis/mapping/ObjectIdProperty.java
@@ -36,11 +36,11 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.search.BooleanClause.Occur;
/**
* Get the CMIS object id property.
diff --git a/source/java/org/alfresco/cmis/mapping/ParentProperty.java b/source/java/org/alfresco/cmis/mapping/ParentProperty.java
index fef7081a26..55a1ba2adc 100644
--- a/source/java/org/alfresco/cmis/mapping/ParentProperty.java
+++ b/source/java/org/alfresco/cmis/mapping/ParentProperty.java
@@ -33,11 +33,11 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.search.BooleanClause.Occur;
/**
* Get the CMIS parent property
diff --git a/source/java/org/alfresco/jcr/session/SessionImpl.java b/source/java/org/alfresco/jcr/session/SessionImpl.java
index b206aaaf4f..b7b8b014f6 100644
--- a/source/java/org/alfresco/jcr/session/SessionImpl.java
+++ b/source/java/org/alfresco/jcr/session/SessionImpl.java
@@ -86,6 +86,7 @@ import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.view.ExporterCrawlerParameters;
import org.alfresco.service.cmr.view.ExporterService;
import org.alfresco.service.cmr.view.ImporterBinding;
+import org.alfresco.service.cmr.view.ImporterContentCache;
import org.alfresco.service.cmr.view.ImporterException;
import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.NamespacePrefixResolver;
@@ -829,41 +830,35 @@ public class SessionImpl implements Session
}
}
- /*
- * (non-Javadoc)
- * @see org.alfresco.service.cmr.view.ImporterBinding#getUUIDBinding()
- */
+ @Override
public UUID_BINDING getUUIDBinding()
{
return uuidBinding;
}
- /*
- * (non-Javadoc)
- * @see org.alfresco.service.cmr.view.ImporterBinding#getValue(java.lang.String)
- */
+ @Override
public String getValue(String key)
{
return null;
}
- /*
- * (non-Javadoc)
- * @see org.alfresco.service.cmr.view.ImporterBinding#searchWithinTransaction()
- */
+ @Override
public boolean allowReferenceWithinTransaction()
{
return false;
}
- /*
- * (non-Javadoc)
- * @see org.alfresco.service.cmr.view.ImporterBinding#getExcludedClasses()
- */
+ @Override
public QName[] getExcludedClasses()
{
return null;
}
+
+ @Override
+ public ImporterContentCache getImportConentCache()
+ {
+ return null;
+ }
}
//
diff --git a/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java
index e2d050f266..de0e0550eb 100644
--- a/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java
+++ b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java
@@ -247,7 +247,6 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
{
// Put these resources on the transactions
context = null;
- authentication = null;
nodeInfoMap.clear();
objectInfoMap.clear();
}
@@ -575,13 +574,25 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
{
try
{
+ if(connector.filter(child.getNodeRef()))
+ {
+ continue;
+ }
+
// create a child CMIS object
CMISNodeInfo ni = createNodeInfo(child.getNodeRef());
+
if (getObjectInfo(repositoryId, ni.getObjectId())==null)
{
// ignore invalid children
continue;
}
+
+ if (CMISObjectVariant.NOT_A_CMIS_OBJECT.equals(ni.getObjectVariant()))
+ {
+ continue; //Skip non-cmis objects
+ }
+
ObjectData object = connector.createCMISObject(ni, child, filter, includeAllowableActions,
includeRelationships, renditionFilter, false, false);
@@ -700,12 +711,22 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
{
continue;
}
-
+
if(isFolder && type.getAlfrescoClass().equals(ContentModel.TYPE_SYSTEM_FOLDER))
{
continue;
}
+
+ if(connector.isHidden(child.getChildRef()))
+ {
+ continue;
+ }
+ if(connector.filter(child.getChildRef()))
+ {
+ continue;
+ }
+
// create a child CMIS object
ObjectInFolderDataImpl object = new ObjectInFolderDataImpl();
CMISNodeInfo ni = createNodeInfo(child.getChildRef());
@@ -982,6 +1003,12 @@ 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;
+ }
+
if (skipCounter > 0)
{
skipCounter--;
@@ -1117,7 +1144,7 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
connector.getActivityPoster().postFileFolderAdded(fileInfo);
- return nodeRef.toString();
+ return nodeRef.getId();
}
private String stripEncoding(String mimeType)
@@ -1680,7 +1707,7 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
}
catch (Exception e)
{
- result.add(nodeRef.toString());
+ result.add(nodeRef.getId());
}
return result;
@@ -1735,6 +1762,11 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
rootNodeRef,
Arrays.asList(path.substring(1).split("/")));
+ if(connector.filter(fileInfo.getNodeRef()))
+ {
+ throw new CmisObjectNotFoundException("Object not found: " + path);
+ }
+
CMISNodeInfo info = createNodeInfo(fileInfo.getNodeRef());
ObjectData object = connector.createCMISObject(
@@ -1992,6 +2024,8 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
NodeRef nodeRef = info.getNodeRef();
VersionHistory versionHistory = ((CMISNodeInfoImpl) info).getVersionHistory();
+// Collection versions = versionHistory.getAllVersions();
+// if (versionHistory == null || versions.size() == 0 || versions.size() == 1 && versions.contains(versionHistory.getHeadVersion()))
if (versionHistory == null)
{
// add current version
@@ -2427,6 +2461,19 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
return info;
}
+ protected String getGuid(String nodeId)
+ {
+ int idx = nodeId.lastIndexOf("/");
+ if(idx != -1)
+ {
+ return nodeId.substring(idx+1);
+ }
+ else
+ {
+ return nodeId;
+ }
+ }
+
/**
* Collects the {@link ObjectInfo} about an object.
*
@@ -2530,7 +2577,7 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
info.setWorkingCopyId(null);
info.setWorkingCopyOriginalId(null);
- info.setVersionSeriesId(ni.getCurrentNodeId());
+ info.setVersionSeriesId(getGuid(ni.getCurrentNodeId()));
if (ni.isPWC())
{
@@ -2544,7 +2591,7 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr
if (ni.hasPWC())
{
- info.setWorkingCopyId(ni.getCurrentNodeId() + CMISConnector.ID_SEPERATOR
+ info.setWorkingCopyId(getGuid(ni.getCurrentNodeId()) + CMISConnector.ID_SEPERATOR
+ CMISConnector.PWC_VERSION_LABEL);
info.setWorkingCopyOriginalId(ni.getCurrentObjectId());
} else
diff --git a/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java.copy b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java.copy
new file mode 100644
index 0000000000..da0c8cadac
--- /dev/null
+++ b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java.copy
@@ -0,0 +1,2824 @@
+/*
+ * 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.opencmis;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import net.sf.acegisecurity.Authentication;
+
+import org.alfresco.cmis.CMISInvalidArgumentException;
+import org.alfresco.model.ContentModel;
+import org.alfresco.opencmis.dictionary.CMISNodeInfo;
+import org.alfresco.opencmis.dictionary.CMISObjectVariant;
+import org.alfresco.opencmis.dictionary.FolderTypeDefintionWrapper;
+import org.alfresco.opencmis.dictionary.PropertyDefinitionWrapper;
+import org.alfresco.opencmis.dictionary.TypeDefinitionWrapper;
+import org.alfresco.query.PagingRequest;
+import org.alfresco.query.PagingResults;
+import org.alfresco.repo.content.encoding.ContentCharsetFinder;
+import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery;
+import org.alfresco.repo.search.QueryParameterDefImpl;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.security.authentication.Authorization;
+import org.alfresco.repo.version.VersionModel;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.model.FileInfo;
+import org.alfresco.service.cmr.model.FileNotFoundException;
+import org.alfresco.service.cmr.repository.AssociationRef;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.search.QueryParameterDefinition;
+import org.alfresco.service.cmr.search.ResultSet;
+import org.alfresco.service.cmr.search.SearchParameters;
+import org.alfresco.service.cmr.search.SearchService;
+import org.alfresco.service.cmr.version.Version;
+import org.alfresco.service.cmr.version.VersionHistory;
+import org.alfresco.service.cmr.version.VersionType;
+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;
+import org.apache.chemistry.opencmis.commons.data.ContentStream;
+import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
+import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
+import org.apache.chemistry.opencmis.commons.data.ObjectData;
+import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
+import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
+import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
+import org.apache.chemistry.opencmis.commons.data.ObjectList;
+import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
+import org.apache.chemistry.opencmis.commons.data.Properties;
+import org.apache.chemistry.opencmis.commons.data.RenditionData;
+import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
+import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
+import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
+import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
+import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed;
+import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.commons.enums.RelationshipDirection;
+import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
+import org.apache.chemistry.opencmis.commons.enums.VersioningState;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
+import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectParentDataImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionContainerImpl;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionListImpl;
+import org.apache.chemistry.opencmis.commons.impl.server.AbstractCmisService;
+import org.apache.chemistry.opencmis.commons.impl.server.ObjectInfoImpl;
+import org.apache.chemistry.opencmis.commons.impl.server.RenditionInfoImpl;
+import org.apache.chemistry.opencmis.commons.server.CallContext;
+import org.apache.chemistry.opencmis.commons.server.ObjectInfo;
+import org.apache.chemistry.opencmis.commons.server.RenditionInfo;
+import org.apache.chemistry.opencmis.commons.spi.Holder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * OpenCMIS service implementation
+ *
+ * @author florian.mueller
+ * @author Derek Hulley
+ * @since 4.0
+ */
+public class AlfrescoCmisServiceImpl extends AbstractCmisService implements AlfrescoCmisService
+{
+ private static Log logger = LogFactory.getLog(AlfrescoCmisService.class);
+
+ private static final QName PARAM_PARENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "parent");
+ private static final QName PARAM_USERNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "username");
+ private static final String LUCENE_QUERY_CHECKEDOUT = "+@cm\\:workingCopyOwner:${cm:username}";
+ private static final String LUCENE_QUERY_CHECKEDOUT_IN_FOLDER = "+@cm\\:workingCopyOwner:${cm:username} +PARENT:\"${cm:parent}\"";
+
+ private static final String MIN_FILTER = "cmis:name,cmis:baseTypeId,cmis:objectTypeId,"
+ + "cmis:createdBy,cmis:creationDate,cmis:lastModifiedBy,cmis:lastModificationDate,"
+ + "cmis:contentStreamLength,cmis:contentStreamMimeType,cmis:contentStreamFileName,"
+ + "cmis:contentStreamId";
+
+ private CMISConnector connector;
+ private CallContext context;
+ private UserTransaction txn;
+
+ private Map nodeInfoMap;
+ private Map objectInfoMap;
+
+ public AlfrescoCmisService(CMISConnector connector)
+ {
+ this.connector = connector;
+ nodeInfoMap = new HashMap();
+ objectInfoMap = new HashMap();
+ }
+
+
+ public void beginCall(CallContext context)
+ {
+ this.context = context;
+
+ AuthenticationUtil.pushAuthentication();
+
+ try
+ {
+ String currentUser = connector.getAuthenticationService().getCurrentUserName();
+ String user = context.getUsername();
+ String password = context.getPassword();
+
+ if (currentUser == null)
+ {
+ Authorization auth = new Authorization(user, password);
+
+ if (auth.isTicket())
+ {
+ connector.getAuthenticationService().validate(auth.getTicket());
+ } else
+ {
+ connector.getAuthenticationService().authenticate(auth.getUserName(), auth.getPasswordCharArray());
+ }
+
+ } else if (currentUser.equals(connector.getProxyUser()))
+ {
+ if (user != null && user.length() > 0)
+ {
+ AuthenticationUtil.setFullyAuthenticatedUser(user);
+ }
+ }
+ } catch (AuthenticationException ae)
+ {
+ throw new CmisPermissionDeniedException(ae.getMessage(), ae);
+ }
+
+ // start read-only transaction
+ try
+ {
+ beginReadOnlyTransaction();
+ } catch (Exception e)
+ {
+ AuthenticationUtil.popAuthentication();
+
+ if (e instanceof CmisBaseException)
+ {
+ throw (CmisBaseException) e;
+ } else
+ {
+ throw new CmisRuntimeException(e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ try
+ {
+ endReadOnlyTransaction();
+ } catch (Exception e)
+ {
+ if (e instanceof CmisBaseException)
+ {
+ throw (CmisBaseException) e;
+ } else
+ {
+ throw new CmisRuntimeException(e.getMessage(), e);
+ }
+ } finally
+ {
+ AuthenticationUtil.popAuthentication();
+ context = null;
+ nodeInfoMap.clear();
+ objectInfoMap.clear();
+ }
+ }
+
+ /**
+ * Called directly before any CMIS method is used
+ */
+ void beforeCall();
+
+ /**
+ * Called directly after any CMIS method is used
+ */
+ void afterCall();
+
+ /**
+ * Call before the work method and forms the opposite of {@link #close()}.
+ * Gathers the type descendants tree.
+ */
+ private TypeDefinitionContainer getTypesDescendants(int depth, TypeDefinitionWrapper tdw,
+ boolean includePropertyDefinitions)
+ {
+ TypeDefinitionContainerImpl result = new TypeDefinitionContainerImpl();
+
+ result.setTypeDefinition(tdw.getTypeDefinition(includePropertyDefinitions));
+
+ if (depth != 0)
+ {
+ if (tdw.getChildren() != null)
+ {
+ result.setChildren(new ArrayList());
+ for (TypeDefinitionWrapper tdc : tdw.getChildren())
+ {
+ result.getChildren().add(
+ getTypesDescendants(depth < 0 ? -1 : depth - 1, tdc, includePropertyDefinitions));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ // --- navigation service ---
+
+ /*
+ * Lucene based getChildren - deactivated
+ */
+ public ObjectInFolderList XgetChildren(String repositoryId, String folderId, String filter, String orderBy,
+ Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+ Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // convert BigIntegers to int
+ int max = (maxItems == null ? Integer.MAX_VALUE : maxItems.intValue());
+ int skip = (skipCount == null || skipCount.intValue() < 0 ? 0 : skipCount.intValue());
+
+ ObjectInFolderListImpl result = new ObjectInFolderListImpl();
+ List list = new ArrayList();
+ result.setObjects(list);
+
+ // get the children references
+ NodeRef folderNodeRef = getOrCreateFolderInfo(folderId, "Folder").getNodeRef();
+
+ // lucene part
+ QName PARAM_PARENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "parent");
+ DataTypeDefinition nodeRefDataType = connector.getDictionaryService().getDataType(DataTypeDefinition.NODE_REF);
+
+ SearchParameters params = new SearchParameters();
+ params.setLanguage(SearchService.LANGUAGE_LUCENE);
+ params.addStore(folderNodeRef.getStoreRef());
+ QueryParameterDefinition parentDef = new QueryParameterDefImpl(PARAM_PARENT, nodeRefDataType, true,
+ folderNodeRef.toString());
+ params.addQueryParameterDefinition(parentDef);
+
+ // Build a query for the appropriate types
+ StringBuilder query = new StringBuilder(1024).append("+PARENT:\"${cm:parent}\" -ASPECT:\"")
+ .append(ContentModel.ASPECT_WORKING_COPY).append("\" +TYPE:(");
+
+ // Include doc type if necessary
+ query.append('"').append(ContentModel.TYPE_CONTENT).append('"');
+ query.append(" ");
+ query.append('"').append(ContentModel.TYPE_FOLDER).append('"');
+
+ // Always exclude system folders
+ query.append(") -TYPE:\"").append(ContentModel.TYPE_SYSTEM_FOLDER).append("\"");
+ params.setQuery(query.toString());
+ // parseOrderBy(orderBy, params);
+ ResultSet resultSet = null;
+
+ List childrenList;
+ try
+ {
+ resultSet = connector.getSearchService().query(params);
+ childrenList = resultSet.getNodeRefs();
+ } finally
+ {
+ if (resultSet != null)
+ resultSet.close();
+ }
+
+ if (max > 0)
+ {
+ int lastIndex = (max + skip > childrenList.size() ? childrenList.size() : max + skip) - 1;
+ for (int i = skip; i <= lastIndex; i++)
+ {
+ NodeRef child = childrenList.get(i);
+ CMISNodeInfo ni = createNodeInfo(child);
+
+ // create a child CMIS object
+ ObjectData object = connector.createCMISObject(ni, filter, includeAllowableActions,
+ includeRelationships, renditionFilter, false, false);
+
+ ObjectInFolderDataImpl childData = new ObjectInFolderDataImpl();
+ childData.setObject(object);
+
+ // include path segment
+ if (includePathSegment)
+ {
+ childData.setPathSegment(connector.getName(child));
+ }
+
+ // add it
+ list.add(childData);
+ }
+ }
+
+ result.setHasMoreItems(childrenList.size() - skip > result.getObjects().size());
+ result.setNumItems(BigInteger.valueOf(childrenList.size()));
+
+ return result;
+ }
+
+ public ObjectInFolderList getChildren(String repositoryId, String folderId, String filter, String orderBy,
+ Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+ Boolean includePathSegment, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension)
+ {
+ long start = System.currentTimeMillis();
+
+ checkRepositoryId(repositoryId);
+
+ // convert BigIntegers to int
+ int max = (maxItems == null ? Integer.MAX_VALUE : maxItems.intValue());
+ int skip = (skipCount == null || skipCount.intValue() < 0 ? 0 : skipCount.intValue());
+
+ ObjectInFolderListImpl result = new ObjectInFolderListImpl();
+ List list = new ArrayList();
+ result.setObjects(list);
+
+ // get the children references
+ NodeRef folderNodeRef = getOrCreateFolderInfo(folderId, "Folder").getNodeRef();
+
+ // convert orderBy to sortProps
+ List> sortProps = null;
+ if (orderBy != null)
+ {
+ sortProps = new ArrayList>(1);
+
+ String[] parts = orderBy.split(",");
+ int len = parts.length;
+ final int origLen = len;
+
+ if (origLen > 0)
+ {
+ int maxSortProps = GetChildrenCannedQuery.MAX_FILTER_SORT_PROPS;
+ if (len > maxSortProps)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Too many sort properties in 'orderBy' - ignore those above max (max="
+ + maxSortProps + ",actual=" + len + ")");
+ }
+ len = maxSortProps;
+ }
+ for (int i = 0; i < len; i++)
+ {
+ String[] sort = parts[i].split(" +");
+
+ if (sort.length > 0)
+ {
+ PropertyDefinitionWrapper propDef = connector.getOpenCMISDictionaryService()
+ .findPropertyByQueryName(sort[0]);
+ if (propDef != null)
+ {
+ QName sortProp = propDef.getPropertyAccessor().getMappedProperty();
+ if (sortProp != null)
+ {
+ boolean sortAsc = (sort.length == 1) || sort[1].equalsIgnoreCase("asc");
+ sortProps.add(new Pair(sortProp, sortAsc));
+ } else
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Ignore sort property '" + sort[0] + " - mapping not found");
+ }
+ }
+ } else
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Ignore sort property '" + sort[0] + " - query name not found");
+ }
+ }
+ }
+ }
+ }
+
+ if (sortProps.size() < origLen)
+ {
+ logger.warn("Sort properties trimmed - either too many and/or not found: \n" + " orig: " + orderBy
+ + "\n" + " final: " + sortProps);
+ }
+ }
+
+ PagingRequest pageRequest = new PagingRequest(skip, max, null);
+ pageRequest.setRequestTotalCountMax(skip + 10000); // TODO make this
+ // optional/configurable
+ // - affects whether
+ // numItems may be
+ // returned
+
+ PagingResults pageOfNodeInfos = connector.getFileFolderService().list(folderNodeRef, true, true,
+ null, sortProps, pageRequest);
+
+ if (max > 0)
+ {
+ for (FileInfo child : pageOfNodeInfos.getPage())
+ {
+ try
+ {
+ // create a child CMIS object
+ CMISNodeInfo ni = createNodeInfo(child.getNodeRef());
+ ObjectData object = connector.createCMISObject(ni, child, filter, includeAllowableActions,
+ includeRelationships, renditionFilter, false, false);
+
+ if (context.isObjectInfoRequired())
+ {
+ getObjectInfo(repositoryId, ni.getObjectId(), includeRelationships);
+ }
+
+ ObjectInFolderDataImpl childData = new ObjectInFolderDataImpl();
+ childData.setObject(object);
+
+ // include path segment
+ if (includePathSegment)
+ {
+ childData.setPathSegment(child.getName());
+ }
+
+ // add it
+ list.add(childData);
+ } catch (InvalidNodeRefException e)
+ {
+ // ignore invalid children
+ }
+ }
+ }
+
+ // has more ?
+ result.setHasMoreItems(pageOfNodeInfos.hasMoreItems());
+
+ // total count ?
+ Pair totalCounts = pageOfNodeInfos.getTotalResultCount();
+ if (totalCounts != null)
+ {
+ Integer totalCountLower = totalCounts.getFirst();
+ Integer totalCountUpper = totalCounts.getSecond();
+ if ((totalCountLower != null) && (totalCountLower.equals(totalCountUpper)))
+ {
+ result.setNumItems(BigInteger.valueOf(totalCountLower));
+ }
+ }
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("getChildren: " + list.size() + " in " + (System.currentTimeMillis() - start) + " msecs");
+ }
+
+ return result;
+ }
+
+ @Override
+ public List getDescendants(String repositoryId, String folderId, BigInteger depth,
+ String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+ String renditionFilter, Boolean includePathSegment, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ List result = new ArrayList();
+
+ getDescendantsTree(repositoryId, getOrCreateFolderInfo(folderId, "Folder").getNodeRef(), depth.intValue(),
+ filter, includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, false,
+ result);
+
+ return result;
+ }
+
+ @Override
+ public List getFolderTree(String repositoryId, String folderId, BigInteger depth,
+ String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
+ String renditionFilter, Boolean includePathSegment, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ List result = new ArrayList();
+
+ getDescendantsTree(repositoryId, getOrCreateFolderInfo(folderId, "Folder").getNodeRef(), depth.intValue(),
+ filter, includeAllowableActions, includeRelationships, renditionFilter, includePathSegment, true,
+ result);
+
+ return result;
+ }
+
+ private void getDescendantsTree(String repositoryId, NodeRef folderNodeRef, int depth, String filter,
+ Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+ Boolean includePathSegment, boolean foldersOnly, List list)
+ {
+ // get the children references
+ List childrenList = connector.getNodeService().getChildAssocs(folderNodeRef);
+ for (ChildAssociationRef child : childrenList)
+ {
+ try
+ {
+ TypeDefinitionWrapper type = connector.getType(child.getChildRef());
+ if (type == null)
+ {
+ continue;
+ }
+
+ boolean isFolder = (type instanceof FolderTypeDefintionWrapper);
+
+ if (foldersOnly && !isFolder)
+ {
+ continue;
+ }
+
+ if(connector.isHidden(child.getChildRef()))
+ {
+ continue;
+ }
+
+ // create a child CMIS object
+ ObjectInFolderDataImpl object = new ObjectInFolderDataImpl();
+ CMISNodeInfo ni = createNodeInfo(child.getChildRef());
+ object.setObject(connector.createCMISObject(ni, filter, includeAllowableActions, includeRelationships,
+ renditionFilter, false, false));
+ if (context.isObjectInfoRequired())
+ {
+ getObjectInfo(repositoryId, ni.getObjectId(), includeRelationships);
+ }
+
+ if (includePathSegment)
+ {
+ object.setPathSegment(connector.getName(child.getChildRef()));
+ }
+
+ // create the container
+ ObjectInFolderContainerImpl container = new ObjectInFolderContainerImpl();
+ container.setObject(object);
+
+ if ((depth != 1) && isFolder)
+ {
+ container.setChildren(new ArrayList());
+ getDescendantsTree(repositoryId, child.getChildRef(), depth - 1, filter, includeAllowableActions,
+ includeRelationships, renditionFilter, includePathSegment, foldersOnly,
+ container.getChildren());
+ }
+
+ // add it
+ list.add(container);
+ } catch (InvalidNodeRefException e)
+ {
+ // ignore invalid children
+ }
+ }
+ }
+
+ @Override
+ public ObjectData getFolderParent(String repositoryId, String folderId, String filter, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // get the node ref
+ CMISNodeInfo info = getOrCreateFolderInfo(folderId, "Folder");
+
+ // the root folder has no parent
+ if (info.isRootFolder())
+ {
+ throw new CmisInvalidArgumentException("Root folder has no parent!");
+ }
+
+ // get the parent
+ List parentInfos = info.getParents();
+ if (parentInfos.isEmpty())
+ {
+ throw new CmisRuntimeException("Folder has no parent and is not the root folder?!");
+ }
+
+ CMISNodeInfo parentInfo = addNodeInfo(parentInfos.get(0));
+
+ ObjectData result = connector.createCMISObject(parentInfo, filter, false, IncludeRelationships.NONE,
+ CMISConnector.RENDITION_NONE, false, false);
+ if (context.isObjectInfoRequired())
+ {
+ getObjectInfo(repositoryId, parentInfo.getObjectId(), IncludeRelationships.NONE);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List getObjectParents(String repositoryId, String objectId, String filter,
+ Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+ Boolean includeRelativePathSegment, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ List result = new ArrayList();
+
+ // what kind of object is it?
+ CMISNodeInfo info = getOrCreateNodeInfo(objectId, "Object");
+
+ // relationships are not filed
+ if (info.isRelationship())
+ {
+ throw new CmisConstraintException("Relationships are not fileable!");
+ }
+
+ if (info.isFolder() && !info.isRootFolder())
+ {
+ List parentInfos = info.getParents();
+ if (!parentInfos.isEmpty())
+ {
+ CMISNodeInfo parentInfo = addNodeInfo(parentInfos.get(0));
+
+ ObjectData object = connector.createCMISObject(parentInfo, filter, includeAllowableActions,
+ includeRelationships, renditionFilter, false, false);
+ if (context.isObjectInfoRequired())
+ {
+ getObjectInfo(repositoryId, object.getId(), includeRelationships);
+ }
+
+ ObjectParentDataImpl objectParent = new ObjectParentDataImpl();
+ objectParent.setObject(object);
+
+ // include relative path segment
+ if (includeRelativePathSegment)
+ {
+ objectParent.setRelativePathSegment(info.getName());
+ }
+
+ result.add(objectParent);
+ }
+ } else if (info.isCurrentVersion() || info.isPWC())
+ {
+ List parentInfos = info.getParents();
+ for (CMISNodeInfo parentInfo : parentInfos)
+ {
+ addNodeInfo(parentInfo);
+
+ ObjectData object = connector.createCMISObject(parentInfo, filter, includeAllowableActions,
+ includeRelationships, renditionFilter, false, false);
+ if (context.isObjectInfoRequired())
+ {
+ getObjectInfo(repositoryId, object.getId(), includeRelationships);
+ }
+
+ ObjectParentDataImpl objectParent = new ObjectParentDataImpl();
+ objectParent.setObject(object);
+
+ // include relative path segment
+ if (includeRelativePathSegment)
+ {
+ objectParent.setRelativePathSegment(info.getName());
+ }
+
+ result.add(objectParent);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public ObjectList getCheckedOutDocs(String repositoryId, String folderId, String filter, String orderBy,
+ Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
+ BigInteger maxItems, BigInteger skipCount, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // convert BigIntegers to int
+ int max = (maxItems == null ? Integer.MAX_VALUE : maxItems.intValue());
+ int skip = (skipCount == null || skipCount.intValue() < 0 ? 0 : skipCount.intValue());
+
+ // prepare query
+ SearchParameters params = new SearchParameters();
+ params.setLanguage(SearchService.LANGUAGE_LUCENE);
+ QueryParameterDefinition usernameDef = new QueryParameterDefImpl(PARAM_USERNAME, connector
+ .getDictionaryService().getDataType(DataTypeDefinition.TEXT), true,
+ AuthenticationUtil.getFullyAuthenticatedUser());
+ params.addQueryParameterDefinition(usernameDef);
+
+ if (folderId == null)
+ {
+ params.setQuery(LUCENE_QUERY_CHECKEDOUT);
+ params.addStore(connector.getRootStoreRef());
+ } else
+ {
+ CMISNodeInfo folderInfo = getOrCreateFolderInfo(folderId, "Folder");
+
+ params.setQuery(LUCENE_QUERY_CHECKEDOUT_IN_FOLDER);
+ params.addStore(folderInfo.getNodeRef().getStoreRef());
+ QueryParameterDefinition parentDef = new QueryParameterDefImpl(PARAM_PARENT, connector
+ .getDictionaryService().getDataType(DataTypeDefinition.NODE_REF), true, folderInfo.getNodeRef()
+ .toString());
+ params.addQueryParameterDefinition(parentDef);
+ }
+
+ // set up order
+ if (orderBy != null)
+ {
+ String[] parts = orderBy.split(",");
+ for (int i = 0; i < parts.length; i++)
+ {
+ String[] sort = parts[i].split(" +");
+
+ if (sort.length < 1)
+ {
+ continue;
+ }
+
+ PropertyDefinitionWrapper propDef = connector.getOpenCMISDictionaryService().findPropertyByQueryName(
+ sort[0]);
+ if (propDef != null)
+ {
+ if (propDef.getPropertyDefinition().isOrderable())
+ {
+ QName sortProp = propDef.getPropertyAccessor().getMappedProperty();
+ if (sortProp != null)
+ {
+ boolean sortAsc = (sort.length == 1) || sort[1].equalsIgnoreCase("asc");
+ params.addSort(propDef.getPropertyLuceneBuilder().getLuceneFieldName(), sortAsc);
+ } else
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Ignore sort property '" + sort[0] + " - mapping not found");
+ }
+ }
+ } else
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Ignore sort property '" + sort[0] + " - not orderable");
+ }
+ }
+ } else
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Ignore sort property '" + sort[0] + " - query name not found");
+ }
+ }
+ }
+ }
+
+ // execute query
+ ResultSet resultSet = null;
+ List nodeRefs;
+ try
+ {
+ resultSet = connector.getSearchService().query(params);
+ nodeRefs = resultSet.getNodeRefs();
+ } finally
+ {
+ if (resultSet != null)
+ {
+ resultSet.close();
+ }
+ }
+
+ // collect results
+ ObjectListImpl result = new ObjectListImpl();
+ List list = new ArrayList();
+ result.setObjects(list);
+
+ int skipCounter = skip;
+ if (max > 0)
+ {
+ for (NodeRef nodeRef : nodeRefs)
+ {
+ if (skipCounter > 0)
+ {
+ skipCounter--;
+ continue;
+ }
+
+ if (list.size() == max)
+ {
+ break;
+ }
+
+ try
+ {
+ // create a CMIS object
+ CMISNodeInfo ni = createNodeInfo(nodeRef);
+ ObjectData object = connector.createCMISObject(ni, filter, includeAllowableActions,
+ includeRelationships, renditionFilter, false, false);
+
+ if (context.isObjectInfoRequired())
+ {
+ getObjectInfo(repositoryId, ni.getObjectId(), includeRelationships);
+ }
+
+ // add it
+ list.add(object);
+ } catch (InvalidNodeRefException e)
+ {
+ // ignore invalid objects
+ }
+ }
+ }
+
+ // has more ?
+ result.setHasMoreItems(nodeRefs.size() - skip > list.size());
+
+ return result;
+ }
+
+ // --- object service ---
+
+ @Override
+ public String create(String repositoryId, Properties properties, String folderId, ContentStream contentStream,
+ VersioningState versioningState, List policies, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // check properties
+ if (properties == null || properties.getProperties() == null)
+ {
+ throw new CmisInvalidArgumentException("Properties must be set!");
+ }
+
+ // get the type
+ String objectTypeId = connector.getObjectTypeIdProperty(properties);
+
+ // find the type
+ TypeDefinitionWrapper type = connector.getOpenCMISDictionaryService().findType(objectTypeId);
+ if (type == null)
+ {
+ throw new CmisInvalidArgumentException("Type '" + objectTypeId + "' is unknown!");
+ }
+
+ // create object
+ String newId = null;
+ switch (type.getBaseTypeId())
+ {
+ case CMIS_DOCUMENT:
+ newId = createDocument(repositoryId, properties, folderId, contentStream, versioningState, policies, null,
+ null, extension);
+ break;
+ case CMIS_FOLDER:
+ newId = createFolder(repositoryId, properties, folderId, policies, null, null, extension);
+ break;
+ case CMIS_POLICY:
+ newId = createPolicy(repositoryId, properties, folderId, policies, null, null, extension);
+ break;
+ }
+
+ // check new object id
+ if (newId == null)
+ {
+ throw new CmisRuntimeException("Creation failed!");
+ }
+
+ if (context.isObjectInfoRequired())
+ {
+ try
+ {
+ getObjectInfo(repositoryId, newId, "*", IncludeRelationships.NONE);
+ } catch (InvalidNodeRefException e)
+ {
+ throw new CmisRuntimeException("Creation failed! New object not found!");
+ }
+ }
+
+ // return the new object id
+ return newId;
+ }
+
+ @Override
+ public String createFolder(String repositoryId, final Properties properties, String folderId,
+ final List policies, final Acl addAces, final Acl removeAces, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // get the parent folder node ref
+ final CMISNodeInfo parentInfo = getOrCreateFolderInfo(folderId, "Folder");
+
+ // get name and type
+ final String name = connector.getNameProperty(properties, null);
+ final String objectTypeId = connector.getObjectTypeIdProperty(properties);
+ final TypeDefinitionWrapper type = connector.getTypeForCreate(objectTypeId, BaseTypeId.CMIS_FOLDER);
+
+ connector.checkChildObjectType(parentInfo, type.getTypeId());
+
+ // run transaction
+ endReadOnlyTransaction();
+ NodeRef newNodeRef = connector.getTransactionService().getRetryingTransactionHelper()
+ .doInTransaction(new RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Exception
+ {
+ try
+ {
+ NodeRef nodeRef = connector.getFileFolderService()
+ .create(parentInfo.getNodeRef(), name, type.getAlfrescoClass()).getNodeRef();
+
+ connector.setProperties(nodeRef, type, properties, new String[] { PropertyIds.NAME,
+ PropertyIds.OBJECT_TYPE_ID });
+ connector.applyPolicies(nodeRef, type, policies);
+ connector.applyACL(nodeRef, type, addAces, removeAces);
+
+ return nodeRef;
+ } catch (FileExistsException fee)
+ {
+ throw new CmisContentAlreadyExistsException("An object with this name already exists!", fee);
+ } catch (IntegrityException ie)
+ {
+ throw new CmisConstraintException("Constraint violation: " + ie.getMessage(), ie);
+ } catch (AccessDeniedException ade)
+ {
+ throw new CmisPermissionDeniedException("Permission denied!", ade);
+ }
+ };
+ }, false, true);
+ beginReadOnlyTransaction();
+
+ return newNodeRef.getId();
+ }
+
+ @Override
+ public String createDocument(String repositoryId, final Properties properties, String folderId,
+ final ContentStream contentStream, final VersioningState versioningState, final List policies,
+ final Acl addAces, final Acl removeAces, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // get the parent folder node ref
+ final CMISNodeInfo parentInfo = getOrCreateFolderInfo(folderId, "Parent folder");
+
+ // get name and type
+ final String name = connector.getNameProperty(properties, null);
+ final String objectTypeId = connector.getObjectTypeIdProperty(properties);
+ final TypeDefinitionWrapper type = connector.getTypeForCreate(objectTypeId, BaseTypeId.CMIS_DOCUMENT);
+
+ connector.checkChildObjectType(parentInfo, type.getTypeId());
+
+ DocumentTypeDefinition docType = (DocumentTypeDefinition) type.getTypeDefinition(false);
+
+ if ((docType.getContentStreamAllowed() == ContentStreamAllowed.NOTALLOWED) && (contentStream != null))
+ {
+ throw new CmisConstraintException("This document type does not support content!");
+ }
+
+ if ((docType.getContentStreamAllowed() == ContentStreamAllowed.REQUIRED) && (contentStream == null))
+ {
+ throw new CmisConstraintException("This document type does requires content!");
+ }
+
+ if (docType.isVersionable() && (versioningState == VersioningState.NONE))
+ {
+ throw new CmisConstraintException("This document type is versionable!");
+ }
+
+ if (!docType.isVersionable() && (versioningState != VersioningState.NONE))
+ {
+ throw new CmisConstraintException("This document type is not versionable!");
+ }
+
+ // copy stream to temp file
+ final File tempFile = copyToTempFile(contentStream);
+ final Charset encoding = (tempFile == null ? null : getEncoding(tempFile, contentStream.getMimeType()));
+
+ // run transaction
+ endReadOnlyTransaction();
+ NodeRef newNodeRef = connector.getTransactionService().getRetryingTransactionHelper()
+ .doInTransaction(new RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Exception
+ {
+ try
+ {
+ NodeRef nodeRef = connector.getFileFolderService()
+ .create(parentInfo.getNodeRef(), name, type.getAlfrescoClass()).getNodeRef();
+
+ connector.setProperties(nodeRef, type, properties, new String[] { PropertyIds.NAME,
+ PropertyIds.OBJECT_TYPE_ID });
+ connector.applyPolicies(nodeRef, type, policies);
+ connector.applyACL(nodeRef, type, addAces, removeAces);
+
+ // handle content
+ if (contentStream != null)
+ {
+ // write content
+ ContentWriter writer = connector.getFileFolderService().getWriter(nodeRef);
+ writer.setMimetype(contentStream.getMimeType());
+ writer.setEncoding(encoding.name());
+ writer.putContent(tempFile);
+ }
+
+ connector.applyVersioningState(nodeRef, versioningState);
+
+ return nodeRef;
+ } catch (FileExistsException fee)
+ {
+ removeTempFile(tempFile);
+ throw new CmisContentAlreadyExistsException("An object with this name already exists!", fee);
+ } catch (IntegrityException ie)
+ {
+ removeTempFile(tempFile);
+ throw new CmisConstraintException("Constraint violation: " + ie.getMessage(), ie);
+ } catch (AccessDeniedException ade)
+ {
+ removeTempFile(tempFile);
+ throw new CmisPermissionDeniedException("Permission denied!", ade);
+ }
+ };
+ }, false, true);
+ beginReadOnlyTransaction();
+
+ removeTempFile(tempFile);
+
+ return connector.createObjectId(newNodeRef);
+ }
+
+ @Override
+ public String createDocumentFromSource(String repositoryId, String sourceId, final Properties properties,
+ String folderId, final VersioningState versioningState, final List policies, final Acl addAces,
+ final Acl removeAces, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // get the parent folder node ref
+ final CMISNodeInfo parentInfo = getOrCreateFolderInfo(folderId, "Parent folder");
+
+ // get source
+ CMISNodeInfo info = getOrCreateNodeInfo(sourceId, "Source");
+
+ // check source
+ if (info.isVariant(CMISObjectVariant.ASSOC))
+ {
+ throw new CmisConstraintException("Source object is not a document!");
+ }
+
+ final NodeRef sourceNodeRef = info.getNodeRef();
+ if (!info.isDocument())
+ {
+ throw new CmisConstraintException("Source object is not a document!");
+ }
+
+ // get name and type
+ final String name = connector.getNameProperty(properties, info.getName());
+
+ final TypeDefinitionWrapper type = info.getType();
+ connector.checkChildObjectType(parentInfo, type.getTypeId());
+
+ // run transaction
+ endReadOnlyTransaction();
+ NodeRef newNodeRef = connector.getTransactionService().getRetryingTransactionHelper()
+ .doInTransaction(new RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Exception
+ {
+ try
+ {
+ NodeRef newDocumentNodeRef = connector.getFileFolderService()
+ .copy(sourceNodeRef, parentInfo.getNodeRef(), name).getNodeRef();
+
+ connector.setProperties(newDocumentNodeRef, type, properties, new String[] {
+ PropertyIds.NAME, PropertyIds.OBJECT_TYPE_ID });
+ connector.applyPolicies(newDocumentNodeRef, type, policies);
+ connector.applyACL(newDocumentNodeRef, type, addAces, removeAces);
+ connector.applyVersioningState(newDocumentNodeRef, versioningState);
+
+ return newDocumentNodeRef;
+ } catch (FileExistsException fee)
+ {
+ throw new CmisContentAlreadyExistsException("An object with this name already exists!", fee);
+ } catch (IntegrityException ie)
+ {
+ throw new CmisConstraintException("Constraint violation: " + ie.getMessage(), ie);
+ } catch (AccessDeniedException ade)
+ {
+ throw new CmisPermissionDeniedException("Permission denied!", ade);
+ }
+ };
+ }, false, true);
+ beginReadOnlyTransaction();
+
+ return connector.createObjectId(newNodeRef);
+ }
+
+ @Override
+ public String createPolicy(String repositoryId, Properties properties, String folderId, List policies,
+ Acl addAces, Acl removeAces, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // get the parent folder
+ getOrCreateFolderInfo(folderId, "Parent Folder");
+
+ String objectTypeId = connector.getObjectTypeIdProperty(properties);
+ connector.getTypeForCreate(objectTypeId, BaseTypeId.CMIS_POLICY);
+
+ // we should never get here - policies are not creatable!
+ throw new CmisRuntimeException("Polcies cannot be created!");
+ }
+
+ @Override
+ public String createRelationship(String repositoryId, Properties properties, List policies, Acl addAces,
+ Acl removeAces, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ // get type
+ String objectTypeId = connector.getObjectTypeIdProperty(properties);
+ final TypeDefinitionWrapper type = connector.getTypeForCreate(objectTypeId, BaseTypeId.CMIS_RELATIONSHIP);
+
+ // get source object
+ String sourceId = connector.getSourceIdProperty(properties);
+ CMISNodeInfo sourceInfo = getOrCreateNodeInfo(sourceId, "Source");
+
+ if (!sourceInfo.isVariant(CMISObjectVariant.CURRENT_VERSION) && !sourceInfo.isVariant(CMISObjectVariant.FOLDER))
+ {
+ throw new CmisInvalidArgumentException("Source is not the latest version of a document or a folder object!");
+ }
+
+ final NodeRef sourceNodeRef = sourceInfo.getNodeRef();
+
+ // get target object
+ String targetId = connector.getTargetIdProperty(properties);
+ CMISNodeInfo targetInfo = getOrCreateNodeInfo(targetId, "Target");
+
+ if (!targetInfo.isVariant(CMISObjectVariant.CURRENT_VERSION) && !targetInfo.isVariant(CMISObjectVariant.FOLDER))
+ {
+ throw new CmisInvalidArgumentException(
+ "Target is not the latest version of a document or a folder object!!");
+ }
+
+ final NodeRef targetNodeRef = targetInfo.getNodeRef();
+
+ // check policies and ACLs
+ if ((policies != null) && (!policies.isEmpty()))
+ {
+ throw new CmisConstraintException("Relationships are not policy controllable!");
+ }
+
+ if ((addAces != null) && (addAces.getAces() != null) && (!addAces.getAces().isEmpty()))
+ {
+ throw new CmisConstraintException("Relationships are not ACL controllable!");
+ }
+
+ if ((removeAces != null) && (removeAces.getAces() != null) && (!removeAces.getAces().isEmpty()))
+ {
+ throw new CmisConstraintException("Relationships are not ACL controllable!");
+ }
+
+ // create relationship
+ endReadOnlyTransaction();
+ AssociationRef assocRef = connector.getTransactionService().getRetryingTransactionHelper()
+ .doInTransaction(new RetryingTransactionCallback()
+ {
+ public AssociationRef execute() throws Exception
+ {
+ try
+ {
+ return connector.getNodeService().createAssociation(sourceNodeRef, targetNodeRef,
+ type.getAlfrescoClass());
+ } catch (IntegrityException ie)
+ {
+ throw new CmisConstraintException("Constraint violation: " + ie.getMessage(), ie);
+ } catch (AccessDeniedException ade)
+ {
+ throw new CmisPermissionDeniedException("Permission denied!", ade);
+ }
+ };
+ }, false, true);
+ beginReadOnlyTransaction();
+
+ return CMISConnector.ASSOC_ID_PREFIX + assocRef.getId();
+ }
+
+ @Override
+ public void setContentStream(String repositoryId, Holder objectId, Boolean overwriteFlag,
+ Holder changeToken, final ContentStream contentStream, ExtensionsData extension)
+ {
+ checkRepositoryId(repositoryId);
+
+ CMISNodeInfo info = getOrCreateNodeInfo(objectId.getValue(), "Object");
+
+ if (!info.isVariant(CMISObjectVariant.CURRENT_VERSION) && !info.isVariant(CMISObjectVariant.PWC))
+ {
+ throw new CmisStreamNotSupportedException("Content can only be set ondocuments!");
+ }
+
+ final NodeRef nodeRef = info.getNodeRef();
+
+ if (((DocumentTypeDefinition) info.getType().getTypeDefinition(false)).getContentStreamAllowed() == ContentStreamAllowed.NOTALLOWED)
+ {
+ throw new CmisStreamNotSupportedException("Document type doesn't allow content!");
+ }
+
+ boolean existed = connector.getContentService().getReader(nodeRef, ContentModel.PROP_CONTENT) != null;
+ if (existed && !overwriteFlag)
+ {
+ throw new CmisContentAlreadyExistsException("Content already exists!");
+ }
+
+ if ((contentStream == null) || (contentStream.getStream() == null))
+ {
+ throw new CmisInvalidArgumentException("No content!");
+ }
+
+ // copy stream to temp file
+ final File tempFile = copyToTempFile(contentStream);
+ final Charset encoding = getEncoding(tempFile, contentStream.getMimeType());
+
+ endReadOnlyTransaction();
+ connector.getTransactionService().getRetryingTransactionHelper()
+ .doInTransaction(new RetryingTransactionCallback