001/*
002 * (C) Copyright 2006-2018 Nuxeo (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 - initial API and implementation
018 */
019package org.nuxeo.ecm.platform.content.template.service;
020
021import java.util.HashMap;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.commons.logging.Log;
026import org.apache.commons.logging.LogFactory;
027import org.nuxeo.ecm.core.api.CoreSession;
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.core.repository.RepositoryInitializationHandler;
030import org.nuxeo.ecm.platform.content.template.listener.RepositoryInitializationListener;
031import org.nuxeo.runtime.model.ComponentContext;
032import org.nuxeo.runtime.model.ComponentInstance;
033import org.nuxeo.runtime.model.DefaultComponent;
034
035public class ContentTemplateServiceImpl extends DefaultComponent implements ContentTemplateService {
036
037    public static final String NAME = "org.nuxeo.ecm.platform.content.template.service.TemplateService";
038
039    public static final String FACTORY_DECLARATION_EP = "factory";
040
041    public static final String FACTORY_BINDING_EP = "factoryBinding";
042
043    public static final String POST_CONTENT_CREATION_HANDLERS_EP = "postContentCreationHandlers";
044
045    private static final Log log = LogFactory.getLog(ContentTemplateServiceImpl.class);
046
047    private final Map<String, ContentFactoryDescriptor> factories = new HashMap<>();
048
049    private FactoryBindingRegistry factoryBindings;
050
051    private PostContentCreationHandlerRegistry postContentCreationHandlers;
052
053    private RepositoryInitializationHandler initializationHandler;
054
055    @Override
056    public void activate(ComponentContext context) {
057        // register our Repo init listener
058        initializationHandler = new RepositoryInitializationListener();
059        initializationHandler.install();
060
061        factoryBindings = new FactoryBindingRegistry();
062        postContentCreationHandlers = new PostContentCreationHandlerRegistry();
063    }
064
065    @Override
066    public void deactivate(ComponentContext context) {
067        if (initializationHandler != null) {
068            initializationHandler.uninstall();
069        }
070    }
071
072    @Override
073    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
074        if (extensionPoint.equals(FACTORY_DECLARATION_EP)) {
075            // store factories
076            ContentFactoryDescriptor descriptor = (ContentFactoryDescriptor) contribution;
077            factories.put(descriptor.getName(), descriptor);
078        } else if (extensionPoint.equals(FACTORY_BINDING_EP)) {
079            // store factories binding to types
080            FactoryBindingDescriptor descriptor = (FactoryBindingDescriptor) contribution;
081            if (factories.containsKey(descriptor.getFactoryName())) {
082                factoryBindings.addContribution(descriptor);
083            } else {
084                log.error("Factory Binding" + descriptor.getName() + " can not be registered since Factory "
085                        + descriptor.getFactoryName() + " is not registered");
086            }
087        } else if (POST_CONTENT_CREATION_HANDLERS_EP.equals(extensionPoint)) {
088            PostContentCreationHandlerDescriptor descriptor = (PostContentCreationHandlerDescriptor) contribution;
089            postContentCreationHandlers.addContribution(descriptor);
090        }
091    }
092
093    @Override
094    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
095        if (extensionPoint.equals(FACTORY_DECLARATION_EP)) {
096            ContentFactoryDescriptor descriptor = (ContentFactoryDescriptor) contribution;
097            factories.remove(descriptor.getName());
098        } else if (extensionPoint.equals(FACTORY_BINDING_EP)) {
099            FactoryBindingDescriptor descriptor = (FactoryBindingDescriptor) contribution;
100            factoryBindings.removeContribution(descriptor);
101        } else if (POST_CONTENT_CREATION_HANDLERS_EP.equals(extensionPoint)) {
102            PostContentCreationHandlerDescriptor descriptor = (PostContentCreationHandlerDescriptor) contribution;
103            postContentCreationHandlers.removeContribution(descriptor);
104        }
105    }
106
107    /*
108     * Instantiate a new factory for each caller, because factories are actually stateful, they contain the session of
109     * their root.
110     */
111    @Override
112    public ContentFactory getFactoryForType(String documentType) {
113        FactoryBindingDescriptor descriptor = factoryBindings.getContribution(documentType);
114        if (descriptor == null || !documentType.equals(descriptor.getTargetType())) {
115            return null;
116        }
117        return getFactoryInstance(descriptor);
118    }
119
120    /*
121     * Instantiate a new factory for each caller, because factories are actually stateful, they contain the session of
122     * their root.
123     */
124    public ContentFactory getFactoryForFacet(String facet) {
125        FactoryBindingDescriptor descriptor = factoryBindings.getContribution(facet);
126        if (descriptor == null || !facet.equals(descriptor.getTargetFacet())) {
127            return null;
128        }
129        return getFactoryInstance(descriptor);
130    }
131
132    protected ContentFactory getFactoryInstance(FactoryBindingDescriptor descriptor) {
133        ContentFactoryDescriptor factoryDescriptor = factories.get(descriptor.getFactoryName());
134        try {
135            ContentFactory factory = factoryDescriptor.getClassName().getConstructor().newInstance();
136            boolean factoryOK = factory.initFactory(descriptor.getOptions(), descriptor.getRootAcl(),
137                    descriptor.getTemplate());
138            if (!factoryOK) {
139                log.error("Error while initializing instance of factory " + factoryDescriptor.getName());
140                return null;
141            }
142            return factory;
143        } catch (ReflectiveOperationException e) {
144            log.error(
145                    "Error while creating instance of factory " + factoryDescriptor.getName() + " :" + e.getMessage());
146            return null;
147        }
148    }
149
150    @Override
151    public void executeFactoryForType(DocumentModel createdDocument) {
152        ContentFactory factory = getFactoryForType(createdDocument.getType());
153        if (factory != null) {
154            factory.createContentStructure(createdDocument);
155        }
156        Set<String> facets = createdDocument.getFacets();
157        for (String facet : facets) {
158            factory = getFactoryForFacet(facet);
159            if (factory != null) {
160                factory.createContentStructure(createdDocument);
161            }
162        }
163    }
164
165    @Override
166    public void executePostContentCreationHandlers(CoreSession session) {
167        for (PostContentCreationHandler handler : postContentCreationHandlers.getOrderedHandlers()) {
168            handler.execute(session);
169        }
170    }
171
172    // for testing
173    public Map<String, ContentFactoryDescriptor> getFactories() {
174        return factories;
175    }
176
177    public Map<String, FactoryBindingDescriptor> getFactoryBindings() {
178        return factoryBindings.toMap();
179    }
180
181}