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