001/*
002 * (C) Copyright 2014-2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Maxime Hilaire
018 *     Florent Guillaume
019 */
020package org.nuxeo.ecm.directory.core;
021
022import org.apache.commons.logging.Log;
023import org.apache.commons.logging.LogFactory;
024import org.nuxeo.ecm.core.api.DocumentModel;
025import org.nuxeo.ecm.core.api.DocumentNotFoundException;
026import org.nuxeo.ecm.core.api.DocumentRef;
027import org.nuxeo.ecm.core.api.PathRef;
028import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
029import org.nuxeo.ecm.core.api.security.ACE;
030import org.nuxeo.ecm.core.api.security.ACL;
031import org.nuxeo.ecm.core.api.security.ACP;
032import org.nuxeo.ecm.core.schema.SchemaManager;
033import org.nuxeo.ecm.core.schema.types.Field;
034import org.nuxeo.ecm.core.schema.types.Schema;
035import org.nuxeo.ecm.directory.AbstractDirectory;
036import org.nuxeo.ecm.directory.Directory;
037import org.nuxeo.ecm.directory.DirectoryException;
038import org.nuxeo.ecm.directory.DirectoryFieldMapper;
039import org.nuxeo.ecm.directory.Session;
040import org.nuxeo.runtime.api.Framework;
041
042/**
043 * Implementation of a {@link Directory} on top of a core repository.
044 *
045 * @since 8.2
046 */
047public class CoreDirectory extends AbstractDirectory {
048
049    private static final Log log = LogFactory.getLog(CoreDirectory.class);
050
051    protected final Schema schema;
052
053    public CoreDirectory(CoreDirectoryDescriptor descriptor) {
054        super(descriptor, null);
055        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
056        schema = schemaManager.getSchema(descriptor.schemaName);
057        fieldMapper = new DirectoryFieldMapper(descriptor.fieldMapping);
058        if (schema == null) {
059            throw new DirectoryException(
060                    String.format("Unknown schema '%s' for directory '%s' ", descriptor.schemaName, getName()));
061        }
062        start();
063    }
064
065    @Override
066    public CoreDirectoryDescriptor getDescriptor() {
067        return (CoreDirectoryDescriptor) descriptor;
068    }
069
070    public void start() {
071        CoreDirectoryDescriptor descriptor = getDescriptor();
072        UnrestrictedSessionRunner directoryInitializer = new UnrestrictedSessionRunner(descriptor.getRepositoryName()) {
073
074            @Override
075            public void run() {
076                String createPath = descriptor.getCreatePath();
077
078                DocumentModel rootFolder = null;
079                DocumentRef rootRef = new PathRef(createPath);
080                if (session.exists(rootRef)) {
081                    rootFolder = session.getDocument(rootRef);
082                }
083
084                if (rootFolder == null) {
085
086                    String parentFolder = createPath.substring(0, createPath.lastIndexOf("/"));
087                    if (createPath.lastIndexOf("/") == 0) {
088                        parentFolder = "/";
089                    }
090                    String createFolder = createPath.substring(createPath.lastIndexOf("/") + 1, createPath.length());
091
092                    log.info(String.format(
093                            "Root folder '%s' has not been found for the directory '%s' on the repository '%s', will create it with given ACL",
094                            createPath, getName(), descriptor.getRepositoryName()));
095                    if (descriptor.canCreateRootFolder()) {
096                        try {
097                            DocumentModel doc = session.createDocumentModel(parentFolder, createFolder, "Folder");
098                            doc.setProperty("dublincore", "title", createFolder);
099                            session.createDocument(doc);
100                            // Set ACL from descriptor
101                            for (int i = 0; i < descriptor.acls.length; i++) {
102                                String userOrGroupName = descriptor.acls[i].userOrGroupName;
103                                String privilege = descriptor.acls[i].privilege;
104                                boolean granted = descriptor.acls[i].granted;
105                                setACL(doc, userOrGroupName, privilege, granted);
106                            }
107                            session.save();
108
109                        } catch (DocumentNotFoundException e) {
110                            throw new DirectoryException(String.format(
111                                    "The root folder '%s' can not be created under '%s' for the directory '%s' on the repository '%s',"
112                                            + " please make sure you have set the right path or that the path exist",
113                                    createFolder, parentFolder, getName(), descriptor.getRepositoryName()), e);
114                        }
115                    }
116
117                } else {
118                    log.info(String.format(
119                            "Root folder '%s' has been found for the directory '%s' on the repository '%s', ACL will not be set",
120                            createPath, getName(), descriptor.getRepositoryName()));
121                }
122
123            }
124        };
125        directoryInitializer.runUnrestricted();
126    }
127
128    protected DocumentModel setACL(DocumentModel rootFolder, String userOrGroupName, String privilege,
129            boolean granted) {
130        ACP acp = rootFolder.getACP();
131        ACL localACL = acp.getOrCreateACL();
132        localACL.add(new ACE(userOrGroupName, privilege, granted));
133        rootFolder.setACP(acp, true);
134
135        if (log.isDebugEnabled()) {
136            log.debug(String.format(
137                    "Set ACL on root folder '%s' : userOrGroupName = '%s', privilege = '%s' , granted = '%s' ",
138                    rootFolder.getPathAsString(), userOrGroupName, privilege, granted));
139        }
140
141        return rootFolder.getCoreSession().saveDocument(rootFolder);
142    }
143
144    public Field getField(String name) {
145        Field field = schema.getField(name);
146        if (field == null) {
147            throw new DirectoryException(
148                    String.format("Field '%s' does not exist in the schema '%s'", name, schema.getName()));
149        }
150        return field;
151    }
152
153    @Override
154    public Session getSession() {
155        CoreDirectorySession session = new CoreDirectorySession(this);
156        addSession(session);
157        return session;
158    }
159
160}