org.structr.files.cmis.CMISRepositoryService.java Source code

Java tutorial

Introduction

Here is the source code for org.structr.files.cmis.CMISRepositoryService.java

Source

/**
 * Copyright (C) 2010-2016 Structr GmbH
 *
 * This file is part of Structr <http://structr.org>.
 *
 * Structr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Structr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Structr.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.structr.files.cmis;

import java.math.BigInteger;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.definitions.Choice;
import org.apache.chemistry.opencmis.commons.definitions.MutableDocumentTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.MutableFolderTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.MutableItemTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.MutablePolicyTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.MutablePropertyDefinition;
import org.apache.chemistry.opencmis.commons.definitions.MutableRelationshipTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.MutableSecondaryTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.MutableTypeDefinition;
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.BaseTypeId;
import static org.apache.chemistry.opencmis.commons.enums.BaseTypeId.CMIS_DOCUMENT;
import org.apache.chemistry.opencmis.commons.enums.Cardinality;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed;
import org.apache.chemistry.opencmis.commons.enums.PropertyType;
import org.apache.chemistry.opencmis.commons.enums.Updatability;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionContainerImpl;
import org.apache.chemistry.opencmis.commons.spi.RepositoryService;
import org.apache.chemistry.opencmis.server.support.TypeDefinitionFactory;
import org.apache.commons.lang3.StringUtils;
import org.structr.cmis.CMISInfo;
import org.structr.common.PropertyView;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import org.structr.core.GraphObject;
import org.structr.core.app.App;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.entity.SchemaNode;
import org.structr.core.graph.Tx;
import org.structr.core.graph.search.SearchCommand;
import org.structr.core.property.PropertyKey;
import org.structr.dynamic.File;
import org.structr.files.cmis.config.StructrRepositoryInfo;
import org.structr.files.cmis.wrapper.CMISTypeDefinitionListWrapper;
import org.structr.schema.ConfigurationProvider;
import org.structr.web.entity.Folder;

/**
 *
 *
 */
public class CMISRepositoryService extends AbstractStructrCmisService implements RepositoryService {

    private static final Logger logger = Logger.getLogger(CMISRepositoryService.class.getName());

    private final RepositoryInfo repositoryInfo = new StructrRepositoryInfo();

    public CMISRepositoryService(final StructrCMISService parentService, final SecurityContext securityContext) {
        super(parentService, securityContext);
    }

    @Override
    public List<RepositoryInfo> getRepositoryInfos(final ExtensionsData extension) {

        final List<RepositoryInfo> infoList = new LinkedList<>();

        infoList.add(repositoryInfo);

        return infoList;
    }

    @Override
    public RepositoryInfo getRepositoryInfo(String repositoryId, ExtensionsData extension) {

        if (repositoryId != null && repositoryId.equals(repositoryInfo.getId())) {
            return repositoryInfo;
        }

        throw new CmisObjectNotFoundException(repositoryId);
    }

    @Override
    public TypeDefinitionList getTypeChildren(String repositoryId, String typeId,
            Boolean includePropertyDefinitions, BigInteger maxItems, BigInteger skipCount,
            ExtensionsData extension) {

        // important: children are the direct children of a type, as opposed to the descendants

        final CMISTypeDefinitionListWrapper results = new CMISTypeDefinitionListWrapper(maxItems, skipCount);

        if (typeId != null) {

            final BaseTypeId baseTypeId = getBaseTypeId(typeId);
            if (baseTypeId != null) {

                results.addAll(getBaseTypeChildren(baseTypeId, includePropertyDefinitions));

            } else {

                final Class type = StructrApp.getConfiguration().getNodeEntityClass(typeId);
                if (type != null) {

                    results.addAll(getTypeChildren(typeId, includePropertyDefinitions));

                } else {

                    throw new CmisObjectNotFoundException("Type with ID " + typeId + " does not exist");
                }
            }

        } else {

            results.add(
                    getDocumentTypeDefinition(BaseTypeId.CMIS_DOCUMENT.value(), includePropertyDefinitions, true));
            results.add(getFolderTypeDefinition(BaseTypeId.CMIS_FOLDER.value(), includePropertyDefinitions, true));
            results.add(getItemTypeDefinition(BaseTypeId.CMIS_ITEM.value(), includePropertyDefinitions, true));
            results.add(getPolicyTypeDefinition(BaseTypeId.CMIS_POLICY.value(), includePropertyDefinitions, true));
            results.add(getRelationshipTypeDefinition(BaseTypeId.CMIS_RELATIONSHIP.value(),
                    includePropertyDefinitions, true));
            results.add(getSecondaryTypeDefinition(BaseTypeId.CMIS_SECONDARY.value(), includePropertyDefinitions,
                    true));
        }

        return results;
    }

    @Override
    public List<TypeDefinitionContainer> getTypeDescendants(String repositoryId, String typeId, BigInteger depth,
            Boolean includePropertyDefinitions, ExtensionsData extension) {

        // important: descendants are ALL children and children of children, i.e. the whole tree

        /*
        Id typeId: The typeId of an object-type speci?ed in the repository.
         - If speci?ed, then the repository MUST return all of descendant types of the speci?ed type.
         - If not speci?ed, then the Repository MUST return all types and MUST ignore the value of the depth parameter.
        */

        final List<TypeDefinitionContainer> results = new LinkedList<>();

        if (typeId != null) {

            final BaseTypeId baseTypeId = getBaseTypeId(typeId);
            if (baseTypeId != null) {

                final TypeDefinition typeDefinition = getTypeDefinition(repositoryId, typeId, extension);
                final TypeDefinitionContainer container = getTypeDefinitionContainer(typeDefinition,
                        includePropertyDefinitions);

                results.add(container);

            } else {

                final Class type = StructrApp.getConfiguration().getNodeEntityClass(typeId);
                if (type != null) {

                    final TypeDefinition typeDefinition = extendTypeDefinition(type, includePropertyDefinitions);
                    if (typeDefinition != null) {

                        results.add(getTypeDefinitionContainer(typeDefinition, includePropertyDefinitions));

                    } else {

                        throw new CmisObjectNotFoundException("Type with ID " + typeId + " does not exist");
                    }

                } else {

                    throw new CmisObjectNotFoundException("Type with ID " + typeId + " does not exist");
                }
            }

        } else {

            results.add(getTypeDefinitionContainer(
                    getDocumentTypeDefinition(BaseTypeId.CMIS_DOCUMENT.value(), includePropertyDefinitions, true),
                    includePropertyDefinitions));
            results.add(getTypeDefinitionContainer(
                    getFolderTypeDefinition(BaseTypeId.CMIS_FOLDER.value(), includePropertyDefinitions, true),
                    includePropertyDefinitions));
            results.add(getTypeDefinitionContainer(
                    getItemTypeDefinition(BaseTypeId.CMIS_ITEM.value(), includePropertyDefinitions, true),
                    includePropertyDefinitions));
            results.add(getTypeDefinitionContainer(
                    getPolicyTypeDefinition(BaseTypeId.CMIS_POLICY.value(), includePropertyDefinitions, true),
                    includePropertyDefinitions));
            results.add(
                    getTypeDefinitionContainer(getRelationshipTypeDefinition(BaseTypeId.CMIS_RELATIONSHIP.value(),
                            includePropertyDefinitions, true), includePropertyDefinitions));
            results.add(getTypeDefinitionContainer(
                    getSecondaryTypeDefinition(BaseTypeId.CMIS_SECONDARY.value(), includePropertyDefinitions, true),
                    includePropertyDefinitions));
        }

        return results;
    }

    @Override
    public TypeDefinition getTypeDefinition(final String repositoryId, final String typeId,
            final ExtensionsData extension) {

        switch (typeId) {

        case "cmis:document":
            return getDocumentTypeDefinition(typeId, true, true);

        case "cmis:folder":
            return getFolderTypeDefinition(typeId, true, true);

        case "cmis:item":
            return getItemTypeDefinition(typeId, true, true);

        case "cmis:policy":
            return getPolicyTypeDefinition(typeId, true, true);

        case "cmis:relationship":
            return getRelationshipTypeDefinition(typeId, true, true);

        case "cmis:secondary":
            return getSecondaryTypeDefinition(typeId, true, true);
        }

        final Class type = StructrApp.getConfiguration().getNodeEntityClass(typeId);
        if (type != null) {

            final TypeDefinition extendedTypeDefinition = extendTypeDefinition(type, true);
            if (extendedTypeDefinition != null) {

                return extendedTypeDefinition;
            }
        }

        throw new CmisObjectNotFoundException("Type with ID " + typeId + " does not exist");
    }

    @Override
    public TypeDefinition createType(String repositoryId, TypeDefinition type, ExtensionsData extension) {
        return null;
    }

    @Override
    public TypeDefinition updateType(String repositoryId, TypeDefinition type, ExtensionsData extension) {
        return null;
    }

    @Override
    public void deleteType(String repositoryId, String typeId, ExtensionsData extension) {
    }

    // ----- private methods -----
    private MutableSecondaryTypeDefinition getSecondaryTypeDefinition(final String typeId,
            final boolean includePropertyDefinitions, final boolean baseType) {

        final TypeDefinitionFactory factory = TypeDefinitionFactory.newInstance();
        final MutableSecondaryTypeDefinition def = factory.createSecondaryTypeDefinition(CmisVersion.CMIS_1_1,
                baseType ? null : BaseTypeId.CMIS_SECONDARY.value());

        def.setIsCreatable(false);

        initializeExtendedType(def, typeId);

        if (!includePropertyDefinitions) {
            def.removeAllPropertyDefinitions();
        }

        return def;
    }

    private MutableRelationshipTypeDefinition getRelationshipTypeDefinition(final String typeId,
            final boolean includePropertyDefinitions, final boolean baseType) {

        final TypeDefinitionFactory factory = TypeDefinitionFactory.newInstance();
        final MutableRelationshipTypeDefinition def = factory.createRelationshipTypeDefinition(CmisVersion.CMIS_1_1,
                baseType ? null : BaseTypeId.CMIS_RELATIONSHIP.value());

        def.setIsCreatable(false);

        initializeExtendedType(def, typeId);

        if (!includePropertyDefinitions) {
            def.removeAllPropertyDefinitions();
        }

        return def;
    }

    private MutableItemTypeDefinition getItemTypeDefinition(final String typeId,
            final boolean includePropertyDefinitions, final boolean baseType) {

        final TypeDefinitionFactory factory = TypeDefinitionFactory.newInstance();
        final MutableItemTypeDefinition def = factory.createItemTypeDefinition(CmisVersion.CMIS_1_1,
                baseType ? null : BaseTypeId.CMIS_ITEM.value());

        def.setIsCreatable(false);

        initializeExtendedType(def, typeId);

        if (!includePropertyDefinitions) {
            def.removeAllPropertyDefinitions();
        }

        return def;
    }

    private MutablePolicyTypeDefinition getPolicyTypeDefinition(final String typeId,
            final boolean includePropertyDefinitions, final boolean baseType) {

        final TypeDefinitionFactory factory = TypeDefinitionFactory.newInstance();
        final MutablePolicyTypeDefinition def = factory.createPolicyTypeDefinition(CmisVersion.CMIS_1_1,
                baseType ? null : BaseTypeId.CMIS_POLICY.value());

        def.setIsCreatable(false);

        initializeExtendedType(def, typeId);

        if (!includePropertyDefinitions) {
            def.removeAllPropertyDefinitions();
        }

        return def;
    }

    private MutableFolderTypeDefinition getFolderTypeDefinition(final String typeId,
            final boolean includePropertyDefinitions, final boolean baseType) {

        final TypeDefinitionFactory factory = TypeDefinitionFactory.newInstance();
        final MutableFolderTypeDefinition def = factory.createFolderTypeDefinition(CmisVersion.CMIS_1_1,
                baseType ? null : BaseTypeId.CMIS_FOLDER.value());

        initializeExtendedType(def, typeId);

        if (!includePropertyDefinitions) {
            def.removeAllPropertyDefinitions();
        }

        return def;
    }

    private MutableDocumentTypeDefinition getDocumentTypeDefinition(final String typeId,
            final boolean includePropertyDefinitions, final boolean baseType) {

        final TypeDefinitionFactory factory = TypeDefinitionFactory.newInstance();
        final MutableDocumentTypeDefinition def = factory.createDocumentTypeDefinition(CmisVersion.CMIS_1_1,
                baseType ? null : BaseTypeId.CMIS_DOCUMENT.value());

        // content is required for Structr documents
        def.setContentStreamAllowed(ContentStreamAllowed.REQUIRED);

        initializeExtendedType(def, typeId);

        if (!includePropertyDefinitions) {

            def.removeAllPropertyDefinitions();
        }

        return def;
    }

    private List<TypeDefinition> getTypeChildren(final String typeId, final Boolean includePropertyDefinitions) {

        final Set<String> subtypes = new LinkedHashSet<>(SearchCommand.getAllSubtypesAsStringSet(typeId));
        final ConfigurationProvider config = StructrApp.getConfiguration();
        final List<TypeDefinition> result = new LinkedList<>();

        // subtypes set from Structr contains initial type as well..
        subtypes.remove(typeId);

        for (final String subtype : subtypes) {

            final Class subclass = config.getNodeEntityClass(subtype);
            if (subclass != null) {

                final TypeDefinition extendedTypeDefinition = extendTypeDefinition(subclass,
                        includePropertyDefinitions);
                if (extendedTypeDefinition != null) {

                    result.add(extendedTypeDefinition);
                }
            }
        }

        return result;
    }

    private List<TypeDefinition> getBaseTypeChildren(final BaseTypeId baseTypeId,
            final Boolean includePropertyDefinitions) {

        final ConfigurationProvider config = StructrApp.getConfiguration();
        final List<TypeDefinition> result = new LinkedList<>();
        final App app = StructrApp.getInstance();

        // static definition of base type children, add new types here!
        switch (baseTypeId) {

        case CMIS_DOCUMENT:
            result.add(extendTypeDefinition(File.class, includePropertyDefinitions));
            break;

        case CMIS_FOLDER:
            result.add(extendTypeDefinition(Folder.class, includePropertyDefinitions));
            break;

        case CMIS_ITEM:

            try (final Tx tx = app.tx()) {

                for (final SchemaNode schemaNode : app.nodeQuery(SchemaNode.class).sort(AbstractNode.name)
                        .getAsList()) {

                    final Class type = config.getNodeEntityClass(schemaNode.getClassName());
                    if (type != null) {

                        final CMISInfo info = getCMISInfo(type);
                        if (info != null && baseTypeId.equals(info.getBaseTypeId())) {

                            final TypeDefinition extendedTypeDefinition = extendTypeDefinition(type,
                                    includePropertyDefinitions);
                            if (extendedTypeDefinition != null) {

                                result.add(extendedTypeDefinition);
                            }
                        }
                    }
                }

                tx.success();

            } catch (final FrameworkException fex) {
                fex.printStackTrace();
            }
            break;
        }

        return result;
    }

    private TypeDefinitionContainer getTypeDefinitionContainer(final TypeDefinition typeDefinition,
            final Boolean includePropertyDefinitions) {

        final TypeDefinitionContainerImpl result = new TypeDefinitionContainerImpl();
        final List<TypeDefinitionContainer> list = new LinkedList<>();

        result.setTypeDefinition(typeDefinition);
        result.setChildren(list);

        final String typeId = typeDefinition.getId();
        final BaseTypeId baseTypeId = getBaseTypeId(typeId);

        if (baseTypeId != null) {

            for (final TypeDefinition child : getBaseTypeChildren(baseTypeId, includePropertyDefinitions)) {

                list.add(getTypeDefinitionContainer(child, includePropertyDefinitions));
            }

        } else {

            for (final TypeDefinition child : getTypeChildren(typeDefinition.getId(), includePropertyDefinitions)) {

                list.add(getTypeDefinitionContainer(child, includePropertyDefinitions));
            }

        }

        return result;
    }

    private MutableTypeDefinition extendTypeDefinition(final Class<? extends GraphObject> type,
            final Boolean includePropertyDefinitions) {

        final String typeName = type.getSimpleName();
        MutableTypeDefinition result = null;

        try {

            // instantiate class to obtain runtime CMIS information
            final GraphObject obj = type.newInstance();
            if (obj != null) {

                final CMISInfo info = obj.getCMISInfo();
                if (info != null) {

                    final BaseTypeId baseTypeId = info.getBaseTypeId();
                    if (baseTypeId != null) {

                        switch (baseTypeId) {

                        case CMIS_DOCUMENT:
                            result = getDocumentTypeDefinition(typeName, includePropertyDefinitions, false);
                            break;

                        case CMIS_FOLDER:
                            result = getFolderTypeDefinition(typeName, includePropertyDefinitions, false);
                            break;

                        case CMIS_ITEM:
                            result = getItemTypeDefinition(typeName, includePropertyDefinitions, false);
                            break;

                        case CMIS_POLICY:
                            result = getPolicyTypeDefinition(typeName, includePropertyDefinitions, false);
                            break;

                        case CMIS_RELATIONSHIP:
                            result = getRelationshipTypeDefinition(typeName, includePropertyDefinitions, false);
                            break;

                        case CMIS_SECONDARY:
                            result = getSecondaryTypeDefinition(typeName, includePropertyDefinitions, false);
                            break;
                        }

                        if (result != null) {

                            // initialize..
                            for (final PropertyKey key : StructrApp.getConfiguration().getPropertySet(type,
                                    PropertyView.All)) {

                                final MutablePropertyDefinition property = createProperty(type, key);
                                if (property != null) {

                                    result.addPropertyDefinition(property);
                                }
                            }
                        }
                    }
                }
            }

        } catch (final IllegalAccessException | InstantiationException iex) {
            iex.printStackTrace();
        }

        return result;
    }

    private void initializeExtendedType(final MutableTypeDefinition type, final String typeId) {

        type.setId(typeId);
        type.setLocalName(typeId);
        type.setQueryName(typeId);
        type.setDisplayName(typeId);
        type.setDescription(typeId);
    }

    private MutablePropertyDefinition createProperty(final Class type, final PropertyKey key) {

        // include all dynamic and CMIS-enabled keys in definition
        if (key.isDynamic() || key.isCMISProperty()) {

            // only include primitives here
            final TypeDefinitionFactory factory = TypeDefinitionFactory.newInstance();
            final PropertyType dataType = key.getDataType();

            if (dataType != null) {

                final String propertyId = key.jsonName();
                final String displayName = propertyId;
                final String description = StringUtils.capitalize(propertyId);
                final Class declaringClass = key.getDeclaringClass();
                final boolean isInherited = !type.getSimpleName().equals(declaringClass.getSimpleName());
                final Cardinality cardinality = Cardinality.SINGLE;
                final Updatability updatability = Updatability.READWRITE;
                final boolean required = key.isNotNull();
                final boolean queryable = key.isIndexed();
                final boolean orderable = key.isIndexed();

                final MutablePropertyDefinition property = factory.createPropertyDefinition(propertyId, displayName,
                        description, dataType, cardinality, updatability, isInherited, required, queryable,
                        orderable);

                // add enum choices if present
                final Class valueType = key.valueType();
                if (valueType != null && valueType.isEnum()) {

                    final List<Choice> choices = new LinkedList<>();

                    for (final Object option : valueType.getEnumConstants()) {

                        final String optionName = option.toString();

                        choices.add(factory.createChoice(optionName, optionName));
                    }

                    property.setIsOpenChoice(false);
                    property.setChoices(choices);
                }

                return property;
            }
        }

        return null;
    }
}