1 package nl.hippo.cms.workflow; 2 3 import com.opensymphony.workflow.loader.ActionDescriptor; 4 import java.io.ByteArrayInputStream ; 5 import java.io.ByteArrayOutputStream ; 6 import java.io.IOException ; 7 import java.io.InputStream ; 8 import java.util.Collections ; 9 import java.util.HashMap ; 10 import java.util.Iterator ; 11 import java.util.List ; 12 import java.util.Map ; 13 import java.util.Vector ; 14 import javax.xml.parsers.FactoryConfigurationError ; 15 import javax.xml.parsers.ParserConfigurationException ; 16 import javax.xml.parsers.SAXParser ; 17 import javax.xml.parsers.SAXParserFactory ; 18 import javax.xml.transform.Transformer ; 19 import javax.xml.transform.TransformerException ; 20 import javax.xml.transform.TransformerFactory ; 21 import javax.xml.transform.dom.DOMSource ; 22 import javax.xml.transform.stream.StreamResult ; 23 import nl.hippo.cms.workflows.shared.InitialDataRetriever; 24 import nl.hippo.cms.workflows.shared.InitialDataRetrieverWithContext; 25 import nl.hippo.componentcontainers.AvalonSpringBridge; 26 import nl.hippo.servermanager.ComponentLoadException; 27 import nl.hippo.servermanager.Project; 28 import nl.hippo.servermanager.ProjectWorkflowRepository; 29 import nl.hippo.servermanager.ResourceLoadException; 30 import nl.hippo.servermanager.Server; 31 import nl.hippo.servermanager.ServerManager; 32 import org.apache.avalon.framework.activity.Disposable; 33 import org.apache.avalon.framework.component.Component; 34 import org.apache.avalon.framework.parameters.ParameterException; 35 import org.apache.avalon.framework.service.ServiceException; 36 import org.apache.avalon.framework.service.ServiceManager; 37 import org.apache.avalon.framework.service.Serviceable; 38 import org.apache.avalon.framework.service.WrapperServiceSelector; 39 import org.apache.cocoon.ProcessingException; 40 import org.apache.cocoon.environment.Request; 41 import org.apache.cocoon.generation.AbstractGenerator; 42 import org.apache.commons.httpclient.HttpState; 43 import org.apache.webdav.lib.Property; 44 import org.apache.webdav.lib.PropertyName; 45 import org.w3c.dom.Document ; 46 import org.w3c.dom.Element ; 47 import org.xml.sax.InputSource ; 48 import org.xml.sax.SAXException ; 49 import org.xml.sax.helpers.AttributesImpl ; 50 51 public class AvailableActionsGenerator extends AbstractGenerator implements Serviceable, Disposable 52 { 53 54 private static final Vector PROPERTIES_NEEDED_BY_WORKFLOW = new Vector (); 55 56 private static final PropertyName WORKFLOW_ID_PROPERTY_NAME = new PropertyName( 57 "http://hippo.nl/cms/1.0", "workflowId"); 58 59 private static final PropertyName CUPS_PROPERTY_NAME = new PropertyName("DAV:", 60 "current-user-privilege-set"); 61 62 static 63 { 64 PROPERTIES_NEEDED_BY_WORKFLOW.add(WORKFLOW_ID_PROPERTY_NAME); 65 PROPERTIES_NEEDED_BY_WORKFLOW.add(CUPS_PROPERTY_NAME); 66 } 67 68 private ServiceManager m_manager; 69 70 private AvalonSpringBridge m_avalonSpringBridge; 71 72 public AvailableActionsGenerator() 73 { 74 super(); 75 } 76 77 public void service(ServiceManager manager) throws ServiceException 78 { 79 m_manager = manager; 80 m_avalonSpringBridge = (AvalonSpringBridge) manager.lookup(AvalonSpringBridge.ROLE); 81 } 82 83 public void generate() throws IOException , SAXException , ProcessingException 84 { 85 try 86 { 87 String repositoryRoot = parameters.getParameter("repositoryRoot"); 88 String location = repositoryRoot + "/" + source; 89 90 Request request = (Request) objectModel.get("request"); 91 HttpState httpState = (HttpState) request.getSession().getAttribute("httpstate"); 92 93 ServerManager serverManager = (ServerManager) m_avalonSpringBridge.getBean("serverManager"); 94 Server server = serverManager.getServer(); 95 Project project = server.getProjectByDomain(request.getServerName()); 96 if (project == null) 97 { 98 throw new IllegalStateException ("Cannot determine project. Please check your domain names."); 99 } 100 101 HashMap propertiesCache = new HashMap (); 102 WorkflowHelper.movePropertiesToCache(location, PROPERTIES_NEEDED_BY_WORKFLOW.elements(), propertiesCache, httpState); 103 104 Property workflowIdAsProperty = (Property) propertiesCache 105 .get(WORKFLOW_ID_PROPERTY_NAME); 106 String workflowIdAsString; 107 if (workflowIdAsProperty == null) 108 { 109 workflowIdAsString = null; 110 } 111 else 112 { 113 workflowIdAsString = workflowIdAsProperty.getPropertyAsString(); 114 } 115 116 Map parameters = propertiesCache; 117 parameters.put("location", location); 118 parameters.put("httpstate", httpState); 119 parameters.put("propertiesCache", propertiesCache); 120 ActionDescriptor[] actions = null; 121 ProjectWorkflowRepository workflow = null; 122 if (workflowIdAsString != null && !workflowIdAsString.equals("")) 123 { 124 workflow = project.getWorkflowRepository(); 125 actions = WorkflowHelper.getAvailableActions(workflow, workflowIdAsString, parameters); 126 } 127 if (actions == null) 128 { 129 actions = new ActionDescriptor[0]; 130 } 131 132 List authorisedActions = null; 133 if (workflowIdAsString != null && !workflowIdAsString.equals("")) 134 { 135 long workflowId = Long.parseLong(workflowIdAsString); 136 137 WorkflowActionAuthorizer authorizer = WorkflowHelper.getActionsAuthorizer(workflow, workflowId); 138 WorkflowActionAuthorizerContext authorizerContext = new WorkflowActionAuthorizerContext(project, httpState); 139 authorisedActions = authorizer.authorizeActions(workflowId, actions, authorizerContext); 140 } 141 else 142 { 143 authorisedActions = Collections.EMPTY_LIST; 144 } 145 146 contentHandler.startDocument(); 147 contentHandler.startElement(null, "workflow-actions", "workflow-actions", null); 148 149 if (actions.length > 0 && authorisedActions.isEmpty()) 150 { 151 contentHandler.startElement(null, "insufficient-privileges", "insufficient-privileges", 153 null); 154 155 contentHandler.endElement(null, "insufficient-privileges", "insufficient-privileges"); 156 } 157 for (Iterator authorisedActionsIterator = authorisedActions.iterator(); authorisedActionsIterator 158 .hasNext();) 159 { 160 long workflowId = Long.parseLong(workflowIdAsString); 161 162 ActionDescriptor actionDescriptor = (ActionDescriptor) authorisedActionsIterator 163 .next(); 164 if (actionDescriptor.getMetaAttributes().get("invisibleToUsers") == null) 165 { 166 AttributesImpl workflowActionAttributes = new AttributesImpl (); 167 workflowActionAttributes.addAttribute(null, "name", "name", "CDATA", 168 actionDescriptor.getName()); 169 workflowActionAttributes.addAttribute(null, "workflow-id", "workflow-id", 170 "CDATA", String.valueOf(actionDescriptor.getId())); 171 contentHandler.startElement(null, "workflow-action", "workflow-action", 172 workflowActionAttributes); 173 174 String label = (String ) actionDescriptor.getMetaAttributes().get("label"); 175 optionallyOutputTextElement("label", label); 176 177 String standardUIAction = (String ) actionDescriptor.getMetaAttributes().get( 178 "standardUIAction"); 179 optionallyOutputTextElement("standard-ui-action", standardUIAction); 180 181 String inputSchemaResourceLocation = (String ) actionDescriptor.getMetaAttributes().get( 182 "inputSchema"); 183 if (inputSchemaResourceLocation != null && !inputSchemaResourceLocation.equals("")) 184 { 185 includeResource(workflow, workflowId, inputSchemaResourceLocation); 186 } 187 else 188 { 189 String inputSchemaGeneratorClassName = (String ) actionDescriptor.getMetaAttributes().get("inputSchemaGeneratorClass"); 190 if (inputSchemaGeneratorClassName != null && ! inputSchemaGeneratorClassName.equals("")) 191 { 192 includeGeneratedResource(location, project, workflowId, inputSchemaGeneratorClassName); 193 } 194 } 195 196 String inputFormResourceLocation = (String ) actionDescriptor.getMetaAttributes().get( 197 "inputForm"); 198 if (inputFormResourceLocation != null && !inputFormResourceLocation.equals("")) 199 { 200 includeResource(workflow, workflowId, inputFormResourceLocation); 201 } 202 else 203 { 204 String inputFormGeneratorClassName = (String ) actionDescriptor.getMetaAttributes().get("inputFormGeneratorClass"); 205 if (inputFormGeneratorClassName != null && !inputFormGeneratorClassName.equals("")) 206 { 207 includeGeneratedResource(location, project, workflowId, inputFormGeneratorClassName); 208 } 209 } 210 211 contentHandler.startElement(null, "data", "data", null); 212 213 String initialDataRetrieverClass = (String ) actionDescriptor 214 .getMetaAttributes().get("initialDataRetrieverClass"); 215 if (initialDataRetrieverClass != null) 216 { 217 Object initialDataRetrieverAsObject = null; 218 try 219 { 220 initialDataRetrieverAsObject = workflow.loadComponent(workflowId, initialDataRetrieverClass); 221 Map data; 222 if (initialDataRetrieverAsObject instanceof InitialDataRetrieverWithContext) 223 { 224 InitialDataRetrieverWithContext dataRetrieverWithContext = (InitialDataRetrieverWithContext) initialDataRetrieverAsObject; 225 Map context = new HashMap (); 226 context.put("project", project); 227 data = dataRetrieverWithContext.getData(location, httpState, context); 228 } 229 else 230 { 231 InitialDataRetriever dataRetriever = (InitialDataRetriever) initialDataRetrieverAsObject; 232 data = dataRetriever.getData(location, httpState); 233 } 234 for (Iterator keysIterator = data.keySet().iterator(); keysIterator 235 .hasNext();) 236 { 237 String key = (String ) keysIterator.next(); 238 Object value = data.get(key); 239 if (value == null) 240 { 241 value = ""; 242 } 243 else if (value instanceof Document ) 244 { 245 value = ((Document )value).getDocumentElement(); 246 } 247 248 AttributesImpl valueAttributes = new AttributesImpl (); 249 valueAttributes.addAttribute(null, "name", "name", "CDATA", key); 250 contentHandler.startElement(null, "value", "value", valueAttributes); 251 if (value instanceof Element ) 252 { 253 includeElement((Element ) value); 254 } 255 else 256 { 257 char[] valueAsCharArray = value.toString().toCharArray(); 258 contentHandler.characters(valueAsCharArray, 0, valueAsCharArray.length); 259 } 260 contentHandler.endElement(null, "value", "value"); 261 } 262 } 263 finally 264 { 265 releaseWorkflowExtension(initialDataRetrieverAsObject); 266 } 267 } 268 269 contentHandler.endElement(null, "data", "data"); 270 271 contentHandler.endElement(null, "workflow-action", "workflow-action"); 272 } 273 } 274 275 contentHandler.endElement(null, "workflow-actions", "workflow-actions"); 276 contentHandler.endDocument(); 277 } 278 catch (ParameterException e) 279 { 280 throw new ProcessingException("Unable to retrieve repository root", e); 281 } 282 catch (ParserConfigurationException e) 283 { 284 throw new ProcessingException("Unable to create SAX parser", e); 285 } 286 catch (InstantiationException e) 287 { 288 throw new ProcessingException("Unable to lookup/instantiate workflow extension", e); 289 } 290 catch (IllegalAccessException e) 291 { 292 throw new ProcessingException("Unable to lookup/instantiate workflow extension", e); 293 } 294 catch (ClassNotFoundException e) 295 { 296 throw new ProcessingException("Unable to lookup/instantiate workflow extension", e); 297 } 298 catch (ServiceException e) 299 { 300 throw new ProcessingException("Unable to lookup needed component", e); 301 } 302 catch (Exception e) 303 { 304 throw new ProcessingException("Unknown error", e); 305 } 306 } 307 308 public void dispose() 309 { 310 m_manager.release(m_avalonSpringBridge); 311 m_manager = null; 312 } 313 314 private void releaseWorkflowExtension(Object workflowExtension) 315 { 316 if (workflowExtension instanceof WrapperServiceSelector || workflowExtension instanceof Component) 317 { 318 m_manager.release(workflowExtension); 319 } 320 } 321 322 private void includeResource(ProjectWorkflowRepository workflow, long workflowId, String resourceLocation) 323 throws FactoryConfigurationError , 324 IOException , ProcessingException, ParserConfigurationException , SAXException , ResourceLoadException 325 { 326 SAXParserFactory spf = SAXParserFactory.newInstance(); 327 spf.setNamespaceAware(true); 328 spf.setValidating(false); 329 SAXParser sp = spf.newSAXParser(); 330 DelegatingContentHandler handler = new DelegatingContentHandler(contentHandler, true); 331 InputStream resourceInputStream = workflow.getResourceAsStream(workflowId, resourceLocation); 332 sp.parse(new InputSource (resourceInputStream), handler); 333 } 334 335 private void includeGeneratedResource(String uri, Project project, long workflowId, String generatorClassName) throws ComponentLoadException, SAXException 336 { 337 Object generatorAsObject = project.getWorkflowRepository().loadComponent(workflowId, generatorClassName); 338 if (generatorAsObject instanceof ResourceGenerator) 339 { 340 ResourceGenerator generator = (ResourceGenerator) generatorAsObject; 341 DelegatingContentHandler handler = new DelegatingContentHandler(contentHandler, true); 342 generator.generate(uri, project, handler); 343 } 344 } 345 346 private void includeElement(Element element) throws IOException , TransformerException , ParserConfigurationException , SAXException 347 { 348 TransformerFactory tf = TransformerFactory.newInstance(); 349 Transformer t = tf.newTransformer(); 350 ByteArrayOutputStream o = new ByteArrayOutputStream (); 351 t.transform(new DOMSource (element), new StreamResult (o)); 352 o.close(); 353 SAXParserFactory spf = SAXParserFactory.newInstance(); 354 spf.setNamespaceAware(true); 355 spf.setValidating(false); 356 SAXParser sp = spf.newSAXParser(); 357 DelegatingContentHandler handler = new DelegatingContentHandler(contentHandler, true); 358 sp.parse(new InputSource (new ByteArrayInputStream (o.toByteArray())), handler); 359 } 360 361 private void optionallyOutputTextElement(String elementName, String text) throws SAXException 362 { 363 if (text != null) 364 { 365 contentHandler.startElement(null, elementName, elementName, null); 366 char[] textAsCharacterArray = text.toCharArray(); 367 contentHandler.characters(textAsCharacterArray, 0, textAsCharacterArray.length); 368 contentHandler.endElement(null, elementName, elementName); 369 } 370 } 371 372 } | Popular Tags |