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