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