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