001/*
002 * (C) Copyright 2006-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 *     Nuxeo
018 */
019
020package org.nuxeo.ecm.platform.publisher.impl.service;
021
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.common.utils.Path;
031import org.nuxeo.ecm.core.api.CoreInstance;
032import org.nuxeo.ecm.core.api.CoreSession;
033import org.nuxeo.ecm.core.api.CoreSessionService;
034import org.nuxeo.ecm.core.api.DocumentLocation;
035import org.nuxeo.ecm.core.api.DocumentModel;
036import org.nuxeo.ecm.core.api.NuxeoException;
037import org.nuxeo.ecm.core.api.repository.RepositoryManager;
038import org.nuxeo.ecm.core.repository.RepositoryService;
039import org.nuxeo.ecm.platform.publisher.api.PublicationNode;
040import org.nuxeo.ecm.platform.publisher.api.PublicationTree;
041import org.nuxeo.ecm.platform.publisher.api.PublicationTreeNotAvailable;
042import org.nuxeo.ecm.platform.publisher.api.PublishedDocument;
043import org.nuxeo.ecm.platform.publisher.api.PublishedDocumentFactory;
044import org.nuxeo.ecm.platform.publisher.api.PublisherService;
045import org.nuxeo.ecm.platform.publisher.api.RemotePublicationTreeManager;
046import org.nuxeo.ecm.platform.publisher.descriptors.PublicationTreeConfigDescriptor;
047import org.nuxeo.ecm.platform.publisher.descriptors.PublicationTreeDescriptor;
048import org.nuxeo.ecm.platform.publisher.descriptors.PublishedDocumentFactoryDescriptor;
049import org.nuxeo.ecm.platform.publisher.descriptors.RootSectionFinderFactoryDescriptor;
050import org.nuxeo.ecm.platform.publisher.helper.PublicationRelationHelper;
051import org.nuxeo.ecm.platform.publisher.helper.RootSectionFinder;
052import org.nuxeo.ecm.platform.publisher.helper.RootSectionFinderFactory;
053import org.nuxeo.ecm.platform.publisher.impl.finder.DefaultRootSectionsFinder;
054import org.nuxeo.ecm.platform.publisher.rules.ValidatorsRule;
055import org.nuxeo.ecm.platform.publisher.rules.ValidatorsRuleDescriptor;
056import org.nuxeo.runtime.api.Framework;
057import org.nuxeo.runtime.model.ComponentContext;
058import org.nuxeo.runtime.model.ComponentInstance;
059import org.nuxeo.runtime.model.DefaultComponent;
060import org.nuxeo.runtime.transaction.TransactionHelper;
061
062/**
063 * POJO implementation of the publisher service Implements both {@link PublisherService} and
064 * {@link RemotePublicationTreeManager}.
065 *
066 * @author tiry
067 */
068public class PublisherServiceImpl extends DefaultComponent implements PublisherService, RemotePublicationTreeManager {
069
070    private final Log log = LogFactory.getLog(PublisherServiceImpl.class);
071
072    protected Map<String, PublicationTreeDescriptor> treeDescriptors = new HashMap<String, PublicationTreeDescriptor>();
073
074    protected Map<String, PublishedDocumentFactoryDescriptor> factoryDescriptors = new HashMap<String, PublishedDocumentFactoryDescriptor>();
075
076    protected Map<String, PublicationTreeConfigDescriptor> treeConfigDescriptors = new HashMap<String, PublicationTreeConfigDescriptor>();
077
078    protected Map<String, ValidatorsRuleDescriptor> validatorsRuleDescriptors = new HashMap<String, ValidatorsRuleDescriptor>();
079
080    protected Map<String, PublicationTreeConfigDescriptor> pendingDescriptors = new HashMap<String, PublicationTreeConfigDescriptor>();
081
082    protected Map<String, PublicationTree> liveTrees = new HashMap<String, PublicationTree>();
083
084    protected RootSectionFinderFactory rootSectionFinderFactory = null;
085
086    // Store association between treeSid and CoreSession that was opened locally
087    // for them : this unable proper cleanup of allocated sessions
088    protected Map<String, String> remoteLiveTrees = new HashMap<String, String>();
089
090    public static final String TREE_EP = "tree";
091
092    public static final String TREE_CONFIG_EP = "treeInstance";
093
094    public static final String VALIDATORS_RULE_EP = "validatorsRule";
095
096    public static final String FACTORY_EP = "factory";
097
098    public static final String ROOT_SECTION_FINDER_FACTORY_EP = "rootSectionFinderFactory";
099
100    protected static final String ROOT_PATH_KEY = "RootPath";
101
102    protected static final String RELATIVE_ROOT_PATH_KEY = "RelativeRootPath";
103
104    @Override
105    public void applicationStarted(ComponentContext context) {
106        RepositoryService repositoryService = Framework.getService(RepositoryService.class);
107        if (repositoryService == null) {
108            // RepositoryService failed to start, no need to go further
109            return;
110        }
111        boolean txWasStartedOutsideComponent = TransactionHelper.isTransactionActiveOrMarkedRollback();
112
113        if (txWasStartedOutsideComponent || TransactionHelper.startTransaction()) {
114            boolean completedAbruptly = true;
115            try {
116                doApplicationStarted();
117                completedAbruptly = false;
118            } finally {
119                if (completedAbruptly) {
120                    TransactionHelper.setTransactionRollbackOnly();
121                }
122                if (!txWasStartedOutsideComponent) {
123                    TransactionHelper.commitOrRollbackTransaction();
124                }
125            }
126        } else {
127            doApplicationStarted();
128        }
129    }
130
131    protected void doApplicationStarted() {
132        ClassLoader jbossCL = Thread.currentThread().getContextClassLoader();
133        ClassLoader nuxeoCL = PublisherServiceImpl.class.getClassLoader();
134        try {
135            Thread.currentThread().setContextClassLoader(nuxeoCL);
136            log.info("Publisher Service initialization");
137            registerPendingDescriptors();
138        } finally {
139            Thread.currentThread().setContextClassLoader(jbossCL);
140            log.debug("JBoss ClassLoader restored");
141        }
142    }
143
144    @Override
145    public void activate(ComponentContext context) {
146        liveTrees = new HashMap<String, PublicationTree>();
147        treeDescriptors = new HashMap<String, PublicationTreeDescriptor>();
148        factoryDescriptors = new HashMap<String, PublishedDocumentFactoryDescriptor>();
149        treeConfigDescriptors = new HashMap<String, PublicationTreeConfigDescriptor>();
150        validatorsRuleDescriptors = new HashMap<String, ValidatorsRuleDescriptor>();
151        pendingDescriptors = new HashMap<String, PublicationTreeConfigDescriptor>();
152    }
153
154    // for testing cleanup
155    public int getLiveTreeCount() {
156        return liveTrees.size();
157    }
158
159    public PublicationTree getTreeBySid(String sid) {
160        return liveTrees.get(sid);
161    }
162
163    @Override
164    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
165
166        log.debug("Registry contribution for EP " + extensionPoint);
167
168        if (TREE_EP.equals(extensionPoint)) {
169            PublicationTreeDescriptor desc = (PublicationTreeDescriptor) contribution;
170            treeDescriptors.put(desc.getName(), desc);
171        } else if (TREE_CONFIG_EP.equals(extensionPoint)) {
172            PublicationTreeConfigDescriptor desc = (PublicationTreeConfigDescriptor) contribution;
173            registerTreeConfig(desc);
174        } else if (FACTORY_EP.equals(extensionPoint)) {
175            PublishedDocumentFactoryDescriptor desc = (PublishedDocumentFactoryDescriptor) contribution;
176            factoryDescriptors.put(desc.getName(), desc);
177        } else if (VALIDATORS_RULE_EP.equals(extensionPoint)) {
178            ValidatorsRuleDescriptor desc = (ValidatorsRuleDescriptor) contribution;
179            validatorsRuleDescriptors.put(desc.getName(), desc);
180        } else if (ROOT_SECTION_FINDER_FACTORY_EP.equals(extensionPoint)) {
181            RootSectionFinderFactoryDescriptor desc = (RootSectionFinderFactoryDescriptor) contribution;
182            try {
183                rootSectionFinderFactory = desc.getFactory().newInstance();
184            } catch (ReflectiveOperationException t) {
185                log.error("Unable to load custom RootSectionFinderFactory", t);
186            }
187        }
188    }
189
190    protected void registerTreeConfig(PublicationTreeConfigDescriptor desc) {
191        if (desc.getParameters().get("RelativeRootPath") != null) {
192            pendingDescriptors.put(desc.getName(), desc);
193        } else {
194            treeConfigDescriptors.put(desc.getName(), desc);
195        }
196    }
197
198    @Override
199    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
200        if (contribution instanceof PublicationTreeDescriptor) {
201            treeDescriptors.remove(((PublicationTreeDescriptor) contribution).getName());
202        } else if (contribution instanceof PublicationTreeConfigDescriptor) {
203            String name = ((PublicationTreeConfigDescriptor) contribution).getName();
204            pendingDescriptors.remove(name);
205            treeConfigDescriptors.remove(name);
206        } else if (contribution instanceof ValidatorsRuleDescriptor) {
207            validatorsRuleDescriptors.remove(((ValidatorsRuleDescriptor) contribution).getName());
208        } else if (contribution instanceof RootSectionFinderFactoryDescriptor) {
209            rootSectionFinderFactory = null;
210        }
211    }
212
213    protected String computeTreeSessionId(String treeConfigName, CoreSession coreSession) {
214        return computeTreeSessionId(treeConfigName, coreSession.getSessionId());
215    }
216
217    protected String computeTreeSessionId(String treeConfigName, String sid) {
218        return treeConfigName + sid;
219    }
220
221    @Override
222    public List<String> getAvailablePublicationTree() {
223        List<String> treeConfigs = new ArrayList<String>();
224        treeConfigs.addAll(treeConfigDescriptors.keySet());
225        return treeConfigs;
226    }
227
228    @Override
229    public Map<String, String> getAvailablePublicationTrees() {
230        Map<String, String> trees = new HashMap<String, String>();
231        for (PublicationTreeConfigDescriptor desc : treeConfigDescriptors.values()) {
232            String title = desc.getTitle() == null ? desc.getName() : desc.getTitle();
233            trees.put(desc.getName(), title);
234        }
235        return trees;
236    }
237
238    @Override
239    public PublicationTree getPublicationTree(String treeName, CoreSession coreSession, Map<String, String> params)
240            throws PublicationTreeNotAvailable {
241        return getPublicationTree(treeName, coreSession, params, null);
242    }
243
244    @Override
245    public PublicationTree getPublicationTree(String treeName, CoreSession coreSession, Map<String, String> params,
246            DocumentModel currentDocument) throws PublicationTreeNotAvailable {
247        PublicationTree tree = getOrBuildTree(treeName, coreSession, params);
248        if (tree == null) {
249            return null;
250        }
251        if (currentDocument != null) {
252            tree.setCurrentDocument(currentDocument);
253        }
254        return new ProxyTree(tree, tree.getSessionId());
255    }
256
257    @Override
258    public Map<String, String> initRemoteSession(String treeConfigName, Map<String, String> params) {
259        CoreSession coreSession = CoreInstance.openCoreSession(null);
260        PublicationTree tree = getPublicationTree(treeConfigName, coreSession, params);
261
262        remoteLiveTrees.put(tree.getSessionId(), coreSession.getSessionId());
263
264        Map<String, String> res = new HashMap<String, String>();
265        res.put("sessionId", tree.getSessionId());
266        res.put("title", tree.getTitle());
267        res.put("nodeType", tree.getNodeType());
268        res.put("treeName", tree.getConfigName());
269        res.put("path", tree.getPath());
270
271        return res;
272    }
273
274    @Override
275    public void release(String sid) {
276        PublicationTree tree;
277
278        if (liveTrees.containsKey(sid)) {
279            tree = liveTrees.get(sid);
280            tree.release();
281            liveTrees.remove(sid);
282        }
283        if (remoteLiveTrees.containsKey(sid)) {
284            // close here session opened for remote trees
285            String sessionId = remoteLiveTrees.get(sid);
286            CoreSession remoteSession = Framework.getService(CoreSessionService.class).getCoreSession(sessionId);
287            remoteSession.close();
288            remoteLiveTrees.remove(sid);
289        }
290    }
291
292    @Override
293    public void releaseAllTrees(String sessionId) {
294        for (String configName : treeConfigDescriptors.keySet()) {
295            String treeid = computeTreeSessionId(configName, sessionId);
296            release(treeid);
297        }
298    }
299
300    protected PublicationTree getOrBuildTree(String treeConfigName, CoreSession coreSession, Map<String, String> params)
301            throws PublicationTreeNotAvailable {
302        String key = computeTreeSessionId(treeConfigName, coreSession);
303        PublicationTree tree;
304        if (liveTrees.containsKey(key)) {
305            tree = liveTrees.get(key);
306        } else {
307            tree = buildTree(key, treeConfigName, coreSession, params);
308            if (tree != null) {
309                liveTrees.put(key, tree);
310            }
311        }
312        return tree;
313    }
314
315    protected PublicationTree buildTree(String sid, String treeConfigName, CoreSession coreSession,
316            Map<String, String> params) throws PublicationTreeNotAvailable {
317        PublicationTreeConfigDescriptor config = getPublicationTreeConfigDescriptor(treeConfigName);
318        Map<String, String> allParameters = computeAllParameters(config, params);
319        PublicationTreeDescriptor treeDescriptor = getPublicationTreeDescriptor(config);
320        PublishedDocumentFactory publishedDocumentFactory = getPublishedDocumentFactory(config, treeDescriptor,
321                coreSession, allParameters);
322        return getPublicationTree(treeDescriptor, sid, coreSession, allParameters, publishedDocumentFactory,
323                config.getName(), config.getTitle());
324    }
325
326    protected Map<String, String> computeAllParameters(PublicationTreeConfigDescriptor config,
327            Map<String, String> params) {
328        final Map<String, String> allParameters = config.getParameters();
329        if (params != null) {
330            allParameters.putAll(params);
331        }
332        return allParameters;
333    }
334
335    protected PublishedDocumentFactory getPublishedDocumentFactory(PublicationTreeConfigDescriptor config,
336            PublicationTreeDescriptor treeDescriptor, CoreSession coreSession, Map<String, String> params) {
337        PublishedDocumentFactoryDescriptor factoryDesc = getPublishedDocumentFactoryDescriptor(config, treeDescriptor);
338        ValidatorsRule validatorsRule = getValidatorsRule(factoryDesc);
339
340        PublishedDocumentFactory factory;
341        try {
342            factory = factoryDesc.getKlass().newInstance();
343        } catch (ReflectiveOperationException e) {
344            throw new NuxeoException("Error while creating factory " + factoryDesc.getName(), e);
345        }
346        factory.init(coreSession, validatorsRule, params);
347        return factory;
348    }
349
350    protected ValidatorsRule getValidatorsRule(PublishedDocumentFactoryDescriptor factoryDesc) {
351        String validatorsRuleName = factoryDesc.getValidatorsRuleName();
352        ValidatorsRule validatorsRule = null;
353        if (validatorsRuleName != null) {
354            ValidatorsRuleDescriptor validatorsRuleDesc = validatorsRuleDescriptors.get(validatorsRuleName);
355            if (validatorsRuleDesc == null) {
356                throw new NuxeoException("Unable to find validatorsRule" + validatorsRuleName);
357            }
358            try {
359                validatorsRule = validatorsRuleDesc.getKlass().newInstance();
360            } catch (ReflectiveOperationException e) {
361                throw new NuxeoException("Error while creating validatorsRule " + validatorsRuleName, e);
362            }
363        }
364        return validatorsRule;
365    }
366
367    protected PublishedDocumentFactoryDescriptor getPublishedDocumentFactoryDescriptor(
368            PublicationTreeConfigDescriptor config, PublicationTreeDescriptor treeDescriptor) {
369        String factoryName = config.getFactory();
370        if (factoryName == null) {
371            factoryName = treeDescriptor.getFactory();
372        }
373
374        PublishedDocumentFactoryDescriptor factoryDesc = factoryDescriptors.get(factoryName);
375        if (factoryDesc == null) {
376            throw new NuxeoException("Unable to find factory" + factoryName);
377        }
378        return factoryDesc;
379    }
380
381    protected PublicationTreeConfigDescriptor getPublicationTreeConfigDescriptor(String treeConfigName) {
382        if (!treeConfigDescriptors.containsKey(treeConfigName)) {
383            throw new NuxeoException("Unknow treeConfig :" + treeConfigName);
384        }
385        return treeConfigDescriptors.get(treeConfigName);
386    }
387
388    protected PublicationTreeDescriptor getPublicationTreeDescriptor(PublicationTreeConfigDescriptor config) {
389        String treeImplName = config.getTree();
390        if (!treeDescriptors.containsKey(treeImplName)) {
391            throw new NuxeoException("Unknow treeImplementation :" + treeImplName);
392        }
393        return treeDescriptors.get(treeImplName);
394    }
395
396    protected PublicationTree getPublicationTree(PublicationTreeDescriptor treeDescriptor, String sid,
397            CoreSession coreSession, Map<String, String> parameters, PublishedDocumentFactory factory,
398            String configName, String treeTitle) throws PublicationTreeNotAvailable {
399        PublicationTree treeImpl;
400        try {
401            treeImpl = treeDescriptor.getKlass().newInstance();
402        } catch (ReflectiveOperationException e) {
403            throw new NuxeoException("Error while creating tree implementation", e);
404        }
405        treeImpl.initTree(sid, coreSession, parameters, factory, configName, treeTitle);
406        return treeImpl;
407    }
408
409    @Override
410    public PublishedDocument publish(DocumentModel doc, PublicationNode targetNode) {
411        return publish(doc, targetNode, null);
412    }
413
414    @Override
415    public PublishedDocument publish(DocumentModel doc, PublicationNode targetNode, Map<String, String> params) {
416
417        PublicationTree tree = liveTrees.get(targetNode.getSessionId());
418        if (tree != null) {
419            return tree.publish(doc, targetNode, params);
420        } else {
421            throw new NuxeoException("Calling getChildrenNodes on a closed tree");
422        }
423    }
424
425    @Override
426    public void unpublish(DocumentModel doc, PublicationNode targetNode) {
427        PublicationTree tree = liveTrees.get(targetNode.getSessionId());
428        if (tree != null) {
429            tree.unpublish(doc, targetNode);
430        } else {
431            throw new NuxeoException("Calling getChildrenNodes on a closed tree");
432        }
433    }
434
435    @Override
436    public void unpublish(String sid, PublishedDocument publishedDocument) {
437        PublicationTree tree = liveTrees.get(sid);
438        if (tree != null) {
439            tree.unpublish(publishedDocument);
440        } else {
441            throw new NuxeoException("Calling getChildrenNodes on a closed tree");
442        }
443    }
444
445    @Override
446    public List<PublishedDocument> getChildrenDocuments(PublicationNode node) {
447
448        PublicationTree tree = liveTrees.get(node.getSessionId());
449        if (tree != null) {
450            return tree.getPublishedDocumentInNode(tree.getNodeByPath(node.getPath()));
451        } else {
452            throw new NuxeoException("Calling getChildrenDocuments on a closed tree");
453        }
454    }
455
456    protected List<PublicationNode> makeRemotable(List<PublicationNode> nodes, String sid) {
457        List<PublicationNode> remoteNodes = new ArrayList<PublicationNode>();
458
459        for (PublicationNode node : nodes) {
460            remoteNodes.add(new ProxyNode(node, sid));
461        }
462
463        return remoteNodes;
464    }
465
466    @Override
467    public List<PublicationNode> getChildrenNodes(PublicationNode node) {
468        String sid = node.getSessionId();
469        PublicationTree tree = liveTrees.get(sid);
470        if (tree != null) {
471            return makeRemotable(tree.getNodeByPath(node.getPath()).getChildrenNodes(), sid);
472        } else {
473            throw new NuxeoException("Calling getChildrenNodes on a closed tree");
474        }
475    }
476
477    @Override
478    public PublicationNode getParent(PublicationNode node) {
479        String sid = node.getSessionId();
480        PublicationTree tree = liveTrees.get(sid);
481        if (tree != null) {
482            PublicationNode liveNode;
483            liveNode = tree.getNodeByPath(node.getPath()).getParent();
484            if (liveNode == null) {
485                return null;
486            }
487            return new ProxyNode(liveNode, sid);
488        } else {
489            log.error("Calling getParent on a closed tree");
490            return null;
491        }
492    }
493
494    @Override
495    public PublicationNode getNodeByPath(String sid, String path) {
496        PublicationTree tree = liveTrees.get(sid);
497        if (tree != null) {
498            return new ProxyNode(tree.getNodeByPath(path), sid);
499        } else {
500            throw new NuxeoException("Calling getNodeByPath on a closed tree");
501        }
502    }
503
504    @Override
505    public List<PublishedDocument> getExistingPublishedDocument(String sid, DocumentLocation docLoc) {
506        PublicationTree tree = liveTrees.get(sid);
507        if (tree != null) {
508            return tree.getExistingPublishedDocument(docLoc);
509        } else {
510            throw new NuxeoException("Calling getNodeByPath on a closed tree");
511        }
512    }
513
514    @Override
515    public List<PublishedDocument> getPublishedDocumentInNode(PublicationNode node) {
516        String sid = node.getSessionId();
517        PublicationTree tree = liveTrees.get(sid);
518        if (tree != null) {
519            return tree.getPublishedDocumentInNode(tree.getNodeByPath(node.getPath()));
520        } else {
521            throw new NuxeoException("Calling getPublishedDocumentInNode on a closed tree");
522        }
523    }
524
525    @Override
526    public void setCurrentDocument(String sid, DocumentModel currentDocument) {
527        PublicationTree tree = liveTrees.get(sid);
528        if (tree != null) {
529            tree.setCurrentDocument(currentDocument);
530        } else {
531            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
532        }
533    }
534
535    @Override
536    public void validatorPublishDocument(String sid, PublishedDocument publishedDocument, String comment) {
537        PublicationTree tree = liveTrees.get(sid);
538        if (tree != null) {
539            tree.validatorPublishDocument(publishedDocument, comment);
540        } else {
541            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
542        }
543    }
544
545    @Override
546    public void validatorRejectPublication(String sid, PublishedDocument publishedDocument, String comment) {
547        PublicationTree tree = liveTrees.get(sid);
548        if (tree != null) {
549            tree.validatorRejectPublication(publishedDocument, comment);
550        } else {
551            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
552        }
553    }
554
555    @Override
556    public boolean canPublishTo(String sid, PublicationNode publicationNode) {
557        PublicationTree tree = liveTrees.get(sid);
558        if (tree != null) {
559            return tree.canPublishTo(publicationNode);
560        } else {
561            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
562        }
563    }
564
565    @Override
566    public boolean canUnpublish(String sid, PublishedDocument publishedDocument) {
567        PublicationTree tree = liveTrees.get(sid);
568        if (tree != null) {
569            return tree.canUnpublish(publishedDocument);
570        } else {
571            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
572        }
573    }
574
575    @Override
576    public boolean canManagePublishing(String sid, PublishedDocument publishedDocument) {
577        PublicationTree tree = liveTrees.get(sid);
578        if (tree != null) {
579            return tree.canManagePublishing(publishedDocument);
580        } else {
581            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
582        }
583    }
584
585    @Override
586    public boolean isPublishedDocument(DocumentModel documentModel) {
587        return PublicationRelationHelper.isPublished(documentModel);
588    }
589
590    @Override
591    public PublicationTree getPublicationTreeFor(DocumentModel doc, CoreSession coreSession) {
592        PublicationTree tree = null;
593        try {
594            tree = PublicationRelationHelper.getPublicationTreeUsedForPublishing(doc, coreSession);
595        } catch (NuxeoException e) {
596            // TODO catch proper exception
597            log.error("Unable to get PublicationTree for " + doc.getPathAsString()
598                    + ". Fallback on first PublicationTree accepting this document.", e);
599            for (String treeName : treeConfigDescriptors.keySet()) {
600                tree = getPublicationTree(treeName, coreSession, null);
601                if (tree.isPublicationNode(doc)) {
602                    break;
603                }
604            }
605        }
606        return tree;
607    }
608
609    @Override
610    public boolean hasValidationTask(String sid, PublishedDocument publishedDocument) {
611        PublicationTree tree = liveTrees.get(sid);
612        if (tree != null) {
613            return tree.hasValidationTask(publishedDocument);
614        } else {
615            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
616        }
617    }
618
619    @Override
620    public PublishedDocument wrapToPublishedDocument(String sid, DocumentModel documentModel) {
621        PublicationTree tree = liveTrees.get(sid);
622        if (tree != null) {
623            return tree.wrapToPublishedDocument(documentModel);
624        } else {
625            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
626        }
627    }
628
629    @Override
630    public boolean isPublicationNode(String sid, DocumentModel documentModel) {
631        PublicationTree tree = liveTrees.get(sid);
632        if (tree != null) {
633            return tree.isPublicationNode(documentModel);
634        } else {
635            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
636        }
637    }
638
639    @Override
640    public PublicationNode wrapToPublicationNode(String sid, DocumentModel documentModel) {
641        PublicationTree tree = liveTrees.get(sid);
642        if (tree != null) {
643            return tree.wrapToPublicationNode(documentModel);
644        } else {
645            throw new NuxeoException("Calling validatorPublishDocument on a closed tree");
646        }
647    }
648
649    @Override
650    public PublicationNode wrapToPublicationNode(DocumentModel documentModel, CoreSession coreSession)
651            throws PublicationTreeNotAvailable {
652        for (String name : getAvailablePublicationTree()) {
653            PublicationTree tree = getPublicationTree(name, coreSession, null);
654            PublicationTreeConfigDescriptor config = treeConfigDescriptors.get(tree.getConfigName());
655            if (!config.islocalSectionTree()) {
656                // ignore all non local section tree
657                continue;
658            }
659            if (tree.isPublicationNode(documentModel)) {
660                return tree.wrapToPublicationNode(documentModel);
661            }
662        }
663        return null;
664    }
665
666    protected void registerPendingDescriptors() {
667        // TODO what to do with multiple repositories?
668        RepositoryManager repositoryManager = Framework.getService(RepositoryManager.class);
669        String repositoryName = repositoryManager.getDefaultRepositoryName();
670        List<DocumentModel> domains = new DomainsFinder(repositoryName).getDomains();
671        for (DocumentModel domain : domains) {
672            registerTreeConfigFor(domain);
673        }
674    }
675
676    public void registerTreeConfigFor(DocumentModel domain) {
677        for (PublicationTreeConfigDescriptor desc : pendingDescriptors.values()) {
678            PublicationTreeConfigDescriptor newDesc = new PublicationTreeConfigDescriptor(desc);
679            String newTreeName = desc.getName() + "-" + domain.getName();
680            newDesc.setName(newTreeName);
681            Path newPath = domain.getPath();
682            Map<String, String> parameters = newDesc.getParameters();
683            newPath = newPath.append(parameters.remove(RELATIVE_ROOT_PATH_KEY));
684            parameters.put(ROOT_PATH_KEY, newPath.toString());
685            parameters.put(PublisherService.DOMAIN_NAME_KEY, domain.getTitle());
686            treeConfigDescriptors.put(newDesc.getName(), newDesc);
687        }
688    }
689
690    public void unRegisterTreeConfigFor(DocumentModel domain) {
691        unRegisterTreeConfigFor(domain.getName());
692    }
693
694    /**
695     * @since 7.3
696     */
697    public void unRegisterTreeConfigFor(String domainName) {
698        for (PublicationTreeConfigDescriptor desc : pendingDescriptors.values()) {
699            String treeName = desc.getName() + "-" + domainName;
700            treeConfigDescriptors.remove(treeName);
701            for (Iterator<String> it = liveTrees.keySet().iterator(); it.hasNext();) {
702                String entry = it.next();
703                if (entry.startsWith(treeName)) {
704                    it.remove();
705                }
706            }
707        }
708    }
709
710    @Override
711    public Map<String, String> getParametersFor(String treeConfigName) {
712        PublicationTreeConfigDescriptor desc = treeConfigDescriptors.get(treeConfigName);
713        Map<String, String> parameters = new HashMap<String, String>();
714        if (desc != null) {
715            parameters.putAll(desc.getParameters());
716        }
717        return parameters;
718    }
719
720    @Override
721    public RootSectionFinder getRootSectionFinder(CoreSession session) {
722        if (rootSectionFinderFactory != null) {
723            return rootSectionFinderFactory.getRootSectionFinder(session);
724        }
725        return new DefaultRootSectionsFinder(session);
726    }
727}