001/*
002 * (C) Copyright 2009 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 *     Thierry Delprat
018 */
019package org.nuxeo.ecm.platform.publisher.impl.finder;
020
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.HashSet;
024import java.util.List;
025import java.util.Set;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.ecm.core.api.CoreSession;
030import org.nuxeo.ecm.core.api.DocumentModel;
031import org.nuxeo.ecm.core.api.DocumentModelList;
032import org.nuxeo.ecm.core.api.DocumentNotFoundException;
033import org.nuxeo.ecm.core.api.DocumentRef;
034import org.nuxeo.ecm.core.api.Filter;
035import org.nuxeo.ecm.core.api.IdRef;
036import org.nuxeo.ecm.core.api.LifeCycleConstants;
037import org.nuxeo.ecm.core.api.PathRef;
038import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
039import org.nuxeo.ecm.core.api.impl.CompoundFilter;
040import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
041import org.nuxeo.ecm.core.api.impl.FacetFilter;
042import org.nuxeo.ecm.core.api.impl.LifeCycleFilter;
043import org.nuxeo.ecm.core.api.security.SecurityConstants;
044import org.nuxeo.ecm.core.schema.FacetNames;
045import org.nuxeo.ecm.core.schema.SchemaManager;
046import org.nuxeo.ecm.platform.publisher.helper.RootSectionFinder;
047import org.nuxeo.runtime.api.Framework;
048
049public abstract class AbstractRootSectionsFinder extends UnrestrictedSessionRunner implements RootSectionFinder {
050
051    public static final String SCHEMA_PUBLISHING = "publishing";
052
053    public static final String SECTIONS_PROPERTY_NAME = "publish:sections";
054
055    protected static Set<String> sectionRootTypes;
056
057    protected static Set<String> sectionTypes;
058
059    protected CoreSession userSession;
060
061    protected List<String> unrestrictedSectionRootFromWorkspaceConfig;
062
063    protected List<String> unrestrictedDefaultSectionRoot;
064
065    protected DocumentModelList accessibleSectionRoots;
066
067    protected DocumentModel currentDocument;
068
069    protected static final Log log = LogFactory.getLog(AbstractRootSectionsFinder.class);
070
071    protected abstract void computeUserSectionRoots(DocumentModel currentDoc);
072
073    protected abstract String buildQuery(String path);
074
075    protected abstract void computeUnrestrictedRoots(CoreSession session);
076
077    public AbstractRootSectionsFinder(CoreSession userSession) {
078        super(userSession);
079        this.userSession = userSession;
080    }
081
082    @Override
083    public void reset() {
084        this.currentDocument = null;
085    }
086
087    @Override
088    public DocumentModelList getAccessibleSectionRoots(DocumentModel currentDoc) {
089        if ((currentDocument == null) || (!currentDocument.getRef().equals(currentDoc.getRef()))) {
090            computeUserSectionRoots(currentDoc);
091        }
092        return accessibleSectionRoots;
093    }
094
095    @Override
096    public DocumentModelList getSectionRootsForWorkspace(DocumentModel currentDoc, boolean addDefaultSectionRoots)
097            {
098        if ((currentDocument == null) || (!currentDocument.getRef().equals(currentDoc.getRef()))) {
099            computeUserSectionRoots(currentDoc);
100        }
101
102        if (unrestrictedDefaultSectionRoot.isEmpty() && addDefaultSectionRoots) {
103            if (unrestrictedDefaultSectionRoot == null || unrestrictedDefaultSectionRoot.isEmpty()) {
104                DocumentModelList defaultSectionRoots = getDefaultSectionRoots(session);
105                unrestrictedDefaultSectionRoot = new ArrayList<String>();
106                for (DocumentModel root : defaultSectionRoots) {
107                    unrestrictedDefaultSectionRoot.add(root.getPathAsString());
108                }
109            }
110        }
111
112        return getFiltredSectionRoots(unrestrictedSectionRootFromWorkspaceConfig, true);
113    }
114
115    @Override
116    public DocumentModelList getSectionRootsForWorkspace(DocumentModel currentDoc) {
117        return getSectionRootsForWorkspace(currentDoc, false);
118    }
119
120    @Override
121    public DocumentModelList getDefaultSectionRoots(boolean onlyHeads, boolean addDefaultSectionRoots)
122            {
123        if (unrestrictedDefaultSectionRoot == null) {
124            computeUserSectionRoots(null);
125        }
126
127        if (unrestrictedDefaultSectionRoot.isEmpty() && addDefaultSectionRoots) {
128            if (unrestrictedDefaultSectionRoot == null || unrestrictedDefaultSectionRoot.isEmpty()) {
129                DocumentModelList defaultSectionRoots = getDefaultSectionRoots(session);
130                unrestrictedDefaultSectionRoot = new ArrayList<String>();
131                for (DocumentModel root : defaultSectionRoots) {
132                    unrestrictedDefaultSectionRoot.add(root.getPathAsString());
133                }
134            }
135        }
136
137        return getFiltredSectionRoots(unrestrictedDefaultSectionRoot, onlyHeads);
138    }
139
140    @Override
141    public DocumentModelList getDefaultSectionRoots(boolean onlyHeads) {
142        return getDefaultSectionRoots(onlyHeads, false);
143    }
144
145    protected DocumentModelList getFiltredSectionRoots(List<String> rootPaths, boolean onlyHeads)
146            {
147        List<DocumentRef> filtredDocRef = new ArrayList<DocumentRef>();
148        List<DocumentRef> trashedDocRef = new ArrayList<DocumentRef>();
149
150        for (String rootPath : rootPaths) {
151            DocumentRef rootRef = new PathRef(rootPath);
152            if (userSession.hasPermission(rootRef, SecurityConstants.READ)) {
153                filtredDocRef.add(rootRef);
154            } else {
155                DocumentModelList accessibleSections = userSession.query(buildQuery(rootPath));
156                for (DocumentModel section : accessibleSections) {
157                    if (onlyHeads
158                            && ((filtredDocRef.contains(section.getParentRef())) || (trashedDocRef.contains(section.getParentRef())))) {
159                        trashedDocRef.add(section.getRef());
160                    } else {
161                        filtredDocRef.add(section.getRef());
162                    }
163                }
164            }
165        }
166        DocumentModelList documents = userSession.getDocuments(filtredDocRef.toArray(new DocumentRef[filtredDocRef.size()]));
167        return filterDocuments(documents);
168    }
169
170    protected DocumentModelList filterDocuments(DocumentModelList docs) {
171        DocumentModelList filteredDocuments = new DocumentModelListImpl();
172        FacetFilter facetFilter = new FacetFilter(Arrays.asList(FacetNames.FOLDERISH),
173                Arrays.asList(FacetNames.HIDDEN_IN_NAVIGATION));
174        LifeCycleFilter lfFilter = new LifeCycleFilter(LifeCycleConstants.DELETED_STATE, false);
175        Filter filter = new CompoundFilter(facetFilter, lfFilter);
176        for (DocumentModel doc : docs) {
177            if (filter.accept(doc)) {
178                filteredDocuments.add(doc);
179            }
180        }
181        return filteredDocuments;
182    }
183
184    protected DocumentModelList getDefaultSectionRoots(CoreSession session) {
185        // XXX replace by a query !!!
186        DocumentModelList sectionRoots = new DocumentModelListImpl();
187        DocumentModelList domains = session.getChildren(session.getRootDocument().getRef(), "Domain");
188        for (DocumentModel domain : domains) {
189            for (String sectionRootNameType : getSectionRootTypes()) {
190                DocumentModelList children = session.getChildren(domain.getRef(), sectionRootNameType);
191                sectionRoots.addAll(children);
192            }
193        }
194        return sectionRoots;
195    }
196
197    protected DocumentModelList getSectionRootsFromWorkspaceConfig(DocumentModel workspace, CoreSession session)
198            {
199
200        DocumentModelList selectedSections = new DocumentModelListImpl();
201
202        if (workspace.hasSchema(SCHEMA_PUBLISHING)) {
203            String[] sectionIdsArray = (String[]) workspace.getPropertyValue(SECTIONS_PROPERTY_NAME);
204
205            List<String> sectionIdsList = new ArrayList<String>();
206
207            if (sectionIdsArray != null && sectionIdsArray.length > 0) {
208                sectionIdsList = Arrays.asList(sectionIdsArray);
209            }
210
211            if (sectionIdsList != null) {
212                for (String currentSectionId : sectionIdsList) {
213                    try {
214                        DocumentModel sectionToAdd = session.getDocument(new IdRef(currentSectionId));
215                        selectedSections.add(sectionToAdd);
216                    } catch (DocumentNotFoundException e) {
217                        log.warn("Section with ID=" + currentSectionId + " not found for document with ID="
218                                + workspace.getId());
219                    }
220                }
221            }
222        }
223        return selectedSections;
224    }
225
226    @Override
227    public void run() {
228        computeUnrestrictedRoots(session);
229    }
230
231    protected Set<String> getSectionRootTypes() {
232        if (sectionRootTypes == null) {
233            sectionRootTypes = getTypeNamesForFacet(FacetNames.MASTER_PUBLISH_SPACE);
234            if (sectionRootTypes == null) {
235                sectionRootTypes = new HashSet<String>();
236            }
237        }
238        return sectionRootTypes;
239    }
240
241    protected Set<String> getTypeNamesForFacet(String facetName) {
242        SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
243        Set<String> publishRoots = schemaManager.getDocumentTypeNamesForFacet(facetName);
244        if (publishRoots == null || publishRoots.isEmpty()) {
245            return null;
246        }
247        return publishRoots;
248    }
249
250    protected Set<String> getSectionTypes() {
251        if (sectionTypes == null) {
252            sectionTypes = getTypeNamesForFacet(FacetNames.MASTER_PUBLISH_SPACE);
253            if (sectionTypes == null) {
254                sectionTypes = new HashSet<String>();
255            }
256        }
257        return sectionTypes;
258    }
259
260}