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