001/*
002 * (C) Copyright 2012 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 *     Antoine Taillefer <ataillefer@nuxeo.com>
018 */
019package org.nuxeo.drive.service.impl;
020
021import org.apache.logging.log4j.LogManager;
022import org.apache.logging.log4j.Logger;
023import org.nuxeo.drive.adapter.FileSystemItem;
024import org.nuxeo.drive.adapter.FolderItem;
025import org.nuxeo.drive.adapter.impl.AbstractFileSystemItem;
026import org.nuxeo.drive.service.FileSystemItemAdapterService;
027import org.nuxeo.drive.service.FileSystemItemFactory;
028import org.nuxeo.ecm.core.api.CoreInstance;
029import org.nuxeo.ecm.core.api.CoreSession;
030import org.nuxeo.ecm.core.api.DocumentModel;
031import org.nuxeo.ecm.core.api.DocumentNotFoundException;
032import org.nuxeo.ecm.core.api.DocumentSecurityException;
033import org.nuxeo.ecm.core.api.IdRef;
034import org.nuxeo.ecm.core.api.NuxeoException;
035import org.nuxeo.ecm.core.api.NuxeoPrincipal;
036import org.nuxeo.runtime.api.Framework;
037
038/**
039 * Base class for {@link FileSystemItemFactory} implementers. It is {@link DocumentModel} backed.
040 *
041 * @author Antoine Taillefer
042 * @see DefaultFileSystemItemFactory
043 */
044public abstract class AbstractFileSystemItemFactory implements FileSystemItemFactory {
045
046    private static final Logger log = LogManager.getLogger(AbstractFileSystemItemFactory.class);
047
048    protected String name;
049
050    /**
051     * Adapts the given {@link DocumentModel} to a {@link FileSystemItem}.
052     *
053     * @see #getFileSystemItem(DocumentModel, boolean, FolderItem, boolean, boolean, boolean)
054     */
055    protected abstract FileSystemItem adaptDocument(DocumentModel doc, boolean forceParentItem, FolderItem parentItem,
056            boolean relaxSyncRootConstraint, boolean getLockInfo);
057
058    @Override
059    public String getName() {
060        return name;
061    }
062
063    @Override
064    public void setName(String name) {
065        this.name = name;
066    }
067
068    @Override
069    public boolean isFileSystemItem(DocumentModel doc) {
070        return isFileSystemItem(doc, false);
071    }
072
073    @Override
074    public boolean isFileSystemItem(DocumentModel doc, boolean includeDeleted) {
075        return isFileSystemItem(doc, includeDeleted, false);
076    }
077
078    @Override
079    public FileSystemItem getFileSystemItem(DocumentModel doc) {
080        return getFileSystemItem(doc, false);
081    }
082
083    @Override
084    public FileSystemItem getFileSystemItem(DocumentModel doc, boolean includeDeleted) {
085        return getFileSystemItem(doc, false, null, includeDeleted, false, true);
086    }
087
088    @Override
089    public FileSystemItem getFileSystemItem(DocumentModel doc, boolean includeDeleted,
090            boolean relaxSyncRootConstraint) {
091        return getFileSystemItem(doc, false, null, includeDeleted, relaxSyncRootConstraint, true);
092    }
093
094    @Override
095    public FileSystemItem getFileSystemItem(DocumentModel doc, boolean includeDeleted, boolean relaxSyncRootConstraint,
096            boolean getLockInfo) {
097        return getFileSystemItem(doc, false, null, includeDeleted, relaxSyncRootConstraint, getLockInfo);
098    }
099
100    @Override
101    public FileSystemItem getFileSystemItem(DocumentModel doc, FolderItem parentItem) {
102        return getFileSystemItem(doc, parentItem, false);
103    }
104
105    @Override
106    public FileSystemItem getFileSystemItem(DocumentModel doc, FolderItem parentItem, boolean includeDeleted) {
107        return getFileSystemItem(doc, true, parentItem, includeDeleted, false, true);
108    }
109
110    @Override
111    public FileSystemItem getFileSystemItem(DocumentModel doc, FolderItem parentItem, boolean includeDeleted,
112            boolean relaxSyncRootConstraint) {
113        return getFileSystemItem(doc, true, parentItem, includeDeleted, relaxSyncRootConstraint, true);
114    }
115
116    @Override
117    public FileSystemItem getFileSystemItem(DocumentModel doc, FolderItem parentItem, boolean includeDeleted,
118            boolean relaxSyncRootConstraint, boolean getLockInfo) {
119        return getFileSystemItem(doc, true, parentItem, includeDeleted, relaxSyncRootConstraint, getLockInfo);
120    }
121
122    @Override
123    public boolean canHandleFileSystemItemId(String id) {
124        try {
125            parseFileSystemId(id);
126        } catch (IllegalArgumentException e) {
127            log.trace(e::getMessage);
128            return false;
129        }
130        return true;
131    }
132
133    /**
134     * The default factory considers that a {@link FileSystemItem} with the given id exists if the backing
135     * {@link DocumentModel} can be fetched and {@link #isFileSystemItem(DocumentModel)} returns true.
136     *
137     * @see #isFileSystemItem(DocumentModel)
138     */
139    @Override
140    public boolean exists(String id, NuxeoPrincipal principal) {
141        String[] idFragments = parseFileSystemId(id);
142        String repositoryName = idFragments[1];
143        String docId = idFragments[2];
144        try {
145            CoreSession session = CoreInstance.getCoreSession(repositoryName, principal);
146            DocumentModel doc = getDocumentById(docId, session);
147            return isFileSystemItem(doc);
148        } catch (DocumentNotFoundException e) {
149            log.debug("No doc related to id {}, returning false.", docId);
150            return false;
151        } catch (DocumentSecurityException e) {
152            log.debug("User {} cannot access doc {}, returning false.", principal, docId);
153            return false;
154        }
155    }
156
157    @Override
158    public FileSystemItem getFileSystemItemById(String id, NuxeoPrincipal principal) {
159        String[] idFragments = parseFileSystemId(id);
160        String repositoryName = idFragments[1];
161        String docId = idFragments[2];
162        try {
163            CoreSession session = CoreInstance.getCoreSession(repositoryName, principal);
164            DocumentModel doc = getDocumentById(docId, session);
165            return getFileSystemItem(doc);
166        } catch (DocumentNotFoundException e) {
167
168            log.debug("No doc related to id {}, returning null.", docId);
169            return null;
170        } catch (DocumentSecurityException e) {
171            log.debug("User {} cannot access doc {}, returning null.", principal, docId);
172            return null;
173        }
174    }
175
176    @Override
177    public FileSystemItem getFileSystemItemById(String id, String parentId, NuxeoPrincipal principal) {
178        String[] idFragments = parseFileSystemId(id);
179        String repositoryName = idFragments[1];
180        String docId = idFragments[2];
181        try {
182            CoreSession session = CoreInstance.getCoreSession(repositoryName, principal);
183            FileSystemItem parentItem = Framework.getService(FileSystemItemAdapterService.class)
184                                                 .getFileSystemItemFactoryForId(parentId)
185                                                 .getFileSystemItemById(parentId, principal);
186            if (!(parentItem instanceof FolderItem)) {
187                throw new NuxeoException(String.format("FileSystemItem with id %s should be a FolderItem", parentId));
188            }
189            DocumentModel doc = getDocumentById(docId, session);
190            return getFileSystemItem(doc, (FolderItem) parentItem);
191        } catch (DocumentNotFoundException e) {
192            log.debug("No doc related to id {}, returning null.", docId);
193            return null;
194        } catch (DocumentSecurityException e) {
195            log.debug("User {} cannot access doc {}, returning null.", principal, docId);
196            return null;
197        }
198
199    }
200
201    /*--------------------------- Protected ---------------------------------*/
202    protected FileSystemItem adaptDocument(DocumentModel doc, boolean forceParentItem, FolderItem parentItem) {
203        return adaptDocument(doc, forceParentItem, parentItem, false, true);
204    }
205
206    protected FileSystemItem getFileSystemItem(DocumentModel doc, boolean forceParentItem, FolderItem parentItem,
207            boolean includeDeleted, boolean relaxSyncRootConstraint, boolean getLockInfo) {
208
209        // If the doc is not adaptable as a FileSystemItem return null
210        if (!isFileSystemItem(doc, includeDeleted, relaxSyncRootConstraint)) {
211            log.trace("Document {} cannot be adapted as a FileSystemItem => returning null.", doc::getId);
212            return null;
213        }
214        return adaptDocument(doc, forceParentItem, parentItem, relaxSyncRootConstraint, getLockInfo);
215    }
216
217    protected String[] parseFileSystemId(String id) {
218
219        // Parse id, expecting pattern:
220        // fileSystemItemFactoryName#repositoryName#docId
221        String[] idFragments = id.split(AbstractFileSystemItem.FILE_SYSTEM_ITEM_ID_SEPARATOR);
222        if (idFragments.length != 3) {
223            throw new IllegalArgumentException(String.format(
224                    "FileSystemItem id %s cannot be handled by factory named %s. Should match the 'fileSystemItemFactoryName#repositoryName#docId' pattern.",
225                    id, name));
226        }
227
228        // Check if factory name matches
229        String factoryName = idFragments[0];
230        if (!name.equals(factoryName)) {
231            throw new IllegalArgumentException(
232                    String.format("Factoy name [%s] parsed from id %s does not match the actual factory name [%s].",
233                            factoryName, id, name));
234        }
235        return idFragments;
236    }
237
238    protected DocumentModel getDocumentById(String docId, CoreSession session) {
239        return session.getDocument(new IdRef(docId));
240    }
241
242}