blob: 52f692796776130c36b57bbdb7b8dc7183232f18 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.chemistry.opencmis.client.bindings.spi.atompub;
import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNotEmpty;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.stream.XMLStreamWriter;
import org.apache.chemistry.opencmis.client.bindings.impl.CmisBindingsHelper;
import org.apache.chemistry.opencmis.client.bindings.impl.RepositoryInfoCache;
import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
import org.apache.chemistry.opencmis.client.bindings.spi.LinkAccess;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAcl;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomBase;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.RepositoryWorkspace;
import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.ServiceDoc;
import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpInvoker;
import org.apache.chemistry.opencmis.client.bindings.spi.http.Output;
import org.apache.chemistry.opencmis.client.bindings.spi.http.Response;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.apache.chemistry.opencmis.commons.data.Ace;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
import org.apache.chemistry.opencmis.commons.data.ObjectData;
import org.apache.chemistry.opencmis.commons.data.Properties;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisFilterNotValidException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisProxyAuthenticationException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisServiceUnavailableException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisUnauthorizedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
import org.apache.chemistry.opencmis.commons.impl.XMLConverter;
import org.apache.chemistry.opencmis.commons.impl.XMLUtils;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PolicyIdListImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl;
/**
* Base class for all AtomPub client services.
*/
public abstract class AbstractAtomPubService implements LinkAccess {
protected enum IdentifierType {
ID, PATH
}
protected static final String NAME_COLLECTION = "collection";
protected static final String NAME_URI_TEMPLATE = "uritemplate";
protected static final String NAME_PATH_SEGMENT = "pathSegment";
protected static final String NAME_RELATIVE_PATH_SEGMENT = "relativePathSegment";
protected static final String NAME_NUM_ITEMS = "numItems";
private BindingSession session;
/**
* Sets the current session.
*/
protected void setSession(BindingSession session) {
this.session = session;
}
/**
* Gets the current session.
*/
protected BindingSession getSession() {
return session;
}
/**
* Gets the HTTP Invoker object.
*/
protected HttpInvoker getHttpInvoker() {
return CmisBindingsHelper.getHttpInvoker(session);
}
/**
* Returns the service document URL of this session.
*/
protected String getServiceDocURL() {
Object url = session.get(SessionParameter.ATOMPUB_URL);
if (url instanceof String) {
return (String) url;
}
return null;
}
/**
* Return the CMIS version of the given repository.
*/
protected CmisVersion getCmisVersion(String repositoryId) {
if (CmisBindingsHelper.getForcedCmisVersion(session) != null) {
return CmisBindingsHelper.getForcedCmisVersion(session);
}
RepositoryInfoCache cache = CmisBindingsHelper.getRepositoryInfoCache(session);
RepositoryInfo info = cache.get(repositoryId);
if (info == null) {
List<RepositoryInfo> infoList = getRepositoriesInternal(repositoryId);
if (isNotEmpty(infoList)) {
info = infoList.get(0);
cache.put(info);
}
}
return (info == null ? CmisVersion.CMIS_1_0 : info.getCmisVersion());
}
// ---- link cache ----
/**
* Returns the link cache or creates a new cache if it doesn't exist.
*/
protected LinkCache getLinkCache() {
LinkCache linkCache = (LinkCache) getSession().get(SpiSessionParameter.LINK_CACHE);
if (linkCache == null) {
linkCache = new LinkCache(getSession());
getSession().put(SpiSessionParameter.LINK_CACHE, linkCache);
}
return linkCache;
}
/**
* Gets a link from the cache.
*/
protected String getLink(String repositoryId, String id, String rel, String type) {
if (repositoryId == null) {
throw new CmisInvalidArgumentException("Repository ID must be set!");
}
if (id == null) {
throw new CmisInvalidArgumentException("Object ID must be set!");
}
return getLinkCache().getLink(repositoryId, id, rel, type);
}
/**
* Gets a link from the cache.
*/
protected String getLink(String repositoryId, String id, String rel) {
return getLink(repositoryId, id, rel, null);
}
/**
* Gets a link from the cache if it is there or loads it into the cache if
* it is not there.
*/
public String loadLink(String repositoryId, String id, String rel, String type) {
String link = getLink(repositoryId, id, rel, type);
if (link == null) {
getObjectInternal(repositoryId, IdentifierType.ID, id, ReturnVersion.THIS, "cmis:objectId", Boolean.FALSE,
IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, null);
link = getLink(repositoryId, id, rel, type);
}
return link;
}
/**
* Gets the content link from the cache if it is there or loads it into the
* cache if it is not there.
*/
public String loadContentLink(String repositoryId, String id) {
return loadLink(repositoryId, id, AtomPubParser.LINK_REL_CONTENT, null);
}
/**
* Gets a rendition content link from the cache if it is there or loads it
* into the cache if it is not there.
*/
public String loadRenditionContentLink(String repositoryId, String id, String streamId) {
return loadLink(repositoryId, id, Constants.REL_ALTERNATE, streamId);
}
/**
* Adds a link to the cache.
*/
protected void addLink(String repositoryId, String id, String rel, String type, String link) {
getLinkCache().addLink(repositoryId, id, rel, type, link);
}
/**
* Adds a link to the cache.
*/
protected void addLink(String repositoryId, String id, AtomLink link) {
getLinkCache().addLink(repositoryId, id, link.getRel(), link.getType(), link.getHref());
}
/**
* Removes all links of an object.
*/
protected void removeLinks(String repositoryId, String id) {
getLinkCache().removeLinks(repositoryId, id);
}
/**
* Locks the link cache.
*/
protected void lockLinks() {
getLinkCache().lockLinks();
}
/**
* Unlocks the link cache.
*/
protected void unlockLinks() {
getLinkCache().unlockLinks();
}
/**
* Checks a link throw an appropriate exception.
*/
protected void throwLinkException(String repositoryId, String id, String rel, String type) {
int index = getLinkCache().checkLink(repositoryId, id, rel, type);
switch (index) {
case 0:
throw new CmisObjectNotFoundException("Unknown repository!");
case 1:
throw new CmisObjectNotFoundException("Unknown object!");
case 2:
throw new CmisNotSupportedException("Operation not supported by the repository for this object!");
case 3:
throw new CmisNotSupportedException("No link with matching media type!");
case 4:
throw new CmisRuntimeException("Nothing wrong! Either this is a bug or a threading issue.");
default:
throw new CmisRuntimeException("Unknown error!");
}
}
/**
* Gets a type link from the cache.
*/
protected String getTypeLink(String repositoryId, String typeId, String rel, String type) {
if (repositoryId == null) {
throw new CmisInvalidArgumentException("Repository ID must be set!");
}
if (typeId == null) {
throw new CmisInvalidArgumentException("Type ID must be set!");
}
return getLinkCache().getTypeLink(repositoryId, typeId, rel, type);
}
/**
* Gets a type link from the cache.
*/
protected String getTypeLink(String repositoryId, String typeId, String rel) {
return getTypeLink(repositoryId, typeId, rel, null);
}
/**
* Gets a link from the cache if it is there or loads it into the cache if
* it is not there.
*/
protected String loadTypeLink(String repositoryId, String typeId, String rel, String type) {
String link = getTypeLink(repositoryId, typeId, rel, type);
if (link == null) {
getTypeDefinitionInternal(repositoryId, typeId);
link = getTypeLink(repositoryId, typeId, rel, type);
}
return link;
}
/**
* Adds a type link to the cache.
*/
protected void addTypeLink(String repositoryId, String typeId, String rel, String type, String link) {
getLinkCache().addTypeLink(repositoryId, typeId, rel, type, link);
}
/**
* Adds a type link to the cache.
*/
protected void addTypeLink(String repositoryId, String typeId, AtomLink link) {
getLinkCache().addTypeLink(repositoryId, typeId, link.getRel(), link.getType(), link.getHref());
}
/**
* Removes all links of a type.
*/
protected void removeTypeLinks(String repositoryId, String id) {
getLinkCache().removeTypeLinks(repositoryId, id);
}
/**
* Locks the type link cache.
*/
protected void lockTypeLinks() {
getLinkCache().lockTypeLinks();
}
/**
* Unlocks the type link cache.
*/
protected void unlockTypeLinks() {
getLinkCache().unlockTypeLinks();
}
/**
* Gets a collection from the cache.
*/
protected String getCollection(String repositoryId, String collection) {
return getLinkCache().getCollection(repositoryId, collection);
}
/**
* Gets a collection from the cache if it is there or loads it into the
* cache if it is not there.
*/
protected String loadCollection(String repositoryId, String collection) {
String link = getCollection(repositoryId, collection);
if (link == null) {
// cache repository info
getRepositoriesInternal(repositoryId);
link = getCollection(repositoryId, collection);
}
return link;
}
/**
* Adds a collection to the cache.
*/
protected void addCollection(String repositoryId, String collection, String link) {
getLinkCache().addCollection(repositoryId, collection, link);
}
/**
* Gets a repository link from the cache.
*/
protected String getRepositoryLink(String repositoryId, String rel) {
return getLinkCache().getRepositoryLink(repositoryId, rel);
}
/**
* Gets a repository link from the cache if it is there or loads it into the
* cache if it is not there.
*/
protected String loadRepositoryLink(String repositoryId, String rel) {
String link = getRepositoryLink(repositoryId, rel);
if (link == null) {
// cache repository info
getRepositoriesInternal(repositoryId);
link = getRepositoryLink(repositoryId, rel);
}
return link;
}
/**
* Adds a repository link to the cache.
*/
protected void addRepositoryLink(String repositoryId, String rel, String link) {
getLinkCache().addRepositoryLink(repositoryId, rel, link);
}
/**
* Adds a repository link to the cache.
*/
protected void addRepositoryLink(String repositoryId, AtomLink link) {
addRepositoryLink(repositoryId, link.getRel(), link.getHref());
}
/**
* Gets an URI template from the cache.
*/
protected String getTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
return getLinkCache().getTemplateLink(repositoryId, type, parameters);
}
/**
* Gets a template link from the cache if it is there or loads it into the
* cache if it is not there.
*/
protected String loadTemplateLink(String repositoryId, String type, Map<String, Object> parameters) {
String link = getTemplateLink(repositoryId, type, parameters);
if (link == null) {
// cache repository info
getRepositoriesInternal(repositoryId);
link = getTemplateLink(repositoryId, type, parameters);
}
return link;
}
/**
* Adds an URI template to the cache.
*/
protected void addTemplate(String repositoryId, String type, String link) {
getLinkCache().addTemplate(repositoryId, type, link);
}
// ---- exceptions ----
/**
* Converts a HTTP status code into an Exception.
*/
protected CmisBaseException convertStatusCode(int code, String message, String errorContent, Throwable t) {
String exception = extractException(errorContent);
message = extractErrorMessage(message, errorContent);
switch (code) {
case 301:
case 302:
case 303:
case 307:
return new CmisConnectionException("Redirects are not supported (HTTP status code " + code + "): "
+ message, errorContent, t);
case 400:
if (CmisFilterNotValidException.EXCEPTION_NAME.equals(exception)) {
return new CmisFilterNotValidException(message, errorContent, t);
}
return new CmisInvalidArgumentException(message, errorContent, t);
case 401:
return new CmisUnauthorizedException(message, errorContent, t);
case 403:
if (CmisStreamNotSupportedException.EXCEPTION_NAME.equals(exception)) {
return new CmisStreamNotSupportedException(message, errorContent, t);
}
return new CmisPermissionDeniedException(message, errorContent, t);
case 404:
return new CmisObjectNotFoundException(message, errorContent, t);
case 405:
return new CmisNotSupportedException(message, errorContent, t);
case 407:
return new CmisProxyAuthenticationException(message, errorContent, t);
case 409:
if (CmisContentAlreadyExistsException.EXCEPTION_NAME.equals(exception)) {
return new CmisContentAlreadyExistsException(message, errorContent, t);
} else if (CmisVersioningException.EXCEPTION_NAME.equals(exception)) {
return new CmisVersioningException(message, errorContent, t);
} else if (CmisUpdateConflictException.EXCEPTION_NAME.equals(exception)) {
return new CmisUpdateConflictException(message, errorContent, t);
} else if (CmisNameConstraintViolationException.EXCEPTION_NAME.equals(exception)) {
return new CmisNameConstraintViolationException(message, errorContent, t);
}
return new CmisConstraintException(message, errorContent, t);
case 503:
return new CmisServiceUnavailableException(message, errorContent, t);
default:
if (CmisStorageException.EXCEPTION_NAME.equals(exception)) {
return new CmisStorageException(message, errorContent, t);
}
return new CmisRuntimeException(message, errorContent, t);
}
}
protected String extractException(String errorContent) {
if (errorContent == null) {
return null;
}
int begin = errorContent.indexOf("<!--exception-->");
int end = errorContent.indexOf("<!--/exception-->");
if (begin == -1 || end == -1 || begin > end) {
return null;
}
return errorContent.substring(begin + "<!--exception-->".length(), end);
}
protected String extractErrorMessage(String message, String errorContent) {
if (errorContent == null) {
return message;
}
int begin = errorContent.indexOf("<!--message-->");
int end = errorContent.indexOf("<!--/message-->");
if (begin == -1 || end == -1 || begin > end) {
return message;
}
return errorContent.substring(begin + "<!--message-->".length(), end);
}
// ---- helpers ----
protected boolean is(String name, AtomElement element) {
return name.equals(element.getName().getLocalPart());
}
protected boolean isStr(String name, AtomElement element) {
return is(name, element) && (element.getObject() instanceof String);
}
protected boolean isInt(String name, AtomElement element) {
return is(name, element) && (element.getObject() instanceof BigInteger);
}
protected boolean isNextLink(AtomElement element) {
return Constants.REL_NEXT.equals(((AtomLink) element.getObject()).getRel());
}
/**
* Creates a CMIS object with properties and policy IDs.
*/
protected ObjectDataImpl createObject(Properties properties, String changeToken, List<String> policies) {
ObjectDataImpl object = new ObjectDataImpl();
boolean omitChangeToken = getSession().get(SessionParameter.OMIT_CHANGE_TOKENS, false);
if (properties == null) {
properties = new PropertiesImpl();
if (changeToken != null && !omitChangeToken) {
((PropertiesImpl) properties)
.addProperty(new PropertyStringImpl(PropertyIds.CHANGE_TOKEN, changeToken));
}
} else {
if (omitChangeToken) {
if (properties.getProperties().containsKey(PropertyIds.CHANGE_TOKEN)) {
properties = new PropertiesImpl(properties);
((PropertiesImpl) properties).removeProperty(PropertyIds.CHANGE_TOKEN);
}
} else {
if (changeToken != null && !properties.getProperties().containsKey(PropertyIds.CHANGE_TOKEN)) {
properties = new PropertiesImpl(properties);
((PropertiesImpl) properties).addProperty(new PropertyStringImpl(PropertyIds.CHANGE_TOKEN,
changeToken));
}
}
}
object.setProperties(properties);
if (isNotEmpty(policies)) {
PolicyIdListImpl policyIdList = new PolicyIdListImpl();
policyIdList.setPolicyIds(policies);
object.setPolicyIds(policyIdList);
}
return object;
}
/**
* Creates a CMIS object that only contains an ID in the property list.
*/
protected ObjectData createIdObject(String objectId) {
ObjectDataImpl object = new ObjectDataImpl();
PropertiesImpl properties = new PropertiesImpl();
object.setProperties(properties);
properties.addProperty(new PropertyIdImpl(PropertyIds.OBJECT_ID, objectId));
return object;
}
/**
* Parses an input stream.
*/
@SuppressWarnings("unchecked")
protected <T extends AtomBase> T parse(InputStream stream, Class<T> clazz) {
AtomPubParser parser = new AtomPubParser(stream);
try {
parser.parse();
} catch (Exception e) {
throw new CmisConnectionException("Parsing exception!", e);
}
AtomBase parseResult = parser.getResults();
if (!clazz.isInstance(parseResult)) {
throw new CmisConnectionException("Unexpected document! Received: "
+ (parseResult == null ? "something unknown" : parseResult.getType()));
}
return (T) parseResult;
}
/**
* Performs a GET on an URL, checks the response code and returns the
* result.
*/
protected Response read(UrlBuilder url) {
// make the call
Response resp = getHttpInvoker().invokeGET(url, session);
// check response code
if (resp.getResponseCode() != 200) {
throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
}
return resp;
}
/**
* Performs a POST on an URL, checks the response code and returns the
* result.
*/
protected Response post(UrlBuilder url, String contentType, Output writer) {
// make the call
Response resp = getHttpInvoker().invokePOST(url, contentType, writer, session);
// check response code
if (resp.getResponseCode() != 201) {
throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
}
return resp;
}
/**
* Performs a PUT on an URL, checks the response code and returns the
* result.
*/
protected Response put(UrlBuilder url, String contentType, Output writer) {
return put(url, contentType, null, writer);
}
/**
* Performs a PUT on an URL, checks the response code and returns the
* result.
*/
protected Response put(UrlBuilder url, String contentType, Map<String, String> headers, Output writer) {
// make the call
Response resp = getHttpInvoker().invokePUT(url, contentType, headers, writer, session);
// check response code
if ((resp.getResponseCode() < 200) || (resp.getResponseCode() > 299)) {
throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
}
return resp;
}
/**
* Performs a DELETE on an URL, checks the response code and returns the
* result.
*/
protected void delete(UrlBuilder url) {
// make the call
Response resp = getHttpInvoker().invokeDELETE(url, session);
// check response code
if (resp.getResponseCode() != 204) {
throw convertStatusCode(resp.getResponseCode(), resp.getResponseMessage(), resp.getErrorContent(), null);
}
}
// ---- common operations ----
/**
* Checks if at least one ACE list is not empty.
*/
protected boolean isAclMergeRequired(Acl addAces, Acl removeAces) {
return (addAces != null && isNotEmpty(addAces.getAces()))
|| (removeAces != null && isNotEmpty(removeAces.getAces()));
}
/**
* Merges the new ACL from original, add and remove ACEs lists.
*/
protected Acl mergeAcls(Acl originalAces, Acl addAces, Acl removeAces) {
Map<String, Set<String>> originals = convertAclToMap(originalAces);
Map<String, Set<String>> adds = convertAclToMap(addAces);
Map<String, Set<String>> removes = convertAclToMap(removeAces);
List<Ace> newAces = new ArrayList<Ace>();
// iterate through the original ACEs
for (Map.Entry<String, Set<String>> ace : originals.entrySet()) {
// add permissions
Set<String> addPermissions = adds.get(ace.getKey());
if (addPermissions != null) {
ace.getValue().addAll(addPermissions);
}
// remove permissions
Set<String> removePermissions = removes.get(ace.getKey());
if (removePermissions != null) {
ace.getValue().removeAll(removePermissions);
}
// create new ACE
if (!ace.getValue().isEmpty()) {
newAces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(ace.getKey()),
new ArrayList<String>(ace.getValue())));
}
}
// find all ACEs that should be added but are not in the original ACE
// list
for (Map.Entry<String, Set<String>> ace : adds.entrySet()) {
if (!originals.containsKey(ace.getKey()) && !ace.getValue().isEmpty()) {
newAces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(ace.getKey()),
new ArrayList<String>(ace.getValue())));
}
}
return new AccessControlListImpl(newAces);
}
/**
* Converts a list of ACEs into Map for better handling.
*/
private static Map<String, Set<String>> convertAclToMap(Acl acl) {
Map<String, Set<String>> result = new HashMap<String, Set<String>>();
if (acl == null || acl.getAces() == null) {
return result;
}
for (Ace ace : acl.getAces()) {
// don't consider indirect ACEs - we can't change them
if (!ace.isDirect()) {
// ignore
continue;
}
// although a principal must not be null, check it
if (ace.getPrincipal() == null || ace.getPrincipal().getId() == null) {
// ignore
continue;
}
Set<String> permissions = result.get(ace.getPrincipal().getId());
if (permissions == null) {
permissions = new HashSet<String>();
result.put(ace.getPrincipal().getId(), permissions);
}
if (ace.getPermissions() != null) {
permissions.addAll(ace.getPermissions());
}
}
return result;
}
/**
* Retrieves the Service Document from the server and caches the repository
* info objects, collections, links, URI templates, etc.
*/
@SuppressWarnings("unchecked")
protected List<RepositoryInfo> getRepositoriesInternal(String repositoryId) {
List<RepositoryInfo> repInfos = new ArrayList<RepositoryInfo>();
// retrieve service doc
UrlBuilder url = new UrlBuilder(getServiceDocURL());
url.addParameter(Constants.PARAM_REPOSITORY_ID, repositoryId);
// read and parse
Response resp = read(url);
ServiceDoc serviceDoc = parse(resp.getStream(), ServiceDoc.class);
// walk through the workspaces
for (RepositoryWorkspace ws : serviceDoc.getWorkspaces()) {
if (ws.getId() == null) {
// found a non-CMIS workspace
continue;
}
for (AtomElement element : ws.getElements()) {
if (is(NAME_COLLECTION, element)) {
Map<String, String> colMap = (Map<String, String>) element.getObject();
addCollection(ws.getId(), colMap.get("collectionType"), colMap.get("href"));
} else if (element.getObject() instanceof AtomLink) {
addRepositoryLink(ws.getId(), (AtomLink) element.getObject());
} else if (is(NAME_URI_TEMPLATE, element)) {
Map<String, String> tempMap = (Map<String, String>) element.getObject();
addTemplate(ws.getId(), tempMap.get("type"), tempMap.get("template"));
} else if (element.getObject() instanceof RepositoryInfo) {
repInfos.add((RepositoryInfo) element.getObject());
}
}
}
return repInfos;
}
/**
* Retrieves an object from the server and caches the links.
*/
protected ObjectData getObjectInternal(String repositoryId, IdentifierType idOrPath, String objectIdOrPath,
ReturnVersion returnVersion, String filter, Boolean includeAllowableActions,
IncludeRelationships includeRelationships, String renditionFilter, Boolean includePolicyIds,
Boolean includeAcl, ExtensionsData extension) {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(Constants.PARAM_ID, objectIdOrPath);
parameters.put(Constants.PARAM_PATH, objectIdOrPath);
parameters.put(Constants.PARAM_RETURN_VERSION, returnVersion);
parameters.put(Constants.PARAM_FILTER, filter);
parameters.put(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
parameters.put(Constants.PARAM_ACL, includeAcl);
parameters.put(Constants.PARAM_POLICY_IDS, includePolicyIds);
parameters.put(Constants.PARAM_RELATIONSHIPS, includeRelationships);
parameters.put(Constants.PARAM_RENDITION_FILTER, renditionFilter);
String link = loadTemplateLink(repositoryId, (idOrPath == IdentifierType.ID ? Constants.TEMPLATE_OBJECT_BY_ID
: Constants.TEMPLATE_OBJECT_BY_PATH), parameters);
if (link == null) {
throw new CmisObjectNotFoundException("Unknown repository!");
}
UrlBuilder url = new UrlBuilder(link);
// workaround for missing template parameter in the CMIS spec
if (returnVersion != null && returnVersion != ReturnVersion.THIS) {
url.addParameter(Constants.PARAM_RETURN_VERSION, returnVersion);
}
// read and parse
Response resp = read(url);
AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
// we expect a CMIS entry
if (entry.getId() == null) {
throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
}
lockLinks();
ObjectData result = null;
try {
// clean up cache
removeLinks(repositoryId, entry.getId());
// walk through the entry
for (AtomElement element : entry.getElements()) {
if (element.getObject() instanceof AtomLink) {
addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
} else if (element.getObject() instanceof ObjectData) {
result = (ObjectData) element.getObject();
}
}
} finally {
unlockLinks();
}
return result;
}
/**
* Retrieves a type definition.
*/
protected TypeDefinition getTypeDefinitionInternal(String repositoryId, String typeId) {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(Constants.PARAM_ID, typeId);
String link = loadTemplateLink(repositoryId, Constants.TEMPLATE_TYPE_BY_ID, parameters);
if (link == null) {
throw new CmisObjectNotFoundException("Unknown repository!");
}
// read and parse
Response resp = read(new UrlBuilder(link));
AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
// we expect a CMIS entry
if (entry.getId() == null) {
throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
}
lockTypeLinks();
TypeDefinition result = null;
try {
// clean up cache
removeTypeLinks(repositoryId, entry.getId());
// walk through the entry
for (AtomElement element : entry.getElements()) {
if (element.getObject() instanceof AtomLink) {
addTypeLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
} else if (element.getObject() instanceof TypeDefinition) {
result = (TypeDefinition) element.getObject();
}
}
} finally {
unlockTypeLinks();
}
return result;
}
/**
* Retrieves the ACL of an object.
*/
public Acl getAclInternal(String repositoryId, String objectId, Boolean onlyBasicPermissions,
ExtensionsData extension) {
// find the link
String link = loadLink(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
if (link == null) {
throwLinkException(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
}
UrlBuilder url = new UrlBuilder(link);
url.addParameter(Constants.PARAM_ONLY_BASIC_PERMISSIONS, onlyBasicPermissions);
// read and parse
Response resp = read(url);
AtomAcl acl = parse(resp.getStream(), AtomAcl.class);
return acl.getACL();
}
/**
* Updates the ACL of an object.
*/
protected AtomAcl updateAcl(String repositoryId, String objectId, final Acl acl, AclPropagation aclPropagation) {
// find the link
String link = loadLink(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
if (link == null) {
throwLinkException(repositoryId, objectId, Constants.REL_ACL, Constants.MEDIATYPE_ACL);
}
UrlBuilder aclUrl = new UrlBuilder(link);
aclUrl.addParameter(Constants.PARAM_ACL_PROPAGATION, aclPropagation);
final CmisVersion cmisVersion = getCmisVersion(repositoryId);
// update
Response resp = put(aclUrl, Constants.MEDIATYPE_ACL, new Output() {
public void write(OutputStream out) throws Exception {
XMLStreamWriter writer = XMLUtils.createWriter(out);
XMLUtils.startXmlDocument(writer);
XMLConverter.writeAcl(writer, cmisVersion, true, acl);
XMLUtils.endXmlDocument(writer);
}
});
// parse new entry
return parse(resp.getStream(), AtomAcl.class);
}
}