001/*
002 *  Copyright 2010 Anyware Services
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 */
016package org.ametys.odf.program;
017
018import java.util.Collections;
019import java.util.Set;
020
021import javax.jcr.Node;
022import javax.jcr.RepositoryException;
023
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026
027import org.ametys.cms.content.external.ExternalizableMetadataProviderExtensionPoint;
028import org.ametys.odf.catalog.CatalogsManager;
029import org.ametys.odf.cdmfr.ExportCDMfrManager;
030import org.ametys.odf.course.CourseFactory;
031import org.ametys.plugins.repository.AmetysObject;
032import org.ametys.plugins.repository.AmetysObjectIterable;
033import org.ametys.plugins.repository.AmetysObjectResolver;
034import org.ametys.plugins.repository.AmetysRepositoryException;
035import org.ametys.plugins.repository.RepositoryConstants;
036import org.ametys.plugins.repository.UnknownAmetysObjectException;
037import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
038import org.ametys.plugins.repository.jcr.JCRTraversableAmetysObject;
039import org.ametys.plugins.repository.jcr.TraversableAmetysObjectHelper;
040import org.ametys.plugins.workflow.repository.WorkflowAwareAmetysObject;
041import org.ametys.plugins.workflow.support.WorkflowProvider;
042import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow;
043
044import com.opensymphony.workflow.WorkflowException;
045import com.opensymphony.workflow.spi.Step;
046
047/**
048 * {@link ProgramFactory} for handling {@link Program}
049 */
050public class ProgramFactory extends ProgramPartFactory
051{
052    /** {@link Program} nodetype for resources collection */
053    public static final String PROGRAM_NODETYPE = RepositoryConstants.NAMESPACE_PREFIX + ":programContent";
054
055    /** {@link Program} content type */
056    public static final String PROGRAM_CONTENT_TYPE = "org.ametys.plugins.odf.Content.program";
057
058    private CatalogsManager _catalogsManager;
059    private ExportCDMfrManager _exportCDMfrManager;
060    private WorkflowProvider _workflowProvider;
061    private ExternalizableMetadataProviderExtensionPoint _extMetadataProviderEP;
062    
063    @Override
064    public void service(ServiceManager manager) throws ServiceException
065    {
066        super.service(manager);
067        _exportCDMfrManager = (ExportCDMfrManager) manager.lookup(ExportCDMfrManager.ROLE);
068        _catalogsManager = (CatalogsManager) manager.lookup(CatalogsManager.ROLE);
069        _workflowProvider = (WorkflowProvider) manager.lookup(WorkflowProvider.ROLE);
070        _extMetadataProviderEP = (ExternalizableMetadataProviderExtensionPoint) manager.lookup(ExternalizableMetadataProviderExtensionPoint.ROLE);
071    }
072    
073    @Override
074    public AbstractProgram getAmetysObject(Node node, String parentPath) throws AmetysRepositoryException
075    {
076        return new Program(node, parentPath, this);
077    }
078    
079    /**
080     * Returns the {@link AmetysObject} at the given subPath, relative to the
081     * given {@link DefaultTraversableAmetysObject}.
082     * 
083     * @param <A> the actual type of {@link AmetysObject}.
084     * @param object the context {@link DefaultTraversableAmetysObject}.
085     * @param path the sub path. Cannot be <code>null</code>, empty or absolute.
086     * @return the {@link AmetysObject} at the given subPath, relative to the
087     *         given {@link DefaultTraversableAmetysObject}.
088     * @throws AmetysRepositoryException if an error occurs.
089     * @throws UnknownAmetysObjectException if no such object exists.
090     */
091    public <A extends AmetysObject> A getChild(JCRTraversableAmetysObject object, String path) throws AmetysRepositoryException, UnknownAmetysObjectException
092    {
093        return TraversableAmetysObjectHelper.<A> getChild(object, this, path, _resolver, getLogger());
094    }
095
096    /**
097     * Returns all children of the given {@link DefaultTraversableAmetysObject}.
098     * 
099     * @param <A> the actual type of {@link AmetysObject}s
100     * @param object a {@link DefaultTraversableAmetysObject}.
101     * @return a List containing all children object in the Ametys hierarchy.
102     * @throws AmetysRepositoryException if an error occurs.
103     */
104    public <A extends AmetysObject> AmetysObjectIterable<A> getChildren(JCRTraversableAmetysObject object) throws AmetysRepositoryException
105    {
106        return TraversableAmetysObjectHelper.getChildren(object, this, _resolver, getLogger());
107    }
108
109    /**
110     * Tests if a given object has a child with a given name.
111     * 
112     * @param object the context object.
113     * @param name the name to test.
114     * @return <code>true</code> is the given object has a child with the given
115     *         name, <code>false</code> otherwise.
116     * @throws AmetysRepositoryException if an error occurs.
117     */
118    public boolean hasChild(JCRTraversableAmetysObject object, String name) throws AmetysRepositoryException
119    {
120        return TraversableAmetysObjectHelper.hasChild(object, name, _ametysFactoryExtensionPoint, getLogger());
121    }
122
123    /**
124     * Creates a child to the given object.
125     * 
126     * @param <A> the actual type of {@link AmetysObject}.
127     * @param object the parent {@link AmetysObject}.
128     * @param name the new object's name.
129     * @param type the new object's type.
130     * @return the newly created {@link AmetysObject}.
131     * @throws AmetysRepositoryException if an error occurs.
132     */
133    public <A extends AmetysObject> A createChild(JCRTraversableAmetysObject object, String name, String type) throws AmetysRepositoryException
134    {
135        return TraversableAmetysObjectHelper.<A> createChild(object, this, name, type, _ametysFactoryExtensionPoint, _resolver, getLogger());
136    }
137    
138    AmetysObjectResolver _getResolver()
139    {
140        return _resolver;
141    }
142    
143    ExportCDMfrManager _getExportCDMfrManager()
144    {
145        return _exportCDMfrManager;
146    }
147    
148    CatalogsManager _getCatalogEnumerationHelper()
149    {
150        return _catalogsManager;
151    }
152    
153    WorkflowProvider _getWorkflowProvider()
154    {
155        return _workflowProvider;
156    }
157    
158    Set<String> _getSynchronizedMetadata(AbstractProgram abstractProgram)
159    {
160        return _extMetadataProviderEP.getExternalAndLocalMetadata(abstractProgram);
161    }
162    
163    void recreateContentWorkflow(Node contentNode)
164    {
165        try
166        {
167            String workflowName = null;
168            if (contentNode.isNodeType(ProgramFactory.PROGRAM_NODETYPE)
169                || contentNode.isNodeType(SubProgramFactory.SUBPROGRAM_NODETYPE)
170                || contentNode.isNodeType(ContainerFactory.CONTAINER_NODETYPE))
171            {
172                workflowName = "content";
173            }
174            else if (contentNode.isNodeType(CourseFactory.COURSE_NODETYPE))
175            {
176                workflowName = "course";
177            }
178            
179            if (workflowName != null)
180            {
181                _createContentWorkflow(contentNode, workflowName);
182            }
183        }
184        catch (WorkflowException e)
185        {
186            getLogger().error("Impossible to recreate a workflow instance for content " + contentNode, e);
187        }
188        catch (RepositoryException e)
189        {
190            getLogger().error("Impossible to recreate a workflow instance for content " + contentNode, e);
191        }
192    }
193    
194    private void _createContentWorkflow(Node contentNode, String workflowName) throws WorkflowException, RepositoryException
195    {
196        WorkflowAwareAmetysObject waAmetysObject = _resolver.resolve(contentNode, false);
197        AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waAmetysObject);
198        
199        // initialize workflow
200        long workflowId = workflow.initialize(workflowName, 0, Collections.emptyMap());
201        
202        // set workflow id + current step on the content
203        waAmetysObject.setWorkflowId(workflowId);
204        
205        Step currentStep = (Step) workflow.getCurrentSteps(workflowId).iterator().next();
206        waAmetysObject.setCurrentStepId(currentStep.getStepId());
207    }
208}