001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
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: Servlet.java,v 1.4 2007/03/27 21:59:44 mlipp Exp $
021: *
022: * $Log: Servlet.java,v $
023: * Revision 1.4 2007/03/27 21:59:44 mlipp
024: * Fixed lots of checkstyle warnings.
025: *
026: * Revision 1.3 2007/01/19 22:52:58 mlipp
027: * Updated.
028: *
029: * Revision 1.2 2006/09/29 12:32:09 drmlipp
030: * Consistently using WfMOpen as projct name now.
031: *
032: * Revision 1.1.1.2 2004/08/18 15:17:38 drmlipp
033: * Update to 1.2
034: *
035: * Revision 1.19 2004/04/13 15:24:04 lipp
036: * Improved content-type and debugging support.
037: *
038: * Revision 1.18 2004/04/02 12:41:07 lipp
039: * Added missing xml decalaration.
040: *
041: * Revision 1.17 2004/03/18 10:15:26 schlue
042: * Session invalidation for closed process added.
043: *
044: * Revision 1.16 2004/03/04 08:25:23 schlue
045: * Stylesheet example added (transformation performed by web browser)
046: *
047: * Revision 1.15 2004/03/01 14:58:22 schlue
048: * Chabacc servlet extensions, part 2 completed.
049: *
050: * Revision 1.14 2004/02/27 10:20:17 schlue
051: * Review comments implemented.
052: *
053: * Revision 1.13 2004/02/25 16:15:19 schlue
054: * Chabacc servlet extensions added.
055: *
056: * Revision 1.12 2004/02/24 15:20:05 schlue
057: * Servlet code (initial version) added.
058: *
059: * Revision 1.11 2004/01/30 14:36:30 lipp
060: * Partial implementation of message receipt.
061: *
062: * Revision 1.10 2003/10/08 19:13:38 lipp
063: * Fixed multi caller problem.
064: *
065: * Revision 1.9 2003/10/08 15:15:35 lipp
066: * Updated channel handling.
067: *
068: * Revision 1.8 2003/10/07 21:04:59 lipp
069: * Made process selectable.
070: *
071: * Revision 1.7 2003/10/06 20:43:22 lipp
072: * Continuing channel communication.
073: *
074: * Revision 1.6 2003/10/06 18:28:48 lipp
075: * Added data submission.
076: *
077: * Revision 1.5 2003/10/06 15:21:15 lipp
078: * Use session create method.
079: *
080: * Revision 1.4 2003/10/06 13:57:18 lipp
081: * Finished restructuring.
082: *
083: * Revision 1.3 2003/10/05 19:57:20 lipp
084: * Prepared reorganization.
085: *
086: * Revision 1.2 2003/10/05 15:40:18 lipp
087: * Continuing chabacc implementation.
088: *
089: * Revision 1.1 2003/10/02 20:04:28 lipp
090: * Started channel based access module.
091: *
092: */
093: package de.danet.an.workflow.tools.chabacc.plain;
094:
095: import java.io.CharArrayWriter;
096: import java.io.IOException;
097: import java.io.PrintWriter;
098:
099: import java.util.Collection;
100: import java.util.Enumeration;
101: import java.util.Map;
102: import java.util.StringTokenizer;
103:
104: import java.lang.reflect.InvocationTargetException;
105: import java.rmi.RemoteException;
106:
107: import javax.servlet.ServletConfig;
108: import javax.servlet.ServletException;
109: import javax.servlet.http.HttpServlet;
110: import javax.servlet.http.HttpServletRequest;
111: import javax.servlet.http.HttpServletResponse;
112: import javax.servlet.http.HttpSession;
113: import javax.xml.transform.OutputKeys;
114: import javax.xml.transform.Transformer;
115: import javax.xml.transform.TransformerConfigurationException;
116: import javax.xml.transform.TransformerFactory;
117: import javax.xml.transform.sax.SAXTransformerFactory;
118: import javax.xml.transform.sax.TransformerHandler;
119: import javax.xml.transform.stream.StreamResult;
120:
121: import org.xml.sax.SAXException;
122:
123: import de.danet.an.workflow.omgcore.AlreadyRunningException;
124: import de.danet.an.workflow.omgcore.CannotStartException;
125: import de.danet.an.workflow.omgcore.InvalidDataException;
126: import de.danet.an.workflow.omgcore.ProcessData;
127: import de.danet.an.workflow.omgcore.WfProcess;
128:
129: import de.danet.an.workflow.api.Channel;
130: import de.danet.an.workflow.api.DefaultProcessData;
131: import de.danet.an.workflow.api.DefaultRequester;
132: import de.danet.an.workflow.api.FactoryConfigurationError;
133: import de.danet.an.workflow.api.InvalidKeyException;
134: import de.danet.an.workflow.api.MethodInvocationBatch;
135: import de.danet.an.workflow.api.ProcessDefinitionDirectory;
136: import de.danet.an.workflow.api.ProcessDirectory;
137: import de.danet.an.workflow.api.ProcessMgr;
138: import de.danet.an.workflow.api.SAXEventBuffer;
139: import de.danet.an.workflow.api.WorkflowService;
140: import de.danet.an.workflow.api.WorkflowServiceFactory;
141:
142: /**
143: * This class provides an interface between the workflow engine (i.e. its
144: * processes and any HTTP based client (e.g. Web browser application).
145: *
146: * @author <a href="mailto:mnl@mnl.de">Michael N. Lipp</a>
147: * @version $Revision: 1.4 $
148: */
149:
150: public class Servlet extends HttpServlet {
151:
152: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
153: .getLog(Servlet.class);
154:
155: /** Configuration parameter "packageId" */
156: private String defaultPackageId = "boot";
157: /** Configuration parameter "processId" */
158: private String defaultProcessId = "chabacc_http_plain";
159: /** Cachable singleton "workflow service" */
160: private WorkflowService wfsCache = null;
161:
162: /** Local exception for handling processing problems. */
163: private class ProcessingException extends Exception {
164: private int statusCode = HttpServletResponse.SC_OK;
165:
166: /** Create exception always with error message and status code.
167: * @param message error message
168: * @param sc status code for servlet response
169: */
170: public ProcessingException(int sc, String message) {
171: super (message);
172: statusCode = sc;
173: }
174:
175: public int getStatusCode() {
176: return statusCode;
177: }
178: }
179:
180: /** Container class for process lookup (retrieval or creation). */
181: private class ProcessLookup {
182: WfProcess process = null;
183: String packageId = null;
184: String processId = null;
185: String procKey = null;
186: boolean created = false;
187: }
188:
189: /** Container class for reponse information from channel. */
190: private class ResponseInfo {
191: String responseData;
192: String mimeType;
193: boolean invalidateSession;
194: }
195:
196: /**
197: * Default init method.
198: *
199: * @param servletConfig a <code>ServletConfig</code> value
200: * @exception ServletException if an error occurs
201: */
202: public void init(ServletConfig servletConfig)
203: throws ServletException {
204: // Read configuration values and overwrite default, if set
205: if (servletConfig != null) {
206: String id = servletConfig
207: .getInitParameter("packagePathSegmentDefault");
208: if (id != null) {
209: defaultPackageId = id;
210: }
211: id = servletConfig
212: .getInitParameter("processPathSegmentDefault");
213: if (id != null) {
214: defaultProcessId = id;
215: }
216: }
217: }
218:
219: /**
220: * Receive HTTP requests for a channel based access to a workflow process.
221: * See user manual (chapter "tools") for a detailed description.
222: *
223: * @param request a <code>HttpServletRequest</code> value
224: * @param response a <code>HttpServletResponse</code> value
225: * @exception ServletException if an error occurs
226: * @exception IOException if an error occurs
227: */
228: public void doPost(HttpServletRequest request,
229: HttpServletResponse response) throws ServletException,
230: IOException {
231: String packageID = null;
232: String processID = null;
233: String dataItemName = null;
234: String dataItemValue = null;
235: boolean waitForResponse = true;
236:
237: // Scan request params and store data values in a map for later use
238: ProcessData sendData = new DefaultProcessData();
239: for (Enumeration e = request.getParameterNames(); e
240: .hasMoreElements();) {
241: String pn = (String) e.nextElement();
242: if (pn.equals("WFM_packageID")) {
243: packageID = request.getParameter(pn);
244: } else if (pn.equals("WFM_processID")) {
245: processID = request.getParameter(pn);
246: } else if (pn.equals("WFM_dataItemName")) {
247: dataItemName = request.getParameter(pn);
248: } else if (pn.equals("WFM_dataItemValue")) {
249: dataItemValue = request.getParameter(pn);
250: } else if (pn.equals("WFM_waitForResponse")) {
251: waitForResponse = (new Boolean(request.getParameter(pn))
252: .booleanValue());
253: } else {
254: sendData.put(pn, request.getParameter(pn));
255: }
256: }
257:
258: HttpSession session = request.getSession(true);
259: if (logger.isDebugEnabled()) {
260: logger.debug("Post called for session " + session.getId());
261: }
262:
263: WorkflowService wfs = getWorkflowService();
264: if (wfs == null) {
265: response.sendError(
266: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
267: "Unable to retrieve workflow service");
268: return;
269: }
270: Channel channel = null;
271: boolean invalidateSession = false;
272: try {
273: // Retrieve (or create) process
274: ProcessLookup pl = lookupProcess(session, packageID,
275: processID, sendData, dataItemName, dataItemValue);
276:
277: // Open channel to process (and start process, or send data)
278: if (waitForResponse) {
279: channel = openChannel(pl);
280: }
281: if (pl.created) {
282: pl.process.start();
283: } else {
284: sendData(session, channel, sendData);
285: }
286: // If no response expected, that's it
287: if (!waitForResponse) {
288: response.setStatus(HttpServletResponse.SC_OK);
289: return;
290: }
291:
292: // forward answer from process
293: Map data = receiveData(session, channel);
294: ResponseInfo responseInfo = getResponseInfo(data);
295: invalidateSession = responseInfo.invalidateSession;
296:
297: response.setStatus(HttpServletResponse.SC_OK);
298: String mt = responseInfo.mimeType;
299: if (mt.indexOf("charset=") < 0) {
300: mt = mt + "; charset=UTF-8";
301: }
302: if (logger.isDebugEnabled()) {
303: logger.debug("Response (of type \"" + mt + "\") is:\n"
304: + responseInfo.responseData);
305: }
306: response.setContentType(mt);
307: PrintWriter ow = response.getWriter();
308: ow.write(responseInfo.responseData);
309: ow.close();
310: return;
311: } catch (CannotStartException e) {
312: logger.error(e.getMessage());
313: response.sendError(
314: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
315: .getMessage());
316: } catch (AlreadyRunningException e) {
317: logger.error(e.getMessage());
318: response.sendError(
319: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
320: .getMessage());
321: } catch (ProcessingException e) {
322: response.sendError(e.getStatusCode(), e.getMessage());
323: return;
324: } finally {
325: if (channel != null) {
326: wfs.release(channel);
327: }
328: if (invalidateSession) {
329: session.invalidate();
330: }
331: }
332: }
333:
334: /**
335: * Create a new process and forward initial response (e.g. HTML start page).
336: * See user manual (chapter "tools") for a detailed description.
337: *
338: * @param request a <code>HttpServletRequest</code> value
339: * @param response a <code>HttpServletResponse</code> value
340: * @exception ServletException if an error occurs
341: * @exception IOException if an error occurs
342: */
343: public void doGet(HttpServletRequest request,
344: HttpServletResponse response) throws ServletException,
345: IOException {
346: String packageID = defaultPackageId;
347: String processID = defaultProcessId;
348: String extraPath = request.getPathInfo();
349: if (extraPath != null) {
350: // Read package ID and process ID from extra path info
351: StringTokenizer tok = new StringTokenizer(extraPath, "/");
352: if (tok.hasMoreTokens()) {
353: packageID = tok.nextToken();
354: }
355: if (tok.hasMoreTokens()) {
356: processID = tok.nextToken();
357: }
358: }
359:
360: WorkflowService wfs = getWorkflowService();
361: if (wfs == null) {
362: response.sendError(
363: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
364: "Unable to retrieve workflow service");
365: return;
366: }
367:
368: // Create new process
369: Channel channel = null;
370: try {
371: ProcessData sendData = new DefaultProcessData();
372: // Create new process
373: ProcessLookup pl = lookupProcess(null, packageID,
374: processID, sendData, null, null);
375:
376: // Build connection to process and start process
377: channel = openChannel(pl);
378: if (pl.created) {
379: pl.process.start();
380: }
381:
382: // Send data to process and forward answer from process
383: if (!pl.created) {
384: sendData(null, channel, sendData);
385: }
386: Map data = receiveData(null, channel);
387: ResponseInfo responseInfo = getResponseInfo(data);
388: response.setStatus(HttpServletResponse.SC_OK);
389: String mt = responseInfo.mimeType;
390: if (mt.indexOf("charset=") < 0) {
391: mt = mt + "; charset=UTF-8";
392: }
393: if (logger.isDebugEnabled()) {
394: logger.debug("Response (of type \"" + mt + "\") is:\n"
395: + responseInfo.responseData);
396: }
397: response.setContentType(mt);
398: PrintWriter ow = response.getWriter();
399: ow.write(responseInfo.responseData);
400: ow.close();
401: return;
402: } catch (CannotStartException e) {
403: logger.error(e.getMessage());
404: response.sendError(
405: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
406: .getMessage());
407: } catch (AlreadyRunningException e) {
408: logger.error(e.getMessage());
409: response.sendError(
410: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
411: .getMessage());
412: } catch (ProcessingException e) {
413: response.sendError(e.getStatusCode(), e.getMessage());
414: return;
415: } finally {
416: if (channel != null) {
417: wfs.release(channel);
418: }
419: }
420: }
421:
422: /**
423: * Helper for process lookup (retrieval or creation).
424: * Saves information about the process in session attributes
425: * "WfM_mgrName" and "WfM_procKey".
426: *
427: * @param session current HTTP session
428: * @param packageID package id of process manager
429: * @param processID id of process
430: * @param initData processData for process initialization
431: * @param dataItemName name of additional process data
432: * @param dataItemValue value of additional process data
433: * @exception ProcessingException if an error occurs
434: */
435: private ProcessLookup lookupProcess(HttpSession session,
436: String packageID, String processID, ProcessData initData,
437: String dataItemName, String dataItemValue)
438: throws ProcessingException {
439: while (true) {
440: try {
441: WorkflowService wfs = getWorkflowService();
442: if (wfs == null) {
443: throw new ProcessingException(
444: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
445: "Unable to retrieve workflow service");
446: }
447: ProcessLookup pl = new ProcessLookup();
448: ProcessDefinitionDirectory procDefDir = wfs
449: .processDefinitionDirectory();
450: if (packageID != null && processID != null) {
451: ProcessMgr mgr = null;
452: try {
453: mgr = procDefDir.processMgr(packageID,
454: processID);
455: } catch (InvalidKeyException e) {
456: throw new ProcessingException(
457: HttpServletResponse.SC_BAD_REQUEST, e
458: .getMessage());
459: }
460: String mgrName = mgr.name();
461: if (dataItemName != null && dataItemValue != null) {
462: // Try to connect to existing process
463: Collection procs = mgr.findByDataItem(
464: dataItemName, dataItemValue);
465: if (procs.size() == 1) {
466: pl.process = (WfProcess) procs.iterator()
467: .next();
468: pl.procKey = pl.process.key();
469: pl.packageId = packageID;
470: pl.processId = processID;
471: if (session != null) {
472: session.setAttribute("WfM_mgrName", mgr
473: .name());
474: session.setAttribute("WfM_procKey",
475: pl.procKey);
476: }
477: return pl;
478: }
479: if (procs.size() > 1) {
480: logger
481: .error("More than one process found for "
482: + mgr.name()
483: + ", data item: "
484: + dataItemName
485: + " = "
486: + dataItemValue);
487: throw new ProcessingException(
488: HttpServletResponse.SC_CONFLICT,
489: "More than one matching process found");
490: }
491: // add to init data for creation
492: initData.put(dataItemName, dataItemValue);
493: }
494: // Not found, create new process
495: MethodInvocationBatch mib = new MethodInvocationBatch();
496: mib
497: .addInvocation(
498: mgr,
499: "createProcess",
500: new String[] { "de.danet.an.workflow.omgcore.WfRequester" },
501: new Object[] { new DefaultRequester(
502: wfs) });
503: mib
504: .addInvocation(
505: -1,
506: "setProcessContext",
507: new String[] { "de.danet.an.workflow.omgcore.ProcessData" },
508: new Object[] { initData }, false);
509: mib.addInvocation(-2, "key", null, null, false);
510: MethodInvocationBatch.Result mir = (MethodInvocationBatch.Result) wfs
511: .executeBatch(mib);
512: if (mir.hasExceptions()) {
513: Exception e = mir.firstException();
514: logger.error("Problem executing batch: "
515: + e.getMessage(), e);
516: throw new ProcessingException(
517: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
518: mir.firstException().getMessage());
519: }
520: pl.process = (WfProcess) mir.result(0);
521: pl.procKey = mir.resultAsString(2);
522: pl.packageId = packageID;
523: pl.processId = processID;
524: pl.created = true;
525: if (session != null) {
526: session.setAttribute("WfM_mgrName", mgrName);
527: session.setAttribute("WfM_procKey", pl.procKey);
528: }
529: return pl;
530: }
531: if (session != null) {
532: // Retrieve process key from session context
533: String mgrName = (String) session
534: .getAttribute("WfM_mgrName");
535: String procKey = (String) session
536: .getAttribute("WfM_procKey");
537: if (mgrName == null || procKey == null) {
538: throw new ProcessingException(
539: HttpServletResponse.SC_BAD_REQUEST,
540: "No process information available");
541: }
542: ProcessDirectory procDir = wfs.processDirectory();
543: try {
544: pl.process = procDir.lookupProcess(mgrName,
545: procKey);
546: pl.procKey = pl.process.key();
547: } catch (InvalidKeyException e) {
548: session.invalidate();
549: throw new ProcessingException(
550: HttpServletResponse.SC_GONE,
551: "Process has been removed");
552: }
553: StringTokenizer tok = new StringTokenizer(mgrName,
554: "/");
555: if (tok.hasMoreTokens()) {
556: pl.packageId = tok.nextToken();
557: }
558: if (tok.hasMoreTokens()) {
559: pl.processId = tok.nextToken();
560: }
561: return pl;
562: }
563: return pl;
564: } catch (RemoteException e) {
565: logger.debug(e.getMessage(), e);
566: } catch (FactoryConfigurationError e) {
567: logger.error(e.getMessage());
568: throw new ProcessingException(
569: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
570: .getMessage());
571: } catch (InvocationTargetException e) {
572: String s = "Unexpected exception: "
573: + e.getCause().getMessage();
574: logger.error(s, e);
575: throw new ProcessingException(
576: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e
577: .getCause().getMessage());
578: }
579: }
580: }
581:
582: /**
583: * Helper for opening a channel to the given process.
584: * If process has been created, it is started after opening the channel.
585: *
586: * @param pl process lookup information
587: * @exception ProcessingException if an error occurs
588: */
589: private Channel openChannel(ProcessLookup pl)
590: throws ProcessingException {
591: while (true) {
592: try {
593: WorkflowService wfs = getWorkflowService();
594: if (wfs == null) {
595: throw new ProcessingException(
596: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
597: "Unable to retrieve workflow service");
598: }
599: ProcessDefinitionDirectory procDefDir = wfs
600: .processDefinitionDirectory();
601: ProcessMgr mgr = null;
602: try {
603: mgr = procDefDir.processMgr(pl.packageId,
604: pl.processId);
605: } catch (InvalidKeyException e) {
606: throw new ProcessingException(
607: HttpServletResponse.SC_BAD_REQUEST, e
608: .getMessage());
609: }
610: ProcessDirectory procDir = wfs.processDirectory();
611: WfProcess proc = null;
612: try {
613: proc = procDir
614: .lookupProcess(mgr.name(), pl.procKey);
615: } catch (InvalidKeyException e) {
616: throw new ProcessingException(
617: HttpServletResponse.SC_GONE,
618: "Process has been removed");
619: }
620: return wfs.getChannel(proc, "initiator");
621: } catch (RemoteException e) {
622: logger.debug(e.getMessage(), e);
623: }
624: }
625: }
626:
627: /**
628: * Helper for sending data to a channel.
629: *
630: * @param session current HTTP session
631: * @param channel channel for sending data
632: * @param sendData data to be sent on channel
633: * @exception ProcessingException if an error occurs
634: */
635: private void sendData(HttpSession session, Channel channel,
636: ProcessData sendData) throws ProcessingException {
637: while (true) {
638: try {
639: channel.sendMessage(sendData);
640: break;
641: } catch (InvalidKeyException e) {
642: if (session != null) {
643: session.invalidate();
644: }
645: throw new ProcessingException(
646: HttpServletResponse.SC_GONE,
647: "Process is no longer accessible: "
648: + e.getMessage());
649: } catch (InvalidDataException e) {
650: throw new ProcessingException(
651: HttpServletResponse.SC_BAD_REQUEST, e
652: .getMessage());
653: } catch (RemoteException e) {
654: logger.debug(e.getMessage(), e);
655: }
656: }
657: }
658:
659: /**
660: * Receive data from the given channel.
661: *
662: * @param session current HTTP session
663: * @param channel channel for sending data
664: * @exception ProcessingException if an error occurs
665: */
666: private Map receiveData(HttpSession session, Channel channel)
667: throws ProcessingException {
668: while (true) {
669: try {
670: Map data = channel.receiveMessage();
671: if (data == null) {
672: throw new InvalidKeyException(
673: "Process has been closed or removed");
674: }
675: return data;
676: } catch (InvalidKeyException e) {
677: if (session != null) {
678: session.invalidate();
679: }
680: throw new ProcessingException(
681: HttpServletResponse.SC_GONE,
682: "Process is no longer accessible: "
683: + e.getMessage());
684: } catch (RemoteException e) {
685: logger.debug(e.getMessage(), e);
686: }
687: }
688: }
689:
690: /**
691: * Request workflow service once after authentification.
692: * Thus it performed be called within the servlet's init method
693: * which may be called during the deployment process.
694: */
695: private synchronized WorkflowService getWorkflowService() {
696: if (wfsCache == null) {
697: try {
698: wfsCache = WorkflowServiceFactory.newInstance()
699: .newWorkflowService();
700: } catch (FactoryConfigurationError e) {
701: logger.error(e.getMessage());
702: }
703: }
704: return wfsCache;
705: }
706:
707: /**
708: * Helper to determine complete reponse info from response data map.
709: *
710: * @param data response data map
711: * @exception ProcessingException if an error occurs
712: */
713: private ResponseInfo getResponseInfo(Map data)
714: throws ProcessingException {
715: // create and initialize result structure
716: ResponseInfo responseInfo = new ResponseInfo();
717: String doctypeSystem = (String) data.get("doctype-system");
718: String doctypePublic = (String) data.get("doctype-public");
719: responseInfo.mimeType = (String) data.get("mimeType");
720: responseInfo.invalidateSession = false;
721: Object responseData = null;
722: if (data.size() == 1) {
723: responseData = data.values().iterator().next();
724: } else {
725: responseData = data.get("data");
726: if (responseData == null) {
727: throw new ProcessingException(
728: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
729: "No data found");
730: }
731: if (data.containsKey("invalidateSession")) {
732: responseInfo.invalidateSession = ((Boolean) data
733: .get("invalidateSession")).booleanValue();
734: }
735: }
736: // transform data into string
737: if (responseData instanceof String) {
738: responseInfo.responseData = (String) responseData;
739: if (responseInfo.mimeType == null) {
740: String cmp = (responseInfo.responseData.length() > 50) ? responseInfo.responseData
741: .substring(0, 50).toUpperCase()
742: : responseInfo.responseData.toUpperCase();
743: if (cmp
744: .startsWith("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML")
745: || cmp
746: .startsWith("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML")) {
747: responseInfo.mimeType = "text/html";
748: } else {
749: responseInfo.mimeType = "application/data";
750: }
751: }
752: } else if (responseData instanceof SAXEventBuffer) {
753: CharArrayWriter out = new CharArrayWriter();
754: try {
755: SAXEventBuffer eventbuf = (SAXEventBuffer) responseData;
756: SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory
757: .newInstance();
758: TransformerHandler th = null;
759: th = tf.newTransformerHandler();
760: Transformer xformer = th.getTransformer();
761: if (doctypeSystem != null) {
762: xformer.setOutputProperty(
763: OutputKeys.DOCTYPE_SYSTEM, doctypeSystem);
764: }
765: if (doctypePublic != null) {
766: xformer.setOutputProperty(
767: OutputKeys.DOCTYPE_PUBLIC, doctypePublic);
768: }
769: th.setResult(new StreamResult(out));
770: eventbuf.emit(th);
771: } catch (SAXException e) {
772: String s = "Error generating XML process data: "
773: + e.getMessage();
774: logger.error(s, e);
775: throw new ProcessingException(
776: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, s);
777: } catch (TransformerConfigurationException e) {
778: String s = "Error generating XML process data: "
779: + e.getMessage();
780: logger.error(s, e);
781: throw new ProcessingException(
782: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, s);
783: }
784: responseInfo.responseData = out.toString();
785: if (responseInfo.mimeType == null) {
786: responseInfo.mimeType = "text/xml";
787: }
788: } else {
789: String e = "Illegal data type in channel message: "
790: + responseData.getClass().getName();
791: logger.error(e);
792: throw new ProcessingException(
793: HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
794: }
795: return responseInfo;
796: }
797: }
|