001: package org.swingml;
002:
003: import java.awt.*;
004: import java.io.*;
005: import java.net.*;
006:
007: import javax.xml.parsers.*;
008:
009: import org.apache.xml.serialize.*;
010: import org.swingml.action.*;
011: import org.swingml.component.*;
012: import org.swingml.errors.*;
013: import org.swingml.server.*;
014: import org.swingml.server.xml.*;
015: import org.swingml.system.*;
016: import org.swingml.task.*;
017: import org.swingml.task.monitoring.*;
018: import org.xml.sax.*;
019: import org.xml.sax.ContentHandler;
020: import org.xml.sax.helpers.*;
021:
022: /**
023: * @author CrossLogic
024: */
025: public class HttpSubmitController {
026:
027: /**
028: * Performs an HTTP GET to the specified address, giving feedback to the
029: * system on its progress.
030: */
031: private static class HttpGetTask extends AbstractTask {
032:
033: private String address;
034:
035: public HttpGetTask(String anAddress, ITaskMonitor aTaskMonitor) {
036: super (aTaskMonitor);
037: setAddress(anAddress);
038: }
039:
040: public Object execute() {
041: String result = "";
042: beginTask();
043: try {
044: progressMade(1, "Connecting to the Server");
045: StringBuffer theValueBuffer = new StringBuffer();
046: SwingMLLogger.getInstance().log(SwingMLLogger.INFO,
047: "Connecting to: " + getAddress());
048: URL theSource = URLHandler.handle(getAddress());
049: URLConnection theConnection = theSource
050: .openConnection();
051: theConnection.setUseCaches(false);
052: // set the cookie so we get the previous session, if we have one
053: // SwingMLLogger.getInstance().log(SwingMLLogger.DEBUG, "GET
054: // cookie session: " + getSessionId());
055: if (getSessionId() != null) {
056: theConnection.setRequestProperty("Cookie",
057: getSessionId());
058: }
059: progressMade(1, "Processing");
060: BufferedReader theBufferedReader = new BufferedReader(
061: new InputStreamReader(theConnection
062: .getInputStream()));
063: char[] readChars = new char[BUFFER_SIZE];
064: int numCharsRead = theBufferedReader.read(readChars);
065: while (numCharsRead > 0) {
066: theValueBuffer.append(new String(readChars, 0,
067: numCharsRead));
068: numCharsRead = theBufferedReader.read(readChars);
069: }
070: theBufferedReader.close();
071: progressMade(1, "Receiving Response");
072: // Get the session id and store it
073: setSessionId(theConnection);
074: result = theValueBuffer.toString();
075: progressMade(1, "Processing Response");
076: } catch (MalformedURLException e) {
077: SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
078: result = getErrorResponse(
079: ISwingMLError.ERROR_SERVER_COMMUNICATION,
080: "Invalid server URL.");
081: } catch (IOException e) {
082: SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
083: if (e instanceof ConnectException) {
084: result = getErrorResponse(
085: ISwingMLError.ERROR_SERVER_COMMUNICATION,
086: null);
087: } else {
088: result = getErrorResponse(
089: ISwingMLError.ERROR_INVALID_SERVER_RESPONSE,
090: null);
091: }
092: }
093: return result;
094: }
095:
096: public Object execute(ITaskMonitor monitor) throws Exception {
097: addTaskMonitor(monitor);
098: return execute();
099: }
100:
101: public String getAddress() {
102: return address;
103: }
104:
105: public String getName() {
106: return "Connecting to Server";
107: }
108:
109: public int getSteps() {
110: return 5;
111: }
112:
113: /**
114: * Simply return the response xml we retreived in the execute.
115: */
116: public Object onComplete(Object result) {
117: String xml = (String) result;
118: SwingMLServerResponse finalResult = parseServerResponse(xml);
119: progressMade(1, "Finished");
120: endTask();
121: return finalResult;
122: }
123:
124: public void setAddress(String anAddress) {
125: address = anAddress;
126: }
127: }
128:
129: /**
130: * Performs an HTTP POST to the specified address (with the given form
131: * parameters), giving feedback to the system on its progress.
132: */
133: private static class HttpPostTask extends AbstractTask {
134:
135: private String address;
136: private String request;
137:
138: public HttpPostTask(String anAddress, String httpRequest,
139: ITaskMonitor aTaskMonitor) {
140: super (aTaskMonitor);
141: setAddress(anAddress);
142: setRequest(httpRequest);
143: }
144:
145: public Object execute() {
146: String result = "";
147: beginTask();
148: try {
149: progressMade(1, "Connecting to the Server");
150: SwingMLLogger.getInstance().log(SwingMLLogger.INFO,
151: "Connecting to: " + getAddress());
152: URL theUrl = URLHandler.handle(getAddress());
153: URLConnection theUrlConnection = theUrl
154: .openConnection();
155: // set the cookie so we get the previous session
156: // SwingMLLogger.getInstance().log(SwingMLLogger.DEBUG, "POST
157: // cookie session: " + getSessionId());
158: if (getSessionId() != null) {
159: theUrlConnection.setRequestProperty("Cookie",
160: getSessionId());
161: }
162: theUrlConnection.setUseCaches(false);
163: theUrlConnection.setDoOutput(true);
164:
165: progressMade(1, "Sending Data to the Server");
166: ByteArrayOutputStream theByteStream = new ByteArrayOutputStream(
167: BUFFER_SIZE);
168: PrintWriter theOutput = new PrintWriter(theByteStream,
169: true);
170: if (getRequest() != null && getRequest().length() > 100) {
171: SwingMLLogger.getInstance().log(
172: SwingMLLogger.INFO,
173: "Adding parameters: "
174: + getRequest().substring(0, 100)
175: + "...");
176: } else {
177: SwingMLLogger.getInstance().log(SwingMLLogger.INFO,
178: "Adding parameters: " + getRequest());
179: }
180: theOutput.print(getRequest());
181: theOutput.flush();
182: theUrlConnection.setRequestProperty("Content-Length",
183: theByteStream.size() + "");
184: theUrlConnection.setRequestProperty("Content-Type",
185: "application/x-www-form-urlencoded");
186: theByteStream.writeTo(theUrlConnection
187: .getOutputStream());
188:
189: // Receive Http Response.
190: progressMade(1, "Processing");
191: BufferedReader theBufferedReader = new BufferedReader(
192: new InputStreamReader(theUrlConnection
193: .getInputStream()));
194: StringBuffer theHttpResponse = new StringBuffer();
195: char[] readChars = new char[BUFFER_SIZE];
196: int numCharsRead = theBufferedReader.read(readChars);
197: while (numCharsRead > 0) {
198: theHttpResponse.append(new String(readChars, 0,
199: numCharsRead));
200: numCharsRead = theBufferedReader.read(readChars);
201: }
202: // Get the session id and store it
203: setSessionId(theUrlConnection);
204:
205: progressMade(1, "Receiving Response");
206: result = theHttpResponse.toString();
207: theBufferedReader.close();
208: theByteStream.close();
209: theOutput.close();
210:
211: progressMade(1, "Processing Response");
212: } catch (MalformedURLException e) {
213: SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
214: result = getErrorResponse(
215: ISwingMLError.ERROR_SERVER_COMMUNICATION,
216: "Invalid server URL.");
217: } catch (IOException e) {
218: SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
219: if (e instanceof FileNotFoundException) {
220: result = getErrorResponse(
221: ISwingMLError.ERROR_INVALID_SERVER_RESPONSE,
222: null);
223: } else {
224: result = getErrorResponse(
225: ISwingMLError.ERROR_SERVER_COMMUNICATION,
226: null);
227: }
228: }
229: return result;
230: }
231:
232: public Object execute(ITaskMonitor monitor) throws Exception {
233: addTaskMonitor(monitor);
234: return execute();
235: }
236:
237: public String getAddress() {
238: return address;
239: }
240:
241: public String getName() {
242: return "Connecting to Server";
243: }
244:
245: public String getRequest() {
246: return request;
247: }
248:
249: /**
250: * 6 steps - Connect, Send, Receive, Process, Done, OnComplete
251: */
252: public int getSteps() {
253: return 5;
254: }
255:
256: /**
257: * Simply return the response xml we retreived in the execute.
258: */
259: public Object onComplete(Object result) {
260: String xml = (String) result;
261: SwingMLServerResponse finalResult = parseServerResponse(xml);
262: progressMade(1, "Finished");
263: endTask();
264: return finalResult;
265: }
266:
267: public void setAddress(String anAddress) {
268: address = anAddress;
269: }
270:
271: public void setRequest(String aRequest) {
272: request = aRequest;
273: }
274: }
275:
276: private static URL codeBase;
277: private static final int BUFFER_SIZE = 32000;
278: private static String serverURL;
279: private static String sessionId = null;
280:
281: /**
282: * Uses the parent parameter as a starting point for building the parameters
283: * to use during a submit() operation.
284: *
285: * @param parent
286: * A reference to the Container to use as the root during the
287: * construction of the document's parameters.
288: */
289: public static String buildHttpRequest(Container aContainer) {
290: StringBuffer theFormParameters = new StringBuffer();
291: processFormParameters(aContainer, theFormParameters);
292: if (theFormParameters.length() != 0) {
293: theFormParameters
294: .deleteCharAt(theFormParameters.length() - 1);
295: }
296: return theFormParameters.toString();
297: }
298:
299: private static String createErrorTag(int type, String message) {
300: return "<"
301: + ISwingMLResponseConstants.ELEMENT_ERROR
302: + " "
303: + ISwingMLResponseConstants.ATTRIBUTE_ERROR_TYPE
304: + "=\""
305: + type
306: + "\">"
307: + message
308: + createTag(ISwingMLResponseConstants.ELEMENT_ERROR,
309: true);
310: }
311:
312: private static String createTag(String elementName) {
313: return createTag(elementName, false);
314: }
315:
316: private static String createTag(String elementName, boolean isEndTag) {
317: return "<" + (isEndTag ? "/" : "") + elementName + ">";
318: }
319:
320: public static URL getCodeBase() {
321: return codeBase;
322: }
323:
324: /**
325: * Return an error panel saying that the server could not be connected to.
326: *
327: * @return
328: */
329: public static String getConnectionErrorSpec() {
330: return "<FRAME LAYOUT=\"BorderLayout\" NAME=\"ServerNotFoundWindow\" TEXT=\"Server Unavailable\" WIDTH=\"300\" HEIGHT=\"150\" >"
331: + "<PANEL NAME=\"ServerUnavailablePanel\" LAYOUT=\"BorderLayout\" ORIENTATION=\"Center\">"
332: + "<PANEL NAME=\"LabelPanel\" ORIENTATION=\"Center\">"
333: + "<LABEL NAME=\"ErrorLabel\" TEXT=\"Unable to connect to the server. Application will now exit.\" />"
334: + "</PANEL>"
335: + "<PANEL NAME=\"OkButtonOuterPanel\" ORIENTATION=\"South\" LAYOUT=\"BorderLayout\">"
336: + "<PANEL NAME=\"OkButtonPanel\" ORIENTATION=\"Center\" LAYOUT=\"FlowLayout\">"
337: + "<BUTTON ENABLED=\"True\" NAME=\"okButton\" TEXT=\"OK\" ORIENTATION=\"Center\">"
338: + "<LISTENER EVENT=\"ActionListener.actionPerformed\">"
339: + "<EXTERNAL-ACTION COMPONENT=\"ServerNotFoundWindow\" EXTERNAL-CLASS=\"com.yell.common.swingmlclient.controller.DesktopEventHandler\">"
340: + "<ACTION-PARAM NAME=\"EXIT\" VALUE=\"ServerNotFound\" />"
341: + "<ACTION-PARAM NAME=\"EVENT-SOURCE\" VALUE=\"okButton\" />"
342: + "</EXTERNAL-ACTION>"
343: + "</LISTENER>"
344: + "</BUTTON>"
345: + "</PANEL>" + "</PANEL>" + "</PANEL>" + "</FRAME>";
346: }
347:
348: private static String getErrorResponse(int errorType, String message) {
349: String result = createTag(ISwingMLResponseConstants.ELEMENT_RESPONSE);
350: result += createTag(ISwingMLResponseConstants.ELEMENT_HEAD);
351: result += createTag(ISwingMLResponseConstants.ELEMENT_ERRORS);
352: // find and add the system message
353: int matchedType = ISwingMLError.ERROR_UNKNOWN;
354: switch (errorType) {
355: case ISwingMLError.ERROR_INVALID_SERVER_RESPONSE:
356: matchedType = ISwingMLError.ERROR_INVALID_SERVER_RESPONSE;
357: result += createErrorTag(
358: ISwingMLError.ERROR_INVALID_SERVER_RESPONSE,
359: "The server returned an invalid response.");
360: break;
361: case ISwingMLError.ERROR_NO_SERVER_RESPONSE:
362: matchedType = ISwingMLError.ERROR_NO_SERVER_RESPONSE;
363: result += createErrorTag(
364: ISwingMLError.ERROR_NO_SERVER_RESPONSE,
365: "The server did not return a response");
366: break;
367: case ISwingMLError.ERROR_SERVER_COMMUNICATION:
368: matchedType = ISwingMLError.ERROR_SERVER_COMMUNICATION;
369: result += createErrorTag(
370: ISwingMLError.ERROR_SERVER_COMMUNICATION,
371: "Unable to connect to the server.");
372: break;
373: default:
374: result += createErrorTag(ISwingMLError.ERROR_UNKNOWN,
375: "An unknown error occurred.");
376: }
377: // add the specific error message passed in
378: if (message != null && message.length() > 0) {
379: result += createErrorTag(matchedType, message);
380: }
381: result += createTag(ISwingMLResponseConstants.ELEMENT_ERRORS,
382: true);
383: result += createTag(ISwingMLResponseConstants.ELEMENT_HEAD,
384: true);
385: result += createTag(ISwingMLResponseConstants.ELEMENT_RESPONSE,
386: true);
387: return result;
388: }
389:
390: public static String getInvalidTargetErrorSpec() {
391: return "<FRAME LAYOUT=\"BorderLayout\" NAME=\"InvalidTargetWindow\" TEXT=\"Invalid Target URL\" WIDTH=\"375\" HEIGHT=\"150\" >"
392: + "<PANEL NAME=\"InvalidTargetPanel\" LAYOUT=\"BorderLayout\" ORIENTATION=\"Center\">"
393: + "<PANEL NAME=\"LabelPanel\" ORIENTATION=\"Center\">"
394: + "<LABEL NAME=\"ErrorLabel\" WRAP-TEXT=\"True\" TEXT=\"Invalid component name was specified. No server URL could be found.\" />"
395: + "</PANEL>"
396: + "<PANEL NAME=\"OkButtonOuterPanel\" ORIENTATION=\"South\" LAYOUT=\"BorderLayout\">"
397: + "<PANEL NAME=\"OkButtonPanel\" ORIENTATION=\"Center\" LAYOUT=\"FlowLayout\">"
398: + "<BUTTON ENABLED=\"True\" NAME=\"okButton\" TEXT=\"OK\" ORIENTATION=\"Center\">"
399: + "<LISTENER EVENT=\"ActionListener.actionPerformed\">"
400: + "<EXTERNAL-ACTION COMPONENT=\"InvalidTargetWindow\" EXTERNAL-CLASS=\"com.yell.common.swingmlclient.controller.DesktopEventHandler\">"
401: + "<ACTION-PARAM NAME=\"EXIT\" VALUE=\"InvalidTarget\" />"
402: + "<ACTION-PARAM NAME=\"EVENT-SOURCE\" VALUE=\"okButton\" />"
403: + "</EXTERNAL-ACTION>"
404: + "</LISTENER>"
405: + "</BUTTON>"
406: + "</PANEL>" + "</PANEL>" + "</PANEL>" + "</FRAME>";
407: }
408:
409: /**
410: * Gets the JSESSIONID that is being set if one exists.
411: *
412: * @param httpConnection -
413: * The URLConnection
414: * @return The JSESSIONID
415: */
416: protected static String getJSessionId(URLConnection httpConnection) {
417: return httpConnection.getHeaderField("Set-Cookie");
418: }
419:
420: public static String getServerURL() {
421: return serverURL;
422: }
423:
424: public static String getSessionId() {
425: return sessionId;
426: }
427:
428: /**
429: * Performs the equivalent of an HTTP Get call to the given URL, but doesn't
430: * show progress.
431: */
432: public static SwingMLServerResponse getSpec(String address) {
433: return getSpec(address, null);
434: }
435:
436: /**
437: * Performs the equivalent of an HTTP Get call to the given URL, indicating
438: * progress as it processes.
439: */
440: public static SwingMLServerResponse getSpec(String address,
441: Container container) {
442: return (SwingMLServerResponse) TaskExecutor.getInstance()
443: .runTask(
444: new HttpGetTask(address, StatusBar
445: .findStatusBarFor(container)));
446: }
447:
448: /**
449: * Parse the XML returned from the server into a SwingMLResponse object
450: *
451: * @param xml
452: * @return
453: */
454: private static SwingMLServerResponse parseServerResponse(String xml) {
455: SwingMLServerResponse result = new NullSwingMLResponse();
456: if (xml != null && xml.length() > 0) {
457: try {
458: ServerResponseFilter filter = new ServerResponseFilter();
459: OutputFormat format = new OutputFormat(Method.XML,
460: null, true);
461: format.setOmitXMLDeclaration(true);
462: format.setPreserveSpace(true);
463: StringWriter writer = new StringWriter();
464: ContentHandler xmlSerializer = new XMLSerializer(
465: writer, format).asContentHandler();
466: InputSource inputSource = new InputSource(
467: new StringReader(xml));
468: filter.setContentHandler(xmlSerializer);
469: SAXParser parser = SAXParserFactory.newInstance()
470: .newSAXParser();
471: XMLReader inputReader = new ParserAdapter(parser
472: .getParser());
473: inputReader.setContentHandler(filter);
474: inputReader.parse(inputSource);
475: result = filter.getResponse();
476: result.setSwingMLSpec(writer.toString());
477: } catch (ParserConfigurationException e) {
478: SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
479: } catch (SAXException e) {
480: SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
481: } catch (FactoryConfigurationError e) {
482: SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
483: } catch (IOException e) {
484: SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
485: }
486: }
487: return result;
488: }
489:
490: public static void processDocumentBase(String aSpecLocation) {
491: int theLastIndex = aSpecLocation.lastIndexOf("/");
492: String theDocumentBase = aSpecLocation.substring(0,
493: theLastIndex + 1);
494: setServerURL(theDocumentBase);
495: }
496:
497: public static void processFormParameters(Container aContainer,
498: StringBuffer aFormParameters) {
499: try {
500: Component theComponent = null;
501: XMLTranslatable theXMLTranslatableComponent = null;
502: // process the container first
503: if (aContainer instanceof XMLTranslatable) {
504: theXMLTranslatableComponent = (XMLTranslatable) aContainer;
505: aFormParameters.append(aContainer.getName() + "=");
506: aFormParameters.append(URLEncoder.encode(
507: theXMLTranslatableComponent.getXMLValue() + "",
508: "UTF-8")
509: + "&");
510: }
511: Component[] aComponents = aContainer.getComponents();
512: for (int i = 0; i < aComponents.length; i++) {
513: theComponent = aComponents[i];
514: processFormParameters((Container) theComponent,
515: aFormParameters);
516: }
517: } catch (UnsupportedEncodingException e) {
518: SwingMLLogger.getInstance().log(e);
519: }
520: }
521:
522: public static void setCodeBase(URL base) {
523: HttpSubmitController.codeBase = base;
524: }
525:
526: private static void setServerURL(String someLocation) {
527: HttpSubmitController.serverURL = someLocation;
528: }
529:
530: public static void setSessionId(URLConnection aConnection) {
531: String sid = getJSessionId(aConnection);
532: // SwingMLLogger.getInstance().log(SwingMLLogger.DEBUG, "Set session id:
533: // " + sid);
534: if (sid != null) {
535: sessionId = sid;
536: }
537: }
538:
539: public static SwingMLServerResponse submit(String address,
540: Container submitter, String parameters, boolean showProgress) {
541: SwingMLServerResponse result = null;
542: // Create the HTTP request.
543: String theHttpRequest = buildHttpRequest(submitter);
544: // Append parameters, if necessary
545: StringBuffer sb = new StringBuffer(theHttpRequest);
546: if (parameters != null) {
547: sb.append("&");
548: sb.append(parameters);
549: theHttpRequest = sb.toString();
550: }
551: if (showProgress) {
552: result = submit(address, theHttpRequest, submitter);
553: } else {
554: result = submit(address, theHttpRequest, null);
555: }
556: return result;
557: }
558:
559: /**
560: * Performs the equivalent of an HTTP POST to the given address, with the
561: * given parameters.
562: *
563: * @param address
564: * @param request
565: * @param container
566: * @return
567: */
568: public static SwingMLServerResponse submit(String address,
569: String request, Container container) {
570: ITaskMonitor taskMonitor = StatusBar
571: .findStatusBarFor(container);
572: HttpPostTask postTask = new HttpPostTask(address, request,
573: taskMonitor);
574: return (SwingMLServerResponse) TaskExecutor.getInstance()
575: .runTask(postTask);
576: }
577:
578: public static SwingMLServerResponse submitRemoteAction(
579: String anAddress, RemoteAction action, Container aContainer) {
580: String httpRequest = action.createParamString();
581: return submit(anAddress, httpRequest, aContainer);
582: }
583: }
|