View Javadoc

1   /**
2    * This file Copyright (c) 2003-2011 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.workflow.flows;
35  
36  import info.magnolia.cms.core.Content;
37  import info.magnolia.cms.core.ItemType;
38  import info.magnolia.cms.core.HierarchyManager;
39  import info.magnolia.cms.util.ContentUtil;
40  import info.magnolia.cms.util.NodeDataUtil;
41  import info.magnolia.context.MgnlContext;
42  import info.magnolia.context.WebContextImpl;
43  import info.magnolia.module.workflow.WorkflowConstants;
44  import info.magnolia.repository.RepositoryConstants;
45  
46  import java.io.IOException;
47  import java.io.InputStream;
48  import java.io.StringReader;
49  import java.net.MalformedURLException;
50  import java.net.URL;
51  import java.net.URLConnection;
52  import java.text.MessageFormat;
53  import java.util.ArrayList;
54  import java.util.Collection;
55  import java.util.Collections;
56  import java.util.Iterator;
57  import java.util.List;
58  
59  import javax.jcr.RepositoryException;
60  import javax.servlet.http.HttpServletRequest;
61  
62  import openwfe.org.engine.workitem.LaunchItem;
63  
64  import org.apache.commons.lang.StringUtils;
65  import org.jdom.Document;
66  import org.jdom.Element;
67  import org.slf4j.Logger;
68  import org.slf4j.LoggerFactory;
69  
70  /**
71   * Read and store flows in the repositories.
72   * @author philipp
73   */
74  public class DefaultFlowDefinitionManager implements FlowDefinitionManager {
75  
76      private static Logger log = LoggerFactory.getLogger(DefaultFlowDefinitionManager.class);
77  
78      private boolean saveWorkflowDefinitionInWorkItem = true;
79  
80      private String flowDefinitionURLPattern;
81  
82      @Override
83      public void configure(LaunchItem launchItem, String workflowName) throws FlowDefinitionException {
84          if(saveWorkflowDefinitionInWorkItem){
85              launchItem.setWorkflowDefinitionUrl(WorkflowConstants.ATTRIBUTE_WORKFLOW_DEFINITION_URL);
86              String flowDef = readDefinition(workflowName);
87              launchItem.getAttributes().puts(WorkflowConstants.ATTRIBUTE_DEFINITION, flowDef);
88          }
89          else{
90              InputStream is = null;
91              String surl = getFlowDefinitionURLPattern();
92              surl = MessageFormat.format(surl, new String[]{workflowName});
93              try {
94                  URL url = new URL(surl);
95                  URLConnection connection = url.openConnection();
96                  connection.connect();
97                  is = connection.getInputStream();
98                  launchItem.setWorkflowDefinitionUrl(surl);
99              }
100             catch (MalformedURLException e) {
101                 throw new FlowDefinitionException("can't use workflow name [" + workflowName + "] because the url[" + surl + "] is not an url", e);
102             }
103             catch (IOException e) {
104                 throw new FlowDefinitionException("can't use workflow name [" + workflowName + "] because the url[" + surl + "] is not accessible", e);
105             }
106             finally {
107                 try {if(is!=null) {
108                     is.close();
109                 }} catch(Exception e) {/*just try to close any open stream*/}
110             }
111 
112         }
113     }
114 
115     @Override
116     public String readDefinition(String workflowName) throws FlowDefinitionException {
117         Content node;
118         try {
119             node = getDefinitionNode(workflowName);
120         }
121         catch (RepositoryException e) {
122             throw new FlowDefinitionException("can't read workflow definition [" + workflowName + "]", e);
123         }
124         if (node == null){
125             throw new FlowDefinitionException("can't read workflow definition [" + workflowName + "]") ;
126         }
127         return node.getNodeData("value").getString();
128     }
129 
130     /**
131      * find one flow node by flow name.
132      * @return Content node in JCR store for specified flow definition
133      */
134     public Content getDefinitionNode(String name) throws RepositoryException {
135         if (name == null) {
136             return null;
137         }
138         return ContentUtil.getContent(RepositoryConstants.CONFIG, WorkflowConstants.ROOT_PATH_FOR_FLOW + "/"+ name);
139     }
140 
141     @Override
142     public void saveDefinition(String definition) throws FlowDefinitionException {
143         saveDefinition(extractWorkflowName(definition), definition);
144     }
145 
146     protected void saveDefinition(String workflowName, String definition) throws FlowDefinitionException {
147         if (definition == null) {
148             return;
149         }
150 
151         try {
152             HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(RepositoryConstants.CONFIG);
153             Content root = hm.getContent(WorkflowConstants.ROOT_PATH_FOR_FLOW);
154 
155             // check if the node already exist, and if it does update the value of the the NodeData FLOW_VALUE with the
156             // new flow. This is to allow duplication of flow node.
157 
158             final Content wfNode = ContentUtil.getOrCreateContent(root, workflowName, ItemType.CONTENTNODE);
159             NodeDataUtil.getOrCreateAndSet(wfNode, WorkflowConstants.FLOW_VALUE, definition);
160 
161             root.save();
162             log.info("New flow added: " + workflowName);
163         }
164         catch (Exception e) {
165             throw new FlowDefinitionException("can't add flow", e);
166         }
167     }
168 
169     protected String extractWorkflowName(String definition) throws FlowDefinitionException {
170         try {
171             // jdom
172             final org.jdom.input.SAXBuilder builder = new org.jdom.input.SAXBuilder();
173             Document doc = builder.build(new StringReader(definition));
174             Element process_definition = doc.getRootElement();
175             return process_definition.getAttribute("name").getValue();
176         }
177         catch(Exception e){
178             throw new FlowDefinitionException("can't extract name out of the definition", e);
179         }
180     }
181 
182     @Override
183     public List getDefinitionNames(){
184         ArrayList list = new ArrayList();
185 
186         HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(RepositoryConstants.CONFIG);
187         Content root;
188         try {
189             root = hm.getContent(WorkflowConstants.ROOT_PATH_FOR_FLOW);
190         }
191         catch (RepositoryException e) {
192             log.error("can't read flow definitions", e);
193             return Collections.EMPTY_LIST;
194         }
195         // get the leaves
196         Collection c =  ContentUtil.getAllChildren(root);
197 
198         Iterator it = c.iterator();
199         while (it.hasNext()) {
200             String name = ((Content) (it.next())).getName();
201             if (name != null) {
202                 list.add(name);
203             }
204         }
205 
206         return list;
207     }
208 
209     public String getFlowDefinitionURLPattern() {
210         if (StringUtils.isEmpty(flowDefinitionURLPattern) || flowDefinitionURLPattern.equals("auto")) {
211             WebContextImpl impl = (WebContextImpl) MgnlContext.getInstance();
212             HttpServletRequest request = impl.getRequest();
213 
214             StringBuffer baseurl = new StringBuffer();
215             baseurl.append("http");
216             if(request.isSecure()){
217                 baseurl.append("s");
218             }
219             baseurl.append("://");
220             baseurl.append(request.getServerName());
221             baseurl.append(":");
222             baseurl.append(request.getServerPort());
223             baseurl.append(impl.getContextPath());
224             baseurl.append("/.magnolia/pages/flows.html");
225             baseurl.append("?command=showFlow&flowName=");
226             baseurl.append("{0}");
227             flowDefinitionURLPattern = baseurl.toString();
228         }
229 
230         return this.flowDefinitionURLPattern;
231     }
232 
233 
234     public void setFlowDefinitionURLPattern(String flowDefinitionURLPattern) {
235         this.flowDefinitionURLPattern = flowDefinitionURLPattern;
236     }
237 
238 }