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            DocumentModelList defaultSectionRoots = getDefaultSectionRoots(session);
104            unrestrictedDefaultSectionRoot = new ArrayList<String>();
105            for (DocumentModel root : defaultSectionRoots) {
106                unrestrictedDefaultSectionRoot.add(root.getPathAsString());
107            }
108        }
109
110        return getFiltredSectionRoots(unrestrictedSectionRootFromWorkspaceConfig, true);
111    }
112
113    @Override
114    public DocumentModelList getSectionRootsForWorkspace(DocumentModel currentDoc) {
115        return getSectionRootsForWorkspace(currentDoc, false);
116    }
117
118    @Override
119    public DocumentModelList getDefaultSectionRoots(boolean onlyHeads, boolean addDefaultSectionRoots)
120            {
121        if (unrestrictedDefaultSectionRoot == null) {
122            computeUserSectionRoots(null);
123        }
124
125        if (unrestrictedDefaultSectionRoot.isEmpty() && addDefaultSectionRoots) {
126            DocumentModelList defaultSectionRoots = getDefaultSectionRoots(session);
127            unrestrictedDefaultSectionRoot = new ArrayList<String>();
128            for (DocumentModel root : defaultSectionRoots) {
129                unrestrictedDefaultSectionRoot.add(root.getPathAsString());
130            }
131        }
132
133        return getFiltredSectionRoots(unrestrictedDefaultSectionRoot, onlyHeads);
134    }
135
136    @Override
137    public DocumentModelList getDefaultSectionRoots(boolean onlyHeads) {
138        return getDefaultSectionRoots(onlyHeads, false);
139    }
140
141    protected DocumentModelList getFiltredSectionRoots(List<String> rootPaths, boolean onlyHeads)
142            {
143        List<DocumentRef> filtredDocRef = new ArrayList<DocumentRef>();
144        List<DocumentRef> trashedDocRef = new ArrayList<DocumentRef>();
145
146        for (String rootPath : rootPaths) {
147            DocumentRef rootRef = new PathRef(rootPath);
148            if (userSession.hasPermission(rootRef, SecurityConstants.READ)) {
149                filtredDocRef.add(rootRef);
150            } else {
151                DocumentModelList accessibleSections = userSession.query(buildQuery(rootPath));
152                for (DocumentModel section : accessibleSections) {
153                    if (onlyHeads
154                            && ((filtredDocRef.contains(section.getParentRef())) || (trashedDocRef.contains(section.getParentRef())))) {
155                        trashedDocRef.add(section.getRef());
156                    } else {
157                        filtredDocRef.add(section.getRef());
158                    }
159                }
160            }
161        }
162        DocumentModelList documents = userSession.getDocuments(filtredDocRef.toArray(new DocumentRef[filtredDocRef.size()]));
163        return filterDocuments(documents);
164    }
165
166    protected DocumentModelList filterDocuments(DocumentModelList docs) {
167        DocumentModelList filteredDocuments = new DocumentModelListImpl();
168        FacetFilter facetFilter = new FacetFilter(Arrays.asList(FacetNames.FOLDERISH),
169                Arrays.asList(FacetNames.HIDDEN_IN_NAVIGATION));
170        LifeCycleFilter lfFilter = new LifeCycleFilter(LifeCycleConstants.DELETED_STATE, false);
171        Filter filter = new CompoundFilter(facetFilter, lfFilter);
172        for (DocumentModel doc : docs) {
173            if (filter.accept(doc)) {
174                filteredDocuments.add(doc);
175            }
176        }
177        return filteredDocuments;
178    }
179
180    protected DocumentModelList getDefaultSectionRoots(CoreSession session) {
181        // XXX replace by a query !!!
182        DocumentModelList sectionRoots = new DocumentModelListImpl();
183        DocumentModelList domains = session.getChildren(session.getRootDocument().getRef(), "Domain");
184        for (DocumentModel domain : domains) {
185            for (String sectionRootNameType : getSectionRootTypes()) {
186                DocumentModelList children = session.getChildren(domain.getRef(), sectionRootNameType);
187                sectionRoots.addAll(children);
188            }
189        }
190        return sectionRoots;
191    }
192
193    protected DocumentModelList getSectionRootsFromWorkspaceConfig(DocumentModel workspace, CoreSession session)
194            {
195
196        DocumentModelList selectedSections = new DocumentModelListImpl();
197
198        if (workspace.hasSchema(SCHEMA_PUBLISHING)) {
199            String[] sectionIdsArray = (String[]) workspace.getPropertyValue(SECTIONS_PROPERTY_NAME);
200
201            List<String> sectionIdsList = new ArrayList<String>();
202
203            if (sectionIdsArray != null && sectionIdsArray.length > 0) {
204                sectionIdsList = Arrays.asList(sectionIdsArray);
205            }
206
207            if (sectionIdsList != null) {
208                for (String currentSectionId : sectionIdsList) {
209                    try {
210                        DocumentModel sectionToAdd = session.getDocument(new IdRef(currentSectionId));
211                        selectedSections.add(sectionToAdd);
212                    } catch (DocumentNotFoundException e) {
213                        log.warn("Section with ID=" + currentSectionId + " not found for document with ID="
214                                + workspace.getId());
215                    }
216                }
217            }
218        }
219        return selectedSections;
220    }
221
222    @Override
223    public void run() {
224        computeUnrestrictedRoots(session);
225    }
226
227    protected Set<String> getSectionRootTypes() {
228        if (sectionRootTypes == null) {
229            sectionRootTypes = getTypeNamesForFacet(FacetNames.MASTER_PUBLISH_SPACE);
230            if (sectionRootTypes == null) {
231                sectionRootTypes = new HashSet<String>();
232            }
233        }
234        return sectionRootTypes;
235    }
236
237    protected Set<String> getTypeNamesForFacet(String facetName) {
238        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
239        Set<String> publishRoots = schemaManager.getDocumentTypeNamesForFacet(facetName);
240        if (publishRoots == null || publishRoots.isEmpty()) {
241            return null;
242        }
243        return publishRoots;
244    }
245
246    protected Set<String> getSectionTypes() {
247        if (sectionTypes == null) {
248            sectionTypes = getTypeNamesForFacet(FacetNames.MASTER_PUBLISH_SPACE);
249            if (sectionTypes == null) {
250                sectionTypes = new HashSet<String>();
251            }
252        }
253        return sectionTypes;
254    }
255
256}