001/*
002 *  Copyright 2017 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.plugins.bpm.jcr;
017
018import java.util.ArrayList;
019import java.util.List;
020
021import javax.jcr.Node;
022import javax.jcr.NodeIterator;
023import javax.jcr.PathNotFoundException;
024import javax.jcr.RepositoryException;
025
026import org.ametys.core.group.GroupIdentity;
027import org.ametys.core.user.UserIdentity;
028import org.ametys.plugins.bpm.Workflow;
029import org.ametys.plugins.explorer.resources.ResourceCollection;
030import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollectionFactory;
031import org.ametys.plugins.repository.AmetysObject;
032import org.ametys.plugins.repository.AmetysRepositoryException;
033import org.ametys.plugins.repository.RepositoryConstants;
034import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
035
036/**
037 * Class representing of workflow, backed by a JCR node.<br>
038 */
039public class JCRWorkflow extends DefaultTraversableAmetysObject<JCRWorkflowFactory> implements Workflow
040{
041    private static final String PROPERTY_DESCRIPTION = RepositoryConstants.NAMESPACE_PREFIX + ":description";
042    private static final String PROPERTY_TITLE = RepositoryConstants.NAMESPACE_PREFIX + ":title";
043    private static final String NODE_NAME_OWNER = RepositoryConstants.NAMESPACE_PREFIX + ":owner";
044    private static final String PROPERTY_WORKFLOW_DEFINITION = RepositoryConstants.NAMESPACE_PREFIX + ":workflowDef";
045
046    private static final String NODE_NAME_ALLOWED_USERS = RepositoryConstants.NAMESPACE_PREFIX + ":allowedUsers";
047    private static final String NODE_NAME_ALLOWED_USER = RepositoryConstants.NAMESPACE_PREFIX + ":allowedUser";
048    private static final String NODE_NAME_ALLOWED_GROUPS = RepositoryConstants.NAMESPACE_PREFIX + ":allowedGroups";
049    private static final String NODE_NAME_ALLOWED_GROUP = RepositoryConstants.NAMESPACE_PREFIX + ":allowedGroup";
050    private static final String NODE_NAME_WORKFLOW_VARIABLES = RepositoryConstants.NAMESPACE_PREFIX + ":workflowVariables";
051    private static final String NODE_NAME_ATTACHMENTS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":attachments";
052    /**
053     * Creates an {@link JCRWorkflow}.
054     * @param node the node backing this {@link AmetysObject}
055     * @param parentPath the parentPath in the Ametys hierarchy
056     * @param factory the JCRWorkflowFactory which created the AmetysObject
057     */
058    public JCRWorkflow(Node node, String parentPath, JCRWorkflowFactory factory)
059    {
060        super(node, parentPath, factory);
061    }
062
063    @Override
064    public String getTitle() throws AmetysRepositoryException
065    {
066        try
067        {
068            return getNode().getProperty(PROPERTY_TITLE).getString();
069        }
070        catch (PathNotFoundException e)
071        {
072            return null;
073        }
074        catch (RepositoryException e)
075        {
076            throw new AmetysRepositoryException("Error getting the title property.", e);
077        }
078    }
079
080    public void setTitle(String title)
081    {
082        try
083        {
084            getNode().setProperty(PROPERTY_TITLE, title);
085        }
086        catch (RepositoryException e)
087        {
088            throw new AmetysRepositoryException("Error setting the title property.", e);
089        }
090        
091    }
092
093    @Override
094    public String getWorkflowDefinition() throws AmetysRepositoryException
095    {
096        try
097        {
098            return getNode().getProperty(PROPERTY_WORKFLOW_DEFINITION).getString();
099        }
100        catch (PathNotFoundException e)
101        {
102            return null;
103        }
104        catch (RepositoryException e)
105        {
106            throw new AmetysRepositoryException("Error getting the workflowDefinition property.", e);
107        }
108    }
109
110    public void setWorkflowDefinition(String workflowDefId)
111    {
112        try
113        {
114            getNode().setProperty(PROPERTY_WORKFLOW_DEFINITION, workflowDefId);
115        }
116        catch (RepositoryException e)
117        {
118            throw new AmetysRepositoryException("Error setting the workflowDefinition property.", e);
119        }
120        
121    }
122
123    @Override
124    public String getDescription() throws AmetysRepositoryException
125    {
126        try
127        {
128            return getNode().getProperty(PROPERTY_DESCRIPTION).getString();
129        }
130        catch (PathNotFoundException e)
131        {
132            return null;
133        }
134        catch (RepositoryException e)
135        {
136            throw new AmetysRepositoryException("Error getting the description property.", e);
137        }
138    }
139
140    public void setDescription(String description)
141    {
142        try
143        {
144            getNode().setProperty(PROPERTY_DESCRIPTION, description);
145        }
146        catch (RepositoryException e)
147        {
148            throw new AmetysRepositoryException("Error setting the description property.", e);
149        }
150        
151    }
152
153    @Override
154    public Object getVariable(String variableName) throws AmetysRepositoryException
155    {
156        try
157        {
158            return getNode().getNode(NODE_NAME_WORKFLOW_VARIABLES).getProperty(variableName).getString();
159        }
160        catch (RepositoryException e)
161        {
162            return null;
163        }
164    }
165
166    public void setVariable(String variableName, Object value)
167    {
168        try
169        {
170            Node currentNode = getNode();
171            if (!currentNode.hasNode(NODE_NAME_WORKFLOW_VARIABLES))
172            {
173                currentNode.addNode(NODE_NAME_WORKFLOW_VARIABLES, "ametys:compositeMetadata");
174            }
175            currentNode.getNode(NODE_NAME_WORKFLOW_VARIABLES).setProperty(variableName, value != null ? value.toString() : null);
176        }
177        catch (RepositoryException e)
178        {
179            throw new AmetysRepositoryException("Error setting the variable '" + variableName + "' property.", e);
180        }
181        
182    }
183
184    @Override
185    public UserIdentity getOwner() throws AmetysRepositoryException
186    {
187        try
188        {
189            Node owner = getNode().getNode(NODE_NAME_OWNER);
190            String login = owner.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login").getString();
191            String populationId = owner.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population").getString();
192            return new UserIdentity(login, populationId);
193        }
194        catch (PathNotFoundException e)
195        {
196            return null;
197        }
198        catch (RepositoryException e)
199        {
200            throw new AmetysRepositoryException("Error getting the Owner property.", e);
201        }
202    }
203
204    public void setOwner(UserIdentity owner)
205    {
206        try
207        {
208            Node currentNode = getNode();
209            if (currentNode.hasNode(NODE_NAME_OWNER))
210            {
211                currentNode.getNode(NODE_NAME_OWNER).remove();
212            }
213            if (owner != null)
214            {
215                Node userNode = currentNode.addNode(NODE_NAME_OWNER, "ametys:user");
216                userNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login", owner.getLogin());
217                userNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population", owner.getPopulationId());
218            }
219        }
220        catch (RepositoryException e)
221        {
222            throw new AmetysRepositoryException("Error setting the owner property.", e);
223        }
224        
225    }
226
227    @Override
228    public UserIdentity[] getAllowedUsers() throws AmetysRepositoryException
229    {
230        try
231        {
232            List<UserIdentity> grantedUsers = new ArrayList<>();
233
234            if (getNode().hasNode(NODE_NAME_ALLOWED_USERS))
235            {
236                NodeIterator nodeIt = getNode().getNode(NODE_NAME_ALLOWED_USERS).getNodes(NODE_NAME_ALLOWED_USER);
237                while (nodeIt.hasNext())
238                {
239                    Node allowedUser = (Node) nodeIt.next();
240                    String login = allowedUser.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login").getString();
241                    String populationId = allowedUser.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population").getString();
242    
243                    grantedUsers.add(new UserIdentity(login, populationId));
244                }
245            }
246            return grantedUsers.toArray(new UserIdentity[grantedUsers.size()]);
247        }
248        catch (RepositoryException e)
249        {
250            throw new AmetysRepositoryException("An error occurred while trying to get allowed users.", e);
251        }
252    }
253
254    public void setAllowedUsers(UserIdentity[] allowedUsers)
255    {
256        try
257        {
258            if (getNode().hasNode(NODE_NAME_ALLOWED_USERS))
259            {
260                getNode().getNode(NODE_NAME_ALLOWED_USERS).remove();
261            }
262
263            Node rootNode = getNode().addNode(NODE_NAME_ALLOWED_USERS);
264            for (UserIdentity grantedUser : allowedUsers)
265            {
266                Node userNode = rootNode.addNode(NODE_NAME_ALLOWED_USER, "ametys:user");
267                userNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":login", grantedUser.getLogin());
268                userNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":population", grantedUser.getPopulationId());
269            }
270        }
271        catch (RepositoryException e)
272        {
273            throw new AmetysRepositoryException("An error occurred while setting the allowed users.", e);
274        }
275    }
276
277    @Override
278    public GroupIdentity[] getAllowedGroups() throws AmetysRepositoryException
279    {
280        try
281        {
282            List<GroupIdentity> grantedGroups = new ArrayList<>();
283
284            Node currentNode = getNode();
285            if (currentNode.hasNode(NODE_NAME_ALLOWED_GROUPS))
286            {
287                NodeIterator nodeIt = currentNode.getNode(NODE_NAME_ALLOWED_GROUPS).getNodes(NODE_NAME_ALLOWED_GROUP);
288                while (nodeIt.hasNext())
289                {
290                    Node grantedGroup = (Node) nodeIt.next();
291                    String groupId = grantedGroup.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupId").getString();
292                    String groupDir = grantedGroup.getProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupDirectory").getString();
293    
294                    grantedGroups.add(new GroupIdentity(groupId, groupDir));
295                }
296            }
297            return grantedGroups.toArray(new GroupIdentity[grantedGroups.size()]);
298        }
299        catch (RepositoryException e)
300        {
301            throw new AmetysRepositoryException("An error occurred while trying to get allowed groups.", e);
302        }
303    }
304
305    public void setAllowedGroups(GroupIdentity[] allowedGroups)
306    {
307        try
308        {
309            Node currentNode = getNode();
310            if (currentNode.hasNode(NODE_NAME_ALLOWED_GROUPS))
311            {
312                currentNode.getNode(NODE_NAME_ALLOWED_GROUPS).remove();
313            }
314
315            Node rootNode = currentNode.addNode(NODE_NAME_ALLOWED_GROUPS);
316            for (GroupIdentity allowedGroup : allowedGroups)
317            {
318                Node groupNode = rootNode.addNode(NODE_NAME_ALLOWED_GROUP, "ametys:group");
319                groupNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupId", allowedGroup.getId());
320                groupNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ":groupDirectory", allowedGroup.getDirectoryId());
321            }
322        }
323        catch (RepositoryException e)
324        {
325            throw new AmetysRepositoryException("An error occurred while setting the allowed groups.", e);
326        }
327    }
328    
329    @Override
330    public ResourceCollection getRootAttachments() throws AmetysRepositoryException
331    {
332        ResourceCollection attachments;
333        if (hasChild(NODE_NAME_ATTACHMENTS))
334        {
335            attachments = getChild(NODE_NAME_ATTACHMENTS);
336        }
337        else
338        {
339            attachments = createChild(NODE_NAME_ATTACHMENTS, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE);
340            
341            try
342            {
343                getNode().getSession().save();
344            }
345            catch (RepositoryException e)
346            {
347                throw new AmetysRepositoryException("Unable to save session", e);
348            }
349        }
350        
351        return attachments;
352    }
353    
354}