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