001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2006 Danet GmbH (www.danet.de), BU BTS.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: ServiceRegistryResponseGenerator.java,v 1.10 2007/03/29 11:46:54 schnelle Exp $
021: *
022: * $Log: ServiceRegistryResponseGenerator.java,v $
023: * Revision 1.10 2007/03/29 11:46:54 schnelle
024: * Reactivated ASAPException to propagate ASAP error messages in cases of an invalid key, a missing resource or an invalid factory.
025: *
026: * Revision 1.9 2007/03/01 12:32:58 schnelle
027: * Enhanced Instance.SetProperties to process ContextData.
028: *
029: * Revision 1.8 2007/02/28 13:19:36 drmlipp
030: * Fixed charset problem.
031: *
032: * Revision 1.7 2007/02/16 21:00:21 mlipp
033: * Fixed some null pointer problems.
034: *
035: * Revision 1.6 2007/02/06 08:35:34 schnelle
036: * Started automatic generation of wsdl description.
037: *
038: * Revision 1.5 2007/02/01 13:44:44 schnelle
039: * Using namespace for factory schemas that do not contain '&'.
040: *
041: * Revision 1.4 2007/01/31 22:55:36 mlipp
042: * Some more refactoring and fixes of problems introduced by refactoring.
043: *
044: * Revision 1.3 2007/01/31 12:24:06 drmlipp
045: * Design revisited.
046: *
047: * Revision 1.2 2007/01/30 11:56:14 drmlipp
048: * Merged Wf-XML branch.
049: *
050: * Revision 1.1.2.21 2007/01/29 15:04:21 schnelle
051: * Renaming of Observer to ObserverRegistry and URIDecoder to ResourceReference.
052: *
053: * Revision 1.1.2.20 2007/01/29 13:40:32 schnelle
054: * Storing of the sender base in the servlet context.
055: *
056: * Revision 1.1.2.19 2007/01/19 12:34:56 schnelle
057: * Moved generation and decoding of the URI that is used as the receiver key to new class URIDecoder.
058: *
059: * Revision 1.1.2.18 2007/01/16 11:05:42 schnelle
060: * Refactoring: Moved subscription handling methods to own class.
061: *
062: * Revision 1.1.2.17 2007/01/10 09:03:43 schnelle
063: * Implemented set properties methods.
064: *
065: * Revision 1.1.2.16 2006/12/20 13:32:25 schnelle
066: * Basic implementato of GetProperties for Instance and Activity.
067: *
068: * Revision 1.1.2.15 2006/12/19 14:43:29 schnelle
069: * Implementation of GetProperties for ServiceRegistry and Factory.
070: *
071: * Revision 1.1.2.14 2006/12/18 14:41:03 schnelle
072: * Preparatation for individual schema definition for each getproperties request.
073: *
074: * Revision 1.1.2.13 2006/12/18 11:56:51 schnelle
075: * Returning the XPDL node after a NewDefiniton to the ServiceRegistry.
076: *
077: * Revision 1.1.2.12 2006/12/14 08:50:21 schnelle
078: * Implemented CompleteActivity.
079: *
080: * Revision 1.1.2.11 2006/12/13 11:23:48 schnelle
081: * Implemented instance ListActivities.
082: *
083: * Revision 1.1.2.10 2006/12/12 13:24:38 schnelle
084: * Introduction of ASAPException to provide a detailed mesage.
085: *
086: * Revision 1.1.2.9 2006/12/12 09:34:35 schnelle
087: * Implemented ChangeState for Instance.
088: *
089: * Revision 1.1.2.8 2006/12/11 11:05:34 schnelle
090: * Added template methods for all requests.
091: *
092: * Revision 1.1.2.7 2006/12/01 12:49:54 schnelle
093: * Basic import of context data for process creation.
094: *
095: * Revision 1.1.2.6 2006/11/30 12:45:08 schnelle
096: * Basic implementation of Factory CreateInstance.
097: *
098: * Revision 1.1.2.5 2006/11/30 10:38:08 schnelle
099: * Implementation of Factory ListInstance.
100: *
101: * Revision 1.1.2.4 2006/11/29 14:12:37 schnelle
102: * Take respect to namespaces of asap requests and responses.
103: *
104: * Revision 1.1.2.3 2006/11/29 11:05:22 schnelle
105: * Full implementation of the request and response headers.
106: *
107: * Revision 1.1.2.2 2006/11/28 15:31:51 schnelle
108: * Proper selection of the response generator.
109: *
110: * Revision 1.1.2.1 2006/11/28 12:20:09 schnelle
111: * Creation of a separate class to handle the issues for a specific resource.
112: *
113: * Revision 1.1.2.2 2006/11/27 15:41:55 schnelle
114: * Introducing some constants for request and response identification.
115: *
116: * Revision 1.1.2.1 2006/11/24 12:19:13 schnelle
117: * Separtion of response generation into ResponseGenerator class.
118: *
119: */
120: package de.danet.an.workflow.clients.wfxml;
121:
122: import java.io.UnsupportedEncodingException;
123: import java.rmi.RemoteException;
124: import java.util.Collection;
125: import java.util.Iterator;
126:
127: import javax.xml.soap.SOAPBodyElement;
128: import javax.xml.soap.SOAPElement;
129: import javax.xml.soap.SOAPException;
130: import javax.xml.soap.SOAPMessage;
131: import javax.xml.transform.TransformerException;
132:
133: import de.danet.an.workflow.api.ImportException;
134: import de.danet.an.workflow.api.InvalidKeyException;
135: import de.danet.an.workflow.api.ProcessDefinition;
136: import de.danet.an.workflow.api.ProcessDefinitionDirectory;
137: import de.danet.an.workflow.api.WorkflowService;
138:
139: /**
140: * This class provides the methods of an {@link AbstractResponseGenerator}
141: * that are relevant for the service registry.
142: *
143: * <p>
144: * A <em>Service Registry</em> is a special purpose factory (or meta-factory)
145: * that can start new factories associated with new process definitions given to
146: * them. It can provide a list of factories, in the same way that a factory can
147: * provide a list of instances. This special purpose factory is needed to allow
148: * process definition tools to add new processes to the server.
149: * </p>
150: *
151: * @author Dirk Schnelle
152: *
153: */
154: class ServiceRegistryResponseGenerator extends
155: AbstractResponseGenerator {
156: /** Logger instance. */
157: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
158: .getLog(ServiceRegistryResponseGenerator.class);
159:
160: /**
161: * Constructs a new object.
162: *
163: * @param observerRegistry the observer registry.
164: * @param wfs Reference to the workflow engine.
165: * @param decoder the URI decoder.
166: */
167: public ServiceRegistryResponseGenerator(
168: ObserverRegistry observerRegistry, WorkflowService wfs,
169: ResourceReference decoder) {
170: super (observerRegistry, wfs, decoder);
171: }
172:
173: /* (non-Javadoc)
174: * @see de.danet.an.workflow.clients.wfxml.AbstractResponseGenerator#evaluate(javax.xml.soap.SOAPMessage, javax.xml.soap.SOAPMessage)
175: */
176: public void evaluate(SOAPMessage reqMsg, SOAPMessage respMsg)
177: throws SOAPException, RemoteException {
178: SOAPBodyElement actionElement = getActionElement(reqMsg);
179:
180: String actName = actionElement.getElementName().getLocalName();
181:
182: if (actName.equals(Consts.LIST_DEFINITIONS_REQUEST)) {
183: listDefinitions(reqMsg, respMsg);
184: } else if (actName.equals(Consts.NEW_DEFINITION_REQUEST)) {
185: newDefinition(actionElement, reqMsg, respMsg);
186: } else if (actName.equals(Consts.GET_PROPERTIES_REQUEST)) {
187: getServiceProperties(reqMsg, respMsg);
188: } else if (actName.equals(Consts.GET_PROPERTIES_REQUEST)) {
189: setServiceProperties(reqMsg, respMsg);
190: } else {
191: if (logger.isDebugEnabled()) {
192: logger.debug("unknown action '" + actName + "'");
193: }
194:
195: FaultUtils.setFault(respMsg,
196: ASAPException.ASAP_INVALID_OPERATION_SPECIFICATION,
197: getResourceName() + ": Unknown action \"" + actName
198: + "\".");
199: }
200: }
201:
202: /**
203: * Creates a new definition.
204: *
205: * <p>
206: * Note that this implementation differs from the specification. An
207: * error is not thrown, if the factory exists. If the factory exists,
208: * the process definition will be overwritten without warning.
209: * </p>
210: *
211: * @param action the request element.
212: * @param reqMsg the request message.
213: * @param respMsg the response message.
214: * @throws SOAPException
215: * error evaluating the request or constructing the response.
216: * @throws RemoteException
217: * error accessing the workflow engine.
218: */
219: private void newDefinition(SOAPBodyElement action,
220: SOAPMessage reqMsg, SOAPMessage respMsg)
221: throws SOAPException, RemoteException {
222: String language = getChildsTextContent(action,
223: "ProcessLanguage");
224: if ((language != null) && !language.equalsIgnoreCase("XPDL")) {
225: FaultUtils.setFault(respMsg,
226: ASAPException.ASAP_INVALID_CONTEXT_DATA,
227: "Allowed value for process language is XPDL only!");
228:
229: return;
230: }
231:
232: SOAPElement definition = findChildNode(action, "Definition");
233: SOAPElement pkg = findChildNode(definition, "Package");
234:
235: try {
236: byte[] xpdlBytes = nodeToBytes(pkg);
237: if (logger.isDebugEnabled()) {
238: logger.debug("importing xpdl");
239: try {
240: logger.debug(new String(xpdlBytes, "UTF-8"));
241: } catch (UnsupportedEncodingException e) {
242: logger.debug(new String(xpdlBytes));
243: }
244: }
245: ProcessDefinitionDirectory pdd = getWorkflowService()
246: .processDefinitionDirectory();
247: pdd.importProcessDefinitions(xpdlBytes);
248: } catch (TransformerException e) {
249: FaultUtils.setFault(respMsg,
250: ASAPException.ASAP_INVALID_CONTEXT_DATA,
251: "unable to transform xpdl");
252:
253: return;
254: } catch (ImportException e) {
255: FaultUtils
256: .setFault(respMsg,
257: ASAPException.ASAP_OPERATION_FAILED, e
258: .getMessage());
259:
260: return;
261: }
262:
263: SOAPBodyElement defsNode = createWfxmlResponseNode(respMsg,
264: Consts.NEW_DEFINITION_RESPONSE);
265: defsNode.addNamespaceDeclaration("",
266: "http://www.wfmc.org/2002/XPDL1.0");
267: Iterator prefixes = pkg.getNamespacePrefixes();
268: while (prefixes.hasNext()) {
269: String prefix = (String) prefixes.next();
270: String uri = pkg.getNamespaceURI(prefix);
271:
272: defsNode.addNamespaceDeclaration(prefix, uri);
273: }
274:
275: importAsChild(defsNode, pkg);
276: }
277:
278: /**
279: * Sets properties.
280: * @param reqMsg the request message.
281: * @param respMsg the response message
282: * @throws SOAPException
283: * error evaluating the request or constructing the response.
284: * @throws RemoteException
285: * error accessing the workflow engine.
286: */
287: private void setServiceProperties(SOAPMessage reqMsg,
288: SOAPMessage respMsg) throws SOAPException, RemoteException {
289: if (logger.isDebugEnabled()) {
290: logger.debug("set service properties...");
291: }
292:
293: String receiverKey = getHeaderValue(reqMsg, Consts.RECEIVER_KEY);
294:
295: SOAPBodyElement propsNode = createWfxmlResponseNode(respMsg,
296: Consts.SET_PROPERTIES_RESPONSE);
297: appendServiceProperties(receiverKey, propsNode);
298: }
299:
300: /**
301: * Creates a response that contains properties of the service registry.
302: *
303: * <p>
304: * This method produces XML that fails validation, since the WFXML
305: * schema definition defines a group to return theses properties, but
306: * which is never referenced, so that it must not be a part of
307: * a <code>GetpropertiesRs</code> message.
308: * </p>
309: *
310: * @param reqMsg the request message.
311: * @param respMsg the response message
312: * @throws SOAPException
313: * error evaluating the request or constructing the response.
314: * @throws RemoteException
315: * error accessing the workflow engine.
316: */
317: private void getServiceProperties(SOAPMessage reqMsg,
318: SOAPMessage respMsg) throws SOAPException, RemoteException {
319: if (logger.isDebugEnabled()) {
320: logger.debug("get service properties...");
321: }
322:
323: String receiverKey = getHeaderValue(reqMsg, Consts.RECEIVER_KEY);
324:
325: SOAPBodyElement propsNode = createWfxmlResponseNode(respMsg,
326: Consts.GET_PROPERTIES_RESPONSE);
327: appendServiceProperties(receiverKey, propsNode);
328: }
329:
330: /**
331: * Reads the properties from the process definition and appends them to the
332: * parent.
333: * @param receiverKey this activity instance
334: * @param propsNode the parent node of the response message.
335: * @throws SOAPException
336: * error appending to the parent node
337: * @throws RemoteException
338: * error accessing the process
339: */
340: private void appendServiceProperties(String receiverKey,
341: SOAPBodyElement propsNode) throws SOAPException {
342: SOAPElement keyNode = propsNode.addChildElement("Key",
343: Consts.WFXML_PREFIX);
344: keyNode.addTextNode(getResourceReference().getResourceKey());
345: SOAPElement nameNode = propsNode.addChildElement("Name",
346: Consts.WFXML_PREFIX);
347: nameNode.addTextNode("WfMOpen ServiceRegistry");
348: SOAPElement descNode = propsNode.addChildElement("Description",
349: Consts.WFXML_PREFIX);
350: descNode.addTextNode("The WfMOpen ServiceRegistry");
351: SOAPElement version = propsNode.addChildElement("Version",
352: Consts.WFXML_PREFIX);
353: version.addTextNode("0.1");
354: SOAPElement state = propsNode.addChildElement("Status",
355: Consts.WFXML_PREFIX);
356: state.addTextNode("Enabled");
357: }
358:
359: /**
360: * Creates a response that contains the known definitions.
361: * @param reqMsg the request message.
362: * @param respMsg the response message.
363: * @throws SOAPException
364: * error evaluating the request or constructing the response.
365: * @throws RemoteException
366: * error accessing the workflow engine.
367: */
368: private void listDefinitions(SOAPMessage reqMsg, SOAPMessage respMsg)
369: throws SOAPException, RemoteException {
370: if (logger.isDebugEnabled()) {
371: logger.debug("list all process definitions...");
372: }
373:
374: SOAPBodyElement defsNode = createWfxmlResponseNode(respMsg,
375: Consts.LIST_DEFINITIONS_RESPONSE);
376:
377: ProcessDefinitionDirectory pdd = getWorkflowService()
378: .processDefinitionDirectory();
379:
380: Collection procdefs = pdd.processDefinitions();
381: for (Iterator i = procdefs.iterator(); i.hasNext();) {
382: ProcessDefinition pd = (ProcessDefinition) i.next();
383: try {
384: if (!pdd.isEnabled(pd.packageId(), pd.processId())) {
385: continue;
386: }
387: } catch (InvalidKeyException e) {
388: continue;
389: }
390: SOAPElement defInfo = defsNode.addChildElement(
391: "DefinitionInfo", Consts.WFXML_PREFIX);
392: SOAPElement defKey = defInfo.addChildElement(
393: "DefinitionKey", Consts.WFXML_PREFIX);
394: ResourceReference procDefRes = new ResourceReference(
395: getResourceReference().getBaseUrl(), pd);
396: defKey.addTextNode(procDefRes.getResourceKey());
397: SOAPElement name = defInfo.addChildElement("Name",
398: Consts.WFXML_PREFIX);
399: String val = pd.processName();
400: maybeAddTextNode(name, val);
401: SOAPElement descr = defInfo.addChildElement("Description",
402: Consts.WFXML_PREFIX);
403: val = pd.processHeader().description();
404: maybeAddTextNode(descr, val);
405: SOAPElement version = defInfo.addChildElement("Version",
406: Consts.WFXML_PREFIX);
407: val = pd.processHeader().version();
408: maybeAddTextNode(version, val);
409: SOAPElement status = defInfo.addChildElement("Status",
410: Consts.WFXML_PREFIX);
411: val = pd.processHeader().publicationStatus();
412: maybeAddTextNode(status, val);
413: }
414: }
415:
416: /* (non-Javadoc)
417: * @see de.danet.an.workflow.clients.wfxml.AbstractResponseGenerator#getSender()
418: */
419: protected String getResourceName() {
420: return RESOURCE_SERVICE_REGISTRY;
421: }
422: }
|