All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.chemistry.opencmis.client.runtime.SessionImpl Maven / Gradle / Ivy

The newest version!
/*
 * 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.runtime;

import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNullOrEmpty;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.chemistry.opencmis.client.api.ChangeEvent;
import org.apache.chemistry.opencmis.client.api.ChangeEvents;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.DocumentType;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.client.api.ObjectFactory;
import org.apache.chemistry.opencmis.client.api.ObjectId;
import org.apache.chemistry.opencmis.client.api.ObjectType;
import org.apache.chemistry.opencmis.client.api.OperationContext;
import org.apache.chemistry.opencmis.client.api.Policy;
import org.apache.chemistry.opencmis.client.api.QueryResult;
import org.apache.chemistry.opencmis.client.api.QueryStatement;
import org.apache.chemistry.opencmis.client.api.Relationship;
import org.apache.chemistry.opencmis.client.api.SecondaryType;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.client.api.Tree;
import org.apache.chemistry.opencmis.client.bindings.cache.TypeDefinitionCache;
import org.apache.chemistry.opencmis.client.runtime.cache.Cache;
import org.apache.chemistry.opencmis.client.runtime.cache.CacheImpl;
import org.apache.chemistry.opencmis.client.runtime.repository.ObjectFactoryImpl;
import org.apache.chemistry.opencmis.client.runtime.util.AbstractPageFetcher;
import org.apache.chemistry.opencmis.client.runtime.util.CollectionIterable;
import org.apache.chemistry.opencmis.client.runtime.util.TreeImpl;
import org.apache.chemistry.opencmis.client.util.OperationContextUtils;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.apache.chemistry.opencmis.commons.SessionParameterDefaults;
import org.apache.chemistry.opencmis.commons.data.Ace;
import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.BulkUpdateObjectIdAndChangeToken;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
import org.apache.chemistry.opencmis.commons.data.ObjectData;
import org.apache.chemistry.opencmis.commons.data.ObjectList;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
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.BindingType;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
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.Updatability;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.BulkUpdateObjectIdAndChangeTokenImpl;
import org.apache.chemistry.opencmis.commons.spi.AclService;
import org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider;
import org.apache.chemistry.opencmis.commons.spi.CmisBinding;
import org.apache.chemistry.opencmis.commons.spi.DiscoveryService;
import org.apache.chemistry.opencmis.commons.spi.ExtendedAclService;
import org.apache.chemistry.opencmis.commons.spi.ExtendedHolder;
import org.apache.chemistry.opencmis.commons.spi.ExtendedRepositoryService;
import org.apache.chemistry.opencmis.commons.spi.Holder;
import org.apache.chemistry.opencmis.commons.spi.NavigationService;
import org.apache.chemistry.opencmis.commons.spi.RelationshipService;
import org.apache.chemistry.opencmis.commons.spi.RepositoryService;

/**
 * Persistent model session.
 */
public class SessionImpl implements Session {

    private static final OperationContext DEFAULT_CONTEXT = new OperationContextImpl(null, false, true, false,
            IncludeRelationships.NONE, null, true, null, true, 100);

    private static final Set CREATE_UPDATABILITY = EnumSet.noneOf(Updatability.class);
    private static final Set CREATE_AND_CHECKOUT_UPDATABILITY = EnumSet.noneOf(Updatability.class);

    static {
        CREATE_UPDATABILITY.add(Updatability.ONCREATE);
        CREATE_UPDATABILITY.add(Updatability.READWRITE);
        CREATE_AND_CHECKOUT_UPDATABILITY.add(Updatability.ONCREATE);
        CREATE_AND_CHECKOUT_UPDATABILITY.add(Updatability.READWRITE);
        CREATE_AND_CHECKOUT_UPDATABILITY.add(Updatability.WHENCHECKEDOUT);
    }

    // private static Logger log = LoggerFactory.getLogger(SessionImpl.class);
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private transient LinkedHashMap objectTypeCache;

    /*
     * default session context (serializable)
     */
    private OperationContext defaultContext = DEFAULT_CONTEXT;

    /*
     * session parameter (serializable)
     */
    private Map parameters;

    /*
     * CMIS binding (serializable)
     */
    private CmisBinding binding;

    /*
     * Session Locale, determined from session parameter (serializable)
     */
    private Locale locale;

    /*
     * Object factory (serializable)
     */
    private final ObjectFactory objectFactory;

    /*
     * Authentication provider (serializable)
     */
    private final AuthenticationProvider authenticationProvider;

    /*
     * Object cache (serializable)
     */
    private Cache cache;
    private final boolean cachePathOmit;

    /*
     * Type cache.
     */
    private TypeDefinitionCache typeDefCache;

    /*
     * Repository info (serializable)
     */
    private RepositoryInfo repositoryInfo;

    /**
     * required for serialization
     */
    private static final long serialVersionUID = 1L;

    /**
     * Constructor.
     */
    public SessionImpl(Map parameters, ObjectFactory objectFactory,
            AuthenticationProvider authenticationProvider, Cache cache, TypeDefinitionCache typeDefCache) {
        if (parameters == null) {
            throw new IllegalArgumentException("No parameters provided!");
        }

        this.parameters = parameters;
        this.locale = determineLocale(parameters);

        this.objectFactory = objectFactory == null ? createObjectFactory() : objectFactory;
        this.authenticationProvider = authenticationProvider;
        this.cache = cache == null ? createCache() : cache;
        this.typeDefCache = typeDefCache;

        cachePathOmit = Boolean.parseBoolean(parameters.get(SessionParameter.CACHE_PATH_OMIT));
    }

    private Locale determineLocale(Map parameters) {
        Locale result;

        String language = parameters.get(SessionParameter.LOCALE_ISO639_LANGUAGE);
        String country = parameters.get(SessionParameter.LOCALE_ISO3166_COUNTRY);
        String variant = parameters.get(SessionParameter.LOCALE_VARIANT);

        if (variant != null) {
            // all 3 parameter must not be null and valid
            result = new Locale(language, country, variant);
        } else if (country != null) {
            // 2 parameter must not be null and valid
            result = new Locale(language, country);
        } else if (language != null) {
            // 1 parameter must not be null and valid
            result = new Locale(language);
        } else {
            result = Locale.getDefault();
        }

        return result;
    }

    private ObjectFactory createObjectFactory() {
        try {
            String classname = parameters.get(SessionParameter.OBJECT_FACTORY_CLASS);

            Class objectFactoryClass;
            if (classname == null) {
                objectFactoryClass = ObjectFactoryImpl.class;
            } else {
                objectFactoryClass = ClassLoaderUtil.loadClass(classname);
            }

            Object of = objectFactoryClass.newInstance();
            if (!(of instanceof ObjectFactory)) {
                throw new InstantiationException("Class does not implement ObjectFactory!");
            }

            ((ObjectFactory) of).initialize(this, parameters);

            return (ObjectFactory) of;
        } catch (Exception e) {
            throw new IllegalArgumentException("Unable to create object factory: " + e, e);
        }
    }

    private Cache createCache() {
        try {
            String classname = parameters.get(SessionParameter.CACHE_CLASS);

            Class cacheClass;
            if (classname == null) {
                cacheClass = CacheImpl.class;
            } else {
                cacheClass = ClassLoaderUtil.loadClass(classname);
            }

            Object of = cacheClass.newInstance();
            if (!(of instanceof Cache)) {
                throw new InstantiationException("Class does not implement Cache!");
            }

            ((Cache) of).initialize(this, parameters);

            return (Cache) of;
        } catch (Exception e) {
            throw new IllegalArgumentException("Unable to create cache: " + e, e);
        }
    }

    @Override
    public Map getSessionParameters() {
        return Collections.unmodifiableMap(parameters);
    }

    @Override
    public void clear() {
        lock.writeLock().lock();
        try {
            // create new object cache
            cache = createCache();

            // clear object type cache
            objectTypeCache = null;

            // clear provider cache
            getBinding().clearAllCaches();
        } finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public ObjectFactory getObjectFactory() {
        assert objectFactory != null;
        return objectFactory;
    }

    @Override
    public ItemIterable getCheckedOutDocs() {
        return getCheckedOutDocs(getDefaultContext());
    }

    @Override
    public ItemIterable getCheckedOutDocs(OperationContext context) {
        checkContext(context);

        final NavigationService navigationService = getBinding().getNavigationService();
        final ObjectFactory of = getObjectFactory();
        final OperationContext ctxt = new OperationContextImpl(context);

        return new CollectionIterable(new AbstractPageFetcher(ctxt.getMaxItemsPerPage()) {

            @Override
            protected AbstractPageFetcher.Page fetchPage(long skipCount) {

                // get all checked out documents
                ObjectList checkedOutDocs = navigationService.getCheckedOutDocs(getRepositoryId(), null,
                        ctxt.getFilterString(), ctxt.getOrderBy(), ctxt.isIncludeAllowableActions(),
                        ctxt.getIncludeRelationships(), ctxt.getRenditionFilterString(),
                        BigInteger.valueOf(this.maxNumItems), BigInteger.valueOf(skipCount), null);

                // convert objects
                List page = new ArrayList();
                if (checkedOutDocs.getObjects() != null) {
                    for (ObjectData objectData : checkedOutDocs.getObjects()) {
                        CmisObject doc = of.convertObject(objectData, ctxt);
                        if (!(doc instanceof Document)) {
                            // should not happen...
                            continue;
                        }

                        page.add((Document) doc);
                    }
                }

                return new AbstractPageFetcher.Page(page, checkedOutDocs.getNumItems(),
                        checkedOutDocs.hasMoreItems());
            }
        });
    }

    @Override
    public ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems) {
        return getContentChanges(changeLogToken, includeProperties, maxNumItems, getDefaultContext());
    }

    @Override
    public ChangeEvents getContentChanges(String changeLogToken, boolean includeProperties, long maxNumItems,
            OperationContext context) {
        checkContext(context);

        Holder changeLogTokenHolder = new Holder(changeLogToken);
        ObjectList objectList = null;

        lock.readLock().lock();
        try {
            objectList = getBinding().getDiscoveryService().getContentChanges(getRepositoryInfo().getId(),
                    changeLogTokenHolder, includeProperties, context.getFilterString(), context.isIncludePolicies(),
                    context.isIncludeAcls(), BigInteger.valueOf(maxNumItems), null);
        } finally {
            lock.readLock().unlock();
        }

        return objectFactory.convertChangeEvents(changeLogTokenHolder.getValue(), objectList);
    }

    @Override
    public ItemIterable getContentChanges(String changeLogToken, final boolean includeProperties) {
        return getContentChanges(changeLogToken, includeProperties, getDefaultContext());
    }

    @Override
    public ItemIterable getContentChanges(final String changeLogToken, final boolean includeProperties,
            OperationContext context) {
        checkContext(context);

        final DiscoveryService discoveryService = getBinding().getDiscoveryService();
        final ObjectFactory of = getObjectFactory();
        final OperationContext ctxt = new OperationContextImpl(context);

        return new CollectionIterable(new AbstractPageFetcher(Integer.MAX_VALUE) {

            private String token = changeLogToken;
            private String nextLink = null;
            private boolean firstPage = true;

            @Override
            protected AbstractPageFetcher.Page fetchPage(long skipCount) {
                assert firstPage || token != null ? (nextLink == null) : true;

                // fetch the data
                ExtendedHolder changeLogTokenHolder = new ExtendedHolder(token);
                if (nextLink != null) {
                    changeLogTokenHolder.setExtraValue(Constants.REP_REL_CHANGES, nextLink);
                }

                ObjectList objectList = discoveryService.getContentChanges(getRepositoryInfo().getId(),
                        changeLogTokenHolder, includeProperties, ctxt.getFilterString(), ctxt.isIncludePolicies(),
                        ctxt.isIncludeAcls(), BigInteger.valueOf(this.maxNumItems), null);

                // convert type definitions
                List page = new ArrayList();
                for (ObjectData objectData : objectList.getObjects()) {
                    page.add(of.convertChangeEvent(objectData));
                }

                if (!firstPage) {
                    // the last entry of the previous page is repeated
                    // -> remove the first entry
                    page.remove(0);
                }
                firstPage = false;

                if (changeLogTokenHolder.getValue() != null) {
                    // the web services and the browser binding
                    // return a new token
                    token = changeLogTokenHolder.getValue();
                } else {
                    // the atompub binding does not return a new token,
                    // but might return a link to the next Atom feed
                    token = null;
                    nextLink = (String) changeLogTokenHolder.getExtraValue(Constants.REP_REL_CHANGES);
                }

                return new AbstractPageFetcher.Page(page, objectList.getNumItems(),
                        objectList.hasMoreItems()) {
                };
            }
        }) {

            @Override
            public ItemIterable skipTo(long position) {
                throw new CmisNotSupportedException("Skipping not supported!");
            }

            @Override
            public ItemIterable getPage() {
                throw new CmisNotSupportedException("Paging not supported!");
            }

            @Override
            public ItemIterable getPage(int maxNumItems) {
                throw new CmisNotSupportedException("Paging not supported!");
            }

        };
    }

    @Override
    public String getLatestChangeLogToken() {
        return getBinding().getRepositoryService().getRepositoryInfo(getRepositoryId(), null).getLatestChangeLogToken();
    }

    @Override
    public OperationContext getDefaultContext() {
        lock.readLock().lock();
        try {
            return defaultContext;
        } finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public void setDefaultContext(OperationContext context) {
        lock.writeLock().lock();
        try {
            this.defaultContext = context == null ? DEFAULT_CONTEXT : context;
        } finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public OperationContext createOperationContext(Set filter, boolean includeAcls,
            boolean includeAllowableActions, boolean includePolicies, IncludeRelationships includeRelationships,
            Set renditionFilter, boolean includePathSegments, String orderBy, boolean cacheEnabled,
            int maxItemsPerPage) {
        return OperationContextUtils.createOperationContext(filter, includeAcls, includeAllowableActions,
                includePolicies, includeRelationships, renditionFilter, includePathSegments, orderBy, cacheEnabled,
                maxItemsPerPage);
    }

    @Override
    public OperationContext createOperationContext() {
        return OperationContextUtils.createOperationContext();
    }

    @Override
    public ObjectId createObjectId(String id) {
        return new ObjectIdImpl(id);
    }

    @Override
    public Locale getLocale() {
        return locale;
    }

    @Override
    public CmisObject getObject(ObjectId objectId) {
        return getObject(objectId, getDefaultContext());
    }

    @Override
    public CmisObject getObject(ObjectId objectId, OperationContext context) {
        checkObjectId(objectId);
        return getObject(objectId.getId(), context);
    }

    @Override
    public CmisObject getObject(String objectId) {
        return getObject(objectId, getDefaultContext());
    }

    @Override
    public CmisObject getObject(String objectId, OperationContext context) {
        checkObjectId(objectId);
        checkContext(context);

        CmisObject result = null;

        // ask the cache first
        if (context.isCacheEnabled()) {
            result = cache.getById(objectId, context.getCacheKey());
            if (result != null) {
                return result;
            }
        }

        // get the object
        ObjectData objectData = binding.getObjectService().getObject(getRepositoryId(), objectId,
                context.getFilterString(), context.isIncludeAllowableActions(), context.getIncludeRelationships(),
                context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);

        result = getObjectFactory().convertObject(objectData, context);

        // put into cache
        if (context.isCacheEnabled()) {
            cache.put(result, context.getCacheKey());
        }

        return result;
    }

    @Override
    public CmisObject getObjectByPath(String path) {
        return getObjectByPath(path, getDefaultContext());
    }

    @Override
    public CmisObject getObjectByPath(String path, OperationContext context) {
        checkPath(path);
        checkContext(context);

        CmisObject result = null;

        // ask the cache first
        if (context.isCacheEnabled() && !cachePathOmit) {
            result = cache.getByPath(path, context.getCacheKey());
            if (result != null) {
                return result;
            }
        }

        // get the object
        ObjectData objectData = binding.getObjectService().getObjectByPath(getRepositoryId(), path,
                context.getFilterString(), context.isIncludeAllowableActions(), context.getIncludeRelationships(),
                context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);

        result = getObjectFactory().convertObject(objectData, context);

        // put into cache
        if (context.isCacheEnabled()) {
            cache.putPath(path, result, context.getCacheKey());
        }

        return result;
    }

    @Override
    public CmisObject getObjectByPath(String parentPath, String name) {
        return getObjectByPath(parentPath, name, getDefaultContext());
    }

    @Override
    public CmisObject getObjectByPath(String parentPath, String name, OperationContext context) {
        return getObjectByPath(buildPath(parentPath, name), context);
    }

    @Override
    public Document getLatestDocumentVersion(ObjectId objectId) {
        return getLatestDocumentVersion(objectId, false, getDefaultContext());
    }

    @Override
    public Document getLatestDocumentVersion(String objectId, OperationContext context) {
        checkDocumentId(objectId);
        return getLatestDocumentVersion(createObjectId(objectId), false, context);
    }

    @Override
    public Document getLatestDocumentVersion(String objectId, boolean major, OperationContext context) {
        checkDocumentId(objectId);
        return getLatestDocumentVersion(createObjectId(objectId), major, context);
    }

    @Override
    public Document getLatestDocumentVersion(String objectId) {
        checkDocumentId(objectId);
        return getLatestDocumentVersion(createObjectId(objectId), false, getDefaultContext());
    }

    @Override
    public Document getLatestDocumentVersion(ObjectId objectId, OperationContext context) {
        return getLatestDocumentVersion(objectId, false, context);
    }

    @Override
    public Document getLatestDocumentVersion(ObjectId objectId, boolean major, OperationContext context) {
        checkDocumentId(objectId);
        checkContext(context);

        CmisObject result = null;

        String versionSeriesId = null;

        // first attempt: if we got a Document object, try getting the version
        // series ID from it
        if (objectId instanceof Document) {
            Document sourceDoc = (Document) objectId;

            if (!sourceDoc.isVersionable()) {
                // if it is not versionable, a getObject() is sufficient
                return (Document) getObject(sourceDoc, context);
            }

            versionSeriesId = sourceDoc.getVersionSeriesId();
        }

        // second attempt: if we have a Document object in the cache, retrieve
        // the version series ID form there
        if (versionSeriesId == null) {
            if (context.isCacheEnabled()) {
                CmisObject sourceObj = cache.getById(objectId.getId(), context.getCacheKey());
                if (sourceObj instanceof Document) {
                    Document sourceDoc = (Document) sourceObj;

                    if (!sourceDoc.isVersionable()) {
                        // if it is not versionable, a getObject() is sufficient
                        return (Document) getObject(sourceDoc, context);
                    }

                    versionSeriesId = sourceDoc.getVersionSeriesId();
                }
            }
        }

        // third attempt (Web Services only): get the version series ID from the
        // repository
        // (the AtomPub and Browser binding don't need the version series ID ->
        // avoid roundtrip)
        if (versionSeriesId == null) {
            BindingType bindingType = getBinding().getBindingType();
            if (bindingType == BindingType.WEBSERVICES || bindingType == BindingType.CUSTOM) {

                // get the document to find the version series ID
                ObjectData sourceObjectData = binding.getObjectService().getObject(getRepositoryId(), objectId.getId(),
                        PropertyIds.OBJECT_ID + "," + PropertyIds.OBJECT_TYPE_ID + "," + PropertyIds.VERSION_SERIES_ID,
                        false, IncludeRelationships.NONE, "cmis:none", false, false, null);

                String objectTypeId = null;

                if (sourceObjectData.getProperties() != null
                        && sourceObjectData.getProperties().getProperties() != null) {

                    PropertyData objectTypeIdProp = sourceObjectData.getProperties().getProperties()
                            .get(PropertyIds.OBJECT_TYPE_ID);
                    if (objectTypeIdProp != null && objectTypeIdProp.getFirstValue() instanceof String) {
                        objectTypeId = (String) objectTypeIdProp.getFirstValue();
                    }

                    PropertyData verionsSeriesIdProp = sourceObjectData.getProperties().getProperties()
                            .get(PropertyIds.VERSION_SERIES_ID);
                    if (verionsSeriesIdProp != null && verionsSeriesIdProp.getFirstValue() instanceof String) {
                        versionSeriesId = (String) verionsSeriesIdProp.getFirstValue();
                    }
                }

                // the Web Services binding needs the version series ID
                if (versionSeriesId == null) {

                    ObjectType type = getTypeDefinition(objectTypeId);
                    if (type instanceof DocumentType && Boolean.FALSE.equals(((DocumentType) type).isVersionable())) {
                        // if the document is not versionable, we don't need a
                        // version series ID
                        return (Document) getObject(objectId, context);
                    }

                    throw new IllegalArgumentException("Object is not a document or not versionable!");
                }
            }
        }

        // get the object
        ObjectData objectData = binding.getVersioningService().getObjectOfLatestVersion(getRepositoryId(),
                objectId.getId(), versionSeriesId, major, context.getFilterString(),
                context.isIncludeAllowableActions(), context.getIncludeRelationships(),
                context.getRenditionFilterString(), context.isIncludePolicies(), context.isIncludeAcls(), null);

        result = getObjectFactory().convertObject(objectData, context);

        // put into cache
        if (context.isCacheEnabled()) {
            cache.put(result, context.getCacheKey());
        }

        // check result
        if (!(result instanceof Document)) {
            throw new IllegalArgumentException("Latest version is not a document!");
        }

        return (Document) result;
    }

    @Override
    public boolean exists(ObjectId objectId) {
        checkObjectId(objectId);
        return exists(objectId.getId());
    }

    @Override
    public boolean exists(String objectId) {
        checkObjectId(objectId);

        try {
            binding.getObjectService().getObject(getRepositoryId(), objectId, "cmis:objectId", Boolean.FALSE,
                    IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, null);
            return true;
        } catch (CmisObjectNotFoundException onf) {
            removeObjectFromCache(objectId);
            return false;
        }
    }

    @Override
    public boolean existsPath(String path) {
        checkPath(path);

        try {
            String objectId = getObjectIdByPath(path);
            String cacheObjectId = cache.getObjectIdByPath(path);

            if (cacheObjectId != null && !cacheObjectId.equals(objectId)) {
                cache.removePath(path);
            }

            return true;
        } catch (CmisObjectNotFoundException onf) {
            return false;
        }
    }

    @Override
    public boolean existsPath(String parentPath, String name) {
        return existsPath(buildPath(parentPath, name));
    }

    @Override
    public void removeObjectFromCache(ObjectId objectId) {
        checkObjectId(objectId);
        removeObjectFromCache(objectId.getId());
    }

    @Override
    public void removeObjectFromCache(String objectId) {
        cache.remove(objectId);
    }

    @Override
    public RepositoryInfo getRepositoryInfo() {
        lock.readLock().lock();
        try {
            return repositoryInfo;
        } finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public Folder getRootFolder() {
        return getRootFolder(getDefaultContext());
    }

    @Override
    public Folder getRootFolder(OperationContext context) {
        String rootFolderId = getRepositoryInfo().getRootFolderId();

        CmisObject rootFolder = getObject(rootFolderId, context);
        if (!(rootFolder instanceof Folder)) {
            throw new CmisRuntimeException("Root folder object is not a folder!");
        }

        return (Folder) rootFolder;
    }

    @Override
    public ItemIterable getTypeChildren(final String typeId, final boolean includePropertyDefinitions) {
        final RepositoryService repositoryService = getBinding().getRepositoryService();

        return new CollectionIterable(
                new AbstractPageFetcher(getDefaultContext().getMaxItemsPerPage()) {

                    @Override
                    protected AbstractPageFetcher.Page fetchPage(long skipCount) {

                        // fetch the data
                        TypeDefinitionList tdl = repositoryService.getTypeChildren(SessionImpl.this.getRepositoryId(),
                                typeId, includePropertyDefinitions, BigInteger.valueOf(this.maxNumItems),
                                BigInteger.valueOf(skipCount), null);

                        // convert type definitions
                        List page = new ArrayList(tdl.getList().size());
                        for (TypeDefinition typeDefinition : tdl.getList()) {
                            page.add(convertTypeDefinition(typeDefinition));
                        }

                        return new AbstractPageFetcher.Page(page, tdl.getNumItems(), tdl.hasMoreItems()) {
                        };
                    }
                });
    }

    @Override
    public ObjectType getTypeDefinition(String typeId) {
        TypeDefinition typeDefinition = getBinding().getRepositoryService().getTypeDefinition(getRepositoryId(), typeId,
                null);

        return convertAndCacheTypeDefinition(typeDefinition, true);
    }

    @Override
    public ObjectType getTypeDefinition(String typeId, boolean useCache) {
        RepositoryService service = getBinding().getRepositoryService();
        if (!(service instanceof ExtendedRepositoryService)) {
            throw new CmisRuntimeException(
                    "Internal error: Repository Service does not implement ExtendedRepositoryService!");
        }

        ExtendedRepositoryService extRepSrv = (ExtendedRepositoryService) service;
        TypeDefinition typeDefinition = extRepSrv.getTypeDefinition(getRepositoryId(), typeId, null, useCache);

        return convertAndCacheTypeDefinition(typeDefinition, useCache);
    }

    @Override
    public List> getTypeDescendants(String typeId, int depth, boolean includePropertyDefinitions) {
        List descendants = getBinding().getRepositoryService().getTypeDescendants(
                getRepositoryId(), typeId, BigInteger.valueOf(depth), includePropertyDefinitions, null);

        return convertTypeDescendants(descendants);
    }

    /**
     * Converts binding TypeDefinitionContainer to API
     * Container.
     */
    private List> convertTypeDescendants(List descendantsList) {
        List> result = new ArrayList>();

        for (TypeDefinitionContainer container : descendantsList) {
            ObjectType objectType = convertTypeDefinition(container.getTypeDefinition());
            List> children = convertTypeDescendants(container.getChildren());

            result.add(new TreeImpl(objectType, children));
        }

        return result;
    }

    private ObjectType convertTypeDefinition(TypeDefinition typeDefinition) {
        return objectFactory.convertTypeDefinition(typeDefinition);
    }

    /**
     * Converts a type definition into an object type and caches the result.
     *
     * The cache should only be used for type definitions that have been fetched
     * with getTypeDefinition() because the high level cache should roughly
     * correspond to the low level type cache. The type definitions returned by
     * getTypeChildren() and getTypeDescendants() are not cached in the low
     * level cache and therefore shouldn't be cached here.
     */
    private ObjectType convertAndCacheTypeDefinition(TypeDefinition typeDefinition, boolean useCache) {
        ObjectType result = null;

        lock.writeLock().lock();
        try {
            if (objectTypeCache == null) {
                int cacheSize;
                try {
                    cacheSize = Integer.valueOf(parameters.get(SessionParameter.CACHE_SIZE_TYPES));
                    if (cacheSize < 0) {
                        cacheSize = SessionParameterDefaults.CACHE_SIZE_TYPES;
                    }
                } catch (NumberFormatException nfe) {
                    cacheSize = SessionParameterDefaults.CACHE_SIZE_TYPES;
                }

                final int maxEntries = cacheSize;

                objectTypeCache = new LinkedHashMap(maxEntries + 1, 0.70f, true) {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public boolean removeEldestEntry(Map.Entry eldest) {
                        return size() > maxEntries;
                    }
                };
            }

            if (!useCache) {
                result = objectFactory.convertTypeDefinition(typeDefinition);
                objectTypeCache.put(result.getId(), result);
            } else {
                result = objectTypeCache.get(typeDefinition.getId());
                if (result == null) {
                    result = objectFactory.convertTypeDefinition(typeDefinition);
                    objectTypeCache.put(result.getId(), result);
                }
            }

            return result;
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     * Removes the object type object with the given type ID from the cache.
     */
    private void removeFromObjectTypeCache(String typeId) {
        lock.writeLock().lock();
        try {
            if (objectTypeCache != null) {
                objectTypeCache.remove(typeId);
            }
        } finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public ObjectType createType(TypeDefinition type) {
        checkCmisVersion();

        TypeDefinition newType = getBinding().getRepositoryService().createType(getRepositoryId(), type, null);
        return convertTypeDefinition(newType);
    }

    @Override
    public ObjectType updateType(TypeDefinition type) {
        checkCmisVersion();

        TypeDefinition updatedType = getBinding().getRepositoryService().updateType(getRepositoryId(), type, null);

        removeFromObjectTypeCache(updatedType.getId());

        return convertTypeDefinition(updatedType);
    }

    @Override
    public void deleteType(String typeId) {
        checkCmisVersion();

        getBinding().getRepositoryService().deleteType(getRepositoryId(), typeId, null);
        removeFromObjectTypeCache(typeId);
    }

    @Override
    public ItemIterable query(final String statement, final boolean searchAllVersions) {
        return query(statement, searchAllVersions, getDefaultContext());
    }

    @Override
    public ItemIterable query(final String statement, final boolean searchAllVersions,
            OperationContext context) {
        checkContext(context);

        final DiscoveryService discoveryService = getBinding().getDiscoveryService();
        final ObjectFactory of = getObjectFactory();
        final OperationContext ctxt = new OperationContextImpl(context);

        return new CollectionIterable(new AbstractPageFetcher(ctxt.getMaxItemsPerPage()) {

            @Override
            protected AbstractPageFetcher.Page fetchPage(long skipCount) {

                // fetch the data
                ObjectList resultList = discoveryService.query(getRepositoryId(), statement, searchAllVersions,
                        ctxt.isIncludeAllowableActions(), ctxt.getIncludeRelationships(),
                        ctxt.getRenditionFilterString(), BigInteger.valueOf(this.maxNumItems),
                        BigInteger.valueOf(skipCount), null);

                // convert query results
                List page = new ArrayList();
                if (resultList.getObjects() != null) {
                    for (ObjectData objectData : resultList.getObjects()) {
                        if (objectData == null) {
                            continue;
                        }

                        page.add(of.convertQueryResult(objectData));
                    }
                }

                return new AbstractPageFetcher.Page(page, resultList.getNumItems(),
                        resultList.hasMoreItems());
            }
        });
    }

    @Override
    public ItemIterable queryObjects(String typeId, String where, final boolean searchAllVersions,
            OperationContext context) {
        if (typeId == null || typeId.trim().length() == 0) {
            throw new IllegalArgumentException("Type ID must be set!");
        }

        checkContext(context);

        final DiscoveryService discoveryService = getBinding().getDiscoveryService();
        final ObjectFactory of = getObjectFactory();
        final OperationContext ctxt = new OperationContextImpl(context);
        final StringBuilder statement = new StringBuilder(1024);

        statement.append("SELECT ");

        String select = ctxt.getFilterString();
        if (select == null) {
            statement.append('*');
        } else {
            statement.append(select);
        }

        final ObjectType type = getTypeDefinition(typeId);
        statement.append(" FROM ");
        statement.append(type.getQueryName());

        if (where != null && where.trim().length() > 0) {
            statement.append(" WHERE ");
            statement.append(where);
        }

        String orderBy = ctxt.getOrderBy();
        if (orderBy != null && orderBy.trim().length() > 0) {
            statement.append(" ORDER BY ");
            statement.append(orderBy);
        }

        return new CollectionIterable(new AbstractPageFetcher(ctxt.getMaxItemsPerPage()) {

            @Override
            protected AbstractPageFetcher.Page fetchPage(long skipCount) {

                // fetch the data
                ObjectList resultList = discoveryService.query(getRepositoryId(), statement.toString(),
                        searchAllVersions, ctxt.isIncludeAllowableActions(), ctxt.getIncludeRelationships(),
                        ctxt.getRenditionFilterString(), BigInteger.valueOf(this.maxNumItems),
                        BigInteger.valueOf(skipCount), null);

                // convert query results
                List page = new ArrayList();
                if (resultList.getObjects() != null) {
                    for (ObjectData objectData : resultList.getObjects()) {
                        if (objectData == null) {
                            continue;
                        }

                        page.add(of.convertObject(objectData, ctxt));
                    }
                }

                return new AbstractPageFetcher.Page(page, resultList.getNumItems(),
                        resultList.hasMoreItems());
            }
        });
    }

    @Override
    public QueryStatement createQueryStatement(final String statement) {
        return new QueryStatementImpl(this, statement);
    }

    @Override
    public QueryStatement createQueryStatement(final Collection selectPropertyIds,
            final Map fromTypes, final String whereClause, final List orderByPropertyIds) {
        return new QueryStatementImpl(this, selectPropertyIds, fromTypes, whereClause, orderByPropertyIds);
    }

    /**
     * Connect session object to the provider. This is the very first call after
     * a session is created.
     * 

* In dependency of the parameter set an {@code AtomPub}, a * {@code WebService} or an {@code InMemory} provider is selected. */ public void connect() { lock.writeLock().lock(); try { binding = CmisBindingHelper.createBinding(parameters, authenticationProvider, typeDefCache); /* get initial repository ID from session parameter */ String repositoryId = parameters.get(SessionParameter.REPOSITORY_ID); if (repositoryId == null) { throw new IllegalStateException("Repository ID is not set!"); } repositoryInfo = objectFactory .convertRepositoryInfo(getBinding().getRepositoryService().getRepositoryInfo(repositoryId, null)); } finally { lock.writeLock().unlock(); } } @Override public CmisBinding getBinding() { lock.readLock().lock(); try { return binding; } finally { lock.readLock().unlock(); } } public Cache getCache() { lock.readLock().lock(); try { return cache; } finally { lock.readLock().unlock(); } } /** * Returns the repository id. */ public String getRepositoryId() { return getRepositoryInfo().getId(); } // --- creates --- @Override public ObjectId createDocument(Map properties, ObjectId folderId, ContentStream contentStream, VersioningState versioningState, List policies, List addAces, List removeAces) { checkProperties(properties); String newId = getBinding().getObjectService().createDocument(getRepositoryId(), objectFactory.convertProperties(properties, null, null, CREATE_AND_CHECKOUT_UPDATABILITY), (folderId == null ? null : folderId.getId()), objectFactory.convertContentStream(contentStream), versioningState, objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null); if (newId == null) { return null; } return createObjectId(newId); } @Override public ObjectId createDocumentFromSource(ObjectId source, Map properties, ObjectId folderId, VersioningState versioningState, List policies, List addAces, List removeAces) { if (source == null || source.getId() == null) { throw new IllegalArgumentException("Source must be set!"); } // get the type of the source document ObjectType type = null; List secondaryTypes = null; if (source instanceof CmisObject) { type = ((CmisObject) source).getType(); secondaryTypes = ((CmisObject) source).getSecondaryTypes(); } else { CmisObject sourceObj = getObject(source); type = sourceObj.getType(); secondaryTypes = sourceObj.getSecondaryTypes(); } if (type.getBaseTypeId() != BaseTypeId.CMIS_DOCUMENT) { throw new IllegalArgumentException("Source object must be a document!"); } String newId = getBinding().getObjectService().createDocumentFromSource(getRepositoryId(), source.getId(), objectFactory.convertProperties(properties, type, secondaryTypes, CREATE_AND_CHECKOUT_UPDATABILITY), (folderId == null ? null : folderId.getId()), versioningState, objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null); if (newId == null) { return null; } return createObjectId(newId); } @Override public ObjectId createFolder(Map properties, ObjectId folderId, List policies, List addAces, List removeAces) { checkFolderId(folderId); checkProperties(properties); String newId = getBinding().getObjectService().createFolder(getRepositoryId(), objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY), folderId.getId(), objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null); if (newId == null) { return null; } return createObjectId(newId); } @Override public ObjectId createPath(String newPath, String typeId) { return createPath(null, newPath, typeId); } @Override public ObjectId createPath(ObjectId startFolderId, String newPath, String typeId) { Map properties = new HashMap(); properties.put(PropertyIds.OBJECT_TYPE_ID, typeId); return createPath(startFolderId, newPath, properties, null, null, null); } @Override public ObjectId createPath(String newPath, Map properties) { return createPath(null, newPath, properties); } @Override public ObjectId createPath(ObjectId startFolderId, String newPath, Map properties) { return createPath(startFolderId, newPath, properties, null, null, null); } @Override public ObjectId createPath(ObjectId startFolderId, String newPath, Map properties, List policies, List addAces, List removeAces) { checkPath(newPath); if (newPath.length() == 1) { throw new IllegalArgumentException("Cannot create root folder!"); } if (newPath.charAt(newPath.length() - 1) == '/') { throw new IllegalArgumentException("Path cannot end with a '/'!"); } checkProperties(properties); if (!(properties.get(PropertyIds.OBJECT_TYPE_ID) instanceof String)) { throw new IllegalArgumentException("Property '" + PropertyIds.OBJECT_TYPE_ID + "' not set or invalid!"); } StringBuilder nextPath = new StringBuilder(newPath.length()); String[] segements; ObjectId lastFolderId = null; boolean create = false; // check start folder if (startFolderId != null && startFolderId.getId() != null) { if (startFolderId instanceof Folder) { Folder startFolder = (Folder) startFolderId; if (!startFolder.isRootFolder()) { nextPath.append(startFolder.getPath()); lastFolderId = startFolder; } } else { ObjectData startFolderData = null; try { startFolderData = getBinding().getObjectService().getObject(getRepositoryId(), startFolderId.getId(), "cmis:objectId,cmis:baseTypeId,cmis:name,cmis:path", false, IncludeRelationships.NONE, "cmis:none", false, false, null); } catch (CmisBaseException cbe) { throw new IllegalArgumentException("Start folder does not exist or is not accessible!", cbe); } if (startFolderData.getBaseTypeId() != BaseTypeId.CMIS_FOLDER) { throw new IllegalArgumentException("Start folder is not a folder!"); } if (startFolderData.getProperties() == null || startFolderData.getProperties().getProperties() == null || startFolderData.getProperties().getProperties().get(PropertyIds.PATH) == null) { throw new IllegalArgumentException("Start folder has no path property?!"); } Object startPath = startFolderData.getProperties().getProperties().get(PropertyIds.PATH) .getFirstValue(); if (!(startPath instanceof String)) { throw new IllegalArgumentException("Start folder has an invalid path property?!"); } if (!repositoryInfo.getRootFolderId().equals(startFolderData.getId())) { nextPath.append(startPath); lastFolderId = startFolderId; } } if (!newPath.startsWith(nextPath.toString())) { throw new IllegalArgumentException("Start folder in not in the path!"); } segements = newPath.substring(nextPath.length()).split("/"); } else { segements = newPath.split("/"); } // create folders for (int i = 1; i < segements.length; i++) { if (create) { lastFolderId = createFolder(buildCreatePathProperties(properties, segements[i]), lastFolderId, policies, addAces, removeAces); } else { try { nextPath.append('/'); nextPath.append(segements[i]); ObjectData folderData = getBinding().getObjectService().getObjectByPath(getRepositoryId(), nextPath.toString(), "cmis:objectId,cmis:baseTypeId,cmis:name", false, IncludeRelationships.NONE, "cmis:none", false, false, null); if (folderData.getBaseTypeId() != BaseTypeId.CMIS_FOLDER) { throw new CmisConstraintException("Cannot create a folder '" + segements[i] + "' because there is already an object with this name, which is not a folder!"); } lastFolderId = new ObjectIdImpl(folderData.getId()); } catch (CmisObjectNotFoundException onfe) { if (lastFolderId == null) { lastFolderId = new ObjectIdImpl(repositoryInfo.getRootFolderId()); } lastFolderId = createFolder(buildCreatePathProperties(properties, segements[i]), lastFolderId, policies, addAces, removeAces); create = true; } } } return lastFolderId; } private Map buildCreatePathProperties(Map properties, String name) { Map newProperties = new HashMap(properties); newProperties.put(PropertyIds.NAME, name); return newProperties; } @Override public ObjectId createPolicy(Map properties, ObjectId folderId, List policies, List addAces, List removeAces) { checkProperties(properties); String newId = getBinding().getObjectService().createPolicy(getRepositoryId(), objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY), (folderId == null ? null : folderId.getId()), objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null); if (newId == null) { return null; } return createObjectId(newId); } @Override public ObjectId createItem(Map properties, ObjectId folderId, List policies, List addAces, List removeAces) { checkProperties(properties); String newId = getBinding().getObjectService().createItem(getRepositoryId(), objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY), (folderId == null ? null : folderId.getId()), objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null); if (newId == null) { return null; } return createObjectId(newId); } @Override public ObjectId createRelationship(Map properties, List policies, List addAces, List removeAces) { checkProperties(properties); String newId = getBinding().getObjectService().createRelationship(getRepositoryId(), objectFactory.convertProperties(properties, null, null, CREATE_UPDATABILITY), objectFactory.convertPolicies(policies), objectFactory.convertAces(addAces), objectFactory.convertAces(removeAces), null); if (newId == null) { return null; } return createObjectId(newId); } @Override public ObjectId createDocument(Map properties, ObjectId folderId, ContentStream contentStream, VersioningState versioningState) { return createDocument(properties, folderId, contentStream, versioningState, null, null, null); } @Override public ObjectId createDocumentFromSource(ObjectId source, Map properties, ObjectId folderId, VersioningState versioningState) { return createDocumentFromSource(source, properties, folderId, versioningState, null, null, null); } @Override public ObjectId createFolder(Map properties, ObjectId folderId) { return createFolder(properties, folderId, null, null, null); } @Override public ObjectId createPolicy(Map properties, ObjectId folderId) { return createPolicy(properties, folderId, null, null, null); } @Override public ObjectId createItem(Map properties, ObjectId folderId) { return createItem(properties, folderId, null, null, null); } // --- relationships --- @Override public ObjectId createRelationship(Map properties) { return createRelationship(properties, null, null, null); } @Override public ItemIterable getRelationships(ObjectId objectId, final boolean includeSubRelationshipTypes, final RelationshipDirection relationshipDirection, ObjectType type, OperationContext context) { checkObjectId(objectId); checkContext(context); final String id = objectId.getId(); final String typeId = type == null ? null : type.getId(); final RelationshipService relationshipService = getBinding().getRelationshipService(); final OperationContext ctxt = new OperationContextImpl(context); return new CollectionIterable(new AbstractPageFetcher(ctxt.getMaxItemsPerPage()) { @Override protected AbstractPageFetcher.Page fetchPage(long skipCount) { // fetch the relationships ObjectList relList = relationshipService.getObjectRelationships(getRepositoryId(), id, includeSubRelationshipTypes, relationshipDirection, typeId, ctxt.getFilterString(), ctxt.isIncludeAllowableActions(), BigInteger.valueOf(this.maxNumItems), BigInteger.valueOf(skipCount), null); // convert relationship objects List page = new ArrayList(); if (relList.getObjects() != null) { for (ObjectData rod : relList.getObjects()) { CmisObject relationship = getObject(rod.getId(), ctxt); if (!(relationship instanceof Relationship)) { throw new CmisRuntimeException("Repository returned an object that is not a relationship!"); } page.add((Relationship) relationship); } } return new AbstractPageFetcher.Page(page, relList.getNumItems(), relList.hasMoreItems()); } }); } // --- bulk update --- @Override public List bulkUpdateProperties(List objects, Map properties, List addSecondaryTypeIds, List removeSecondaryTypeIds) { checkCmisVersion(); checkProperties(properties); ObjectType objectType = null; Map secondaryTypes = new HashMap(); // gather secondary types if (addSecondaryTypeIds != null) { for (String stid : addSecondaryTypeIds) { ObjectType secondaryType = getTypeDefinition(stid); if (!(secondaryType instanceof SecondaryType)) { throw new IllegalArgumentException( "Secondary types contains a type that is not a secondary type: " + secondaryType.getId()); } secondaryTypes.put(secondaryType.getId(), (SecondaryType) secondaryType); } } // gather IDs and change tokens List objectIdsAndChangeTokens = new ArrayList(); for (CmisObject object : objects) { if (object == null) { continue; } objectIdsAndChangeTokens .add(new BulkUpdateObjectIdAndChangeTokenImpl(object.getId(), object.getChangeToken())); if (objectType == null) { objectType = object.getType(); } if (object.getSecondaryTypes() != null) { for (SecondaryType secondaryType : object.getSecondaryTypes()) { secondaryTypes.put(secondaryType.getId(), secondaryType); } } } Set updatebility = EnumSet.noneOf(Updatability.class); updatebility.add(Updatability.READWRITE); return getBinding().getObjectService().bulkUpdateProperties(getRepositoryId(), objectIdsAndChangeTokens, objectFactory.convertProperties(properties, objectType, secondaryTypes.values(), updatebility), addSecondaryTypeIds, removeSecondaryTypeIds, null); } // --- delete --- @Override public void delete(ObjectId objectId) { delete(objectId, true); } @Override public void delete(ObjectId objectId, boolean allVersions) { checkObjectId(objectId); getBinding().getObjectService().deleteObject(getRepositoryId(), objectId.getId(), allVersions, null); removeObjectFromCache(objectId); } @Override public void deleteByPath(String path) { deleteByPath(path, true); } @Override public void deleteByPath(String parentPath, String name) { deleteByPath(buildPath(parentPath, name), true); } @Override public void deleteByPath(String path, boolean allVersions) { checkPath(path); delete(new ObjectIdImpl(getObjectIdByPath(path)), allVersions); } @Override public List deleteTree(ObjectId folderId, boolean allVersions, UnfileObject unfile, boolean continueOnFailure) { checkFolderId(folderId); FailedToDeleteData failed = getBinding().getObjectService().deleteTree(getRepositoryId(), folderId.getId(), allVersions, unfile, continueOnFailure, null); if (failed == null || isNullOrEmpty(failed.getIds())) { removeObjectFromCache(folderId); } return (failed != null ? failed.getIds() : null); } @Override public List deleteTreebyPath(String parentPath, String name, boolean allVersions, UnfileObject unfile, boolean continueOnFailure) { return deleteTreebyPath(buildPath(parentPath, name), allVersions, unfile, continueOnFailure); } @Override public List deleteTreebyPath(String path, boolean allVersions, UnfileObject unfile, boolean continueOnFailure) { checkPath(path); return deleteTree(new ObjectIdImpl(getObjectIdByPath(path)), allVersions, unfile, continueOnFailure); } // --- content stream --- @Override public ContentStream getContentStream(ObjectId docId) { return getContentStream(docId, null, null, null); } @Override public ContentStream getContentStream(ObjectId docId, String streamId, BigInteger offset, BigInteger length) { checkDocumentId(docId); // get the stream ContentStream contentStream = null; try { contentStream = getBinding().getObjectService().getContentStream(getRepositoryId(), docId.getId(), streamId, offset, length, null); } catch (CmisConstraintException e) { // no content stream return null; } catch (CmisObjectNotFoundException onfe) { removeObjectFromCache(docId.getId()); throw onfe; } return contentStream; } @Override public ContentStream getContentStreamByPath(String path) { return getContentStreamByPath(path, null, null, null); } @Override public ContentStream getContentStreamByPath(String path, String streamId, BigInteger offset, BigInteger length) { checkPath(path); // check the cache boolean fromCache = true; String objectId = cache.getObjectIdByPath(path); // not in cache -> get the object if (objectId == null) { fromCache = false; objectId = getObjectIdByPath(path); // don't check if the object is a document // the path could belong to a folder or an item and the stream ID // could point to a rendition } // get the stream ContentStream contentStream = null; try { contentStream = getBinding().getObjectService().getContentStream(getRepositoryId(), objectId, streamId, offset, length, null); } catch (CmisConstraintException ce) { // no content stream return null; } catch (CmisObjectNotFoundException onfe) { if (fromCache) { removeObjectFromCache(objectId); cache.removePath(path); } else { throw onfe; } } if (contentStream == null) { // we are here because we got the object ID from the cache but the // object couldn't be found anymore // there maybe now a new object at this path -> let's try again contentStream = getBinding().getObjectService().getContentStream(getRepositoryId(), getObjectIdByPath(path), streamId, offset, length, null); } return contentStream; } // --- ACL --- @Override public Acl getAcl(ObjectId objectId, boolean onlyBasicPermissions) { checkObjectId(objectId); return getBinding().getAclService().getAcl(getRepositoryId(), objectId.getId(), onlyBasicPermissions, null); } @Override public Acl applyAcl(ObjectId objectId, List addAces, List removeAces, AclPropagation aclPropagation) { checkObjectId(objectId); ObjectFactory of = getObjectFactory(); return getBinding().getAclService().applyAcl(getRepositoryId(), objectId.getId(), of.convertAces(addAces), of.convertAces(removeAces), aclPropagation, null); } @Override public Acl setAcl(ObjectId objectId, List aces) { checkObjectId(objectId); if (aces == null) { aces = Collections.emptyList(); } AclService aclService = getBinding().getAclService(); if (!(aclService instanceof ExtendedAclService)) { throw new CmisNotSupportedException("setAcl() is not supported by the binding implementation."); } ObjectFactory of = getObjectFactory(); return ((ExtendedAclService) aclService).setAcl(getRepositoryId(), objectId.getId(), of.convertAces(aces)); } // --- Policies --- @Override public void applyPolicy(ObjectId objectId, ObjectId... policyIds) { checkObjectId(objectId); if (policyIds == null || policyIds.length == 0) { throw new IllegalArgumentException("No Policies provided!"); } String[] ids = new String[policyIds.length]; for (int i = 0; i < policyIds.length; i++) { if (policyIds[i] == null || policyIds[i].getId() == null) { throw new IllegalArgumentException("A Policy ID is not set!"); } ids[i] = policyIds[i].getId(); } for (String id : ids) { getBinding().getPolicyService().applyPolicy(getRepositoryId(), id, objectId.getId(), null); } } @Override public void removePolicy(ObjectId objectId, ObjectId... policyIds) { checkObjectId(objectId); if (policyIds == null || policyIds.length == 0) { throw new IllegalArgumentException("No Policies provided!"); } String[] ids = new String[policyIds.length]; for (int i = 0; i < policyIds.length; i++) { if (policyIds[i] == null || policyIds[i].getId() == null) { throw new IllegalArgumentException("A Policy ID is not set!"); } ids[i] = policyIds[i].getId(); } for (String id : ids) { getBinding().getPolicyService().removePolicy(getRepositoryId(), id, objectId.getId(), null); } } // ---- protected String buildPath(String parentPath, String name) { if (parentPath == null || parentPath.length() < 1) { throw new IllegalArgumentException("Parent path must be set!"); } if (parentPath.charAt(0) != '/') { throw new IllegalArgumentException("Parent path must start with a '/'!"); } if (name == null || name.length() < 1) { throw new IllegalArgumentException("Name must be set!"); } StringBuilder path = new StringBuilder(parentPath.length() + name.length() + 2); path.append(parentPath); if (!parentPath.endsWith("/")) { path.append('/'); } path.append(name); return path.toString(); } protected String getObjectIdByPath(String path) { try { return getBinding().getObjectService().getObjectByPath(getRepositoryId(), path, "cmis:objectId,cmis:baseTypeId", false, IncludeRelationships.NONE, "cmis:none", false, false, null) .getId(); } catch (CmisObjectNotFoundException onfe) { cache.removePath(path); throw onfe; } } protected final void checkObjectId(ObjectId objectId) { if (objectId == null || objectId.getId() == null) { throw new IllegalArgumentException("Invalid object ID!"); } } protected final void checkObjectId(String objectId) { if (objectId == null) { throw new IllegalArgumentException("Invalid object ID!"); } } protected final void checkDocumentId(ObjectId docId) { if (docId == null || docId.getId() == null) { throw new IllegalArgumentException("Invalid document ID!"); } } protected final void checkDocumentId(String docId) { if (docId == null) { throw new IllegalArgumentException("Invalid document ID!"); } } protected final void checkFolderId(ObjectId folderId) { if (folderId == null || folderId.getId() == null) { throw new IllegalArgumentException("Invalid folder ID!"); } } protected final void checkPath(String path) { if (path == null || path.length() < 1) { throw new IllegalArgumentException("Invalid path!"); } if (path.charAt(0) != '/') { throw new IllegalArgumentException("Path must start with a '/'!"); } } protected final void checkContext(OperationContext context) { if (context == null) { throw new IllegalArgumentException("Invalid Operation Context!"); } } protected final void checkProperties(Map properties) { if (isNullOrEmpty(properties)) { throw new IllegalArgumentException("Properties must not be empty!"); } } protected final void checkCmisVersion() { if (repositoryInfo.getCmisVersion() == CmisVersion.CMIS_1_0) { throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories."); } } // ---- @Override public String toString() { return "Session " + getBinding().getSessionId(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy