package org.swingml;
import java.awt.*;
import java.io.*;
import java.net.*;
import javax.xml.parsers.*;
import org.apache.xml.serialize.*;
import org.swingml.action.*;
import org.swingml.component.*;
import org.swingml.errors.*;
import org.swingml.server.*;
import org.swingml.server.xml.*;
import org.swingml.system.*;
import org.swingml.task.*;
import org.swingml.task.monitoring.*;
import org.xml.sax.*;
import org.xml.sax.ContentHandler;
import org.xml.sax.helpers.*;
/**
* @author CrossLogic
*/
public class HttpSubmitController {
/**
* Performs an HTTP GET to the specified address, giving feedback to the
* system on its progress.
*/
private static class HttpGetTask extends AbstractTask {
private String address;
public HttpGetTask (String anAddress, ITaskMonitor aTaskMonitor) {
super(aTaskMonitor);
setAddress(anAddress);
}
public Object execute () {
String result = "";
beginTask();
try {
progressMade(1, "Connecting to the Server");
StringBuffer theValueBuffer = new StringBuffer();
SwingMLLogger.getInstance().log(SwingMLLogger.INFO, "Connecting to: " + getAddress());
URL theSource = URLHandler.handle(getAddress());
URLConnection theConnection = theSource.openConnection();
theConnection.setUseCaches(false);
// set the cookie so we get the previous session, if we have one
// SwingMLLogger.getInstance().log(SwingMLLogger.DEBUG, "GET
// cookie session: " + getSessionId());
if (getSessionId() != null) {
theConnection.setRequestProperty("Cookie", getSessionId());
}
progressMade(1, "Processing");
BufferedReader theBufferedReader = new BufferedReader(new InputStreamReader(theConnection.getInputStream()));
char[] readChars = new char[BUFFER_SIZE];
int numCharsRead = theBufferedReader.read(readChars);
while (numCharsRead > 0) {
theValueBuffer.append(new String(readChars, 0, numCharsRead));
numCharsRead = theBufferedReader.read(readChars);
}
theBufferedReader.close();
progressMade(1, "Receiving Response");
// Get the session id and store it
setSessionId(theConnection);
result = theValueBuffer.toString();
progressMade(1, "Processing Response");
} catch (MalformedURLException e) {
SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
result = getErrorResponse(ISwingMLError.ERROR_SERVER_COMMUNICATION, "Invalid server URL.");
} catch (IOException e) {
SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
if (e instanceof ConnectException) {
result = getErrorResponse(ISwingMLError.ERROR_SERVER_COMMUNICATION, null);
} else {
result = getErrorResponse(ISwingMLError.ERROR_INVALID_SERVER_RESPONSE, null);
}
}
return result;
}
public Object execute (ITaskMonitor monitor) throws Exception {
addTaskMonitor(monitor);
return execute();
}
public String getAddress () {
return address;
}
public String getName () {
return "Connecting to Server";
}
public int getSteps () {
return 5;
}
/**
* Simply return the response xml we retreived in the execute.
*/
public Object onComplete (Object result) {
String xml = (String) result;
SwingMLServerResponse finalResult = parseServerResponse(xml);
progressMade(1, "Finished");
endTask();
return finalResult;
}
public void setAddress (String anAddress) {
address = anAddress;
}
}
/**
* Performs an HTTP POST to the specified address (with the given form
* parameters), giving feedback to the system on its progress.
*/
private static class HttpPostTask extends AbstractTask {
private String address;
private String request;
public HttpPostTask (String anAddress, String httpRequest, ITaskMonitor aTaskMonitor) {
super(aTaskMonitor);
setAddress(anAddress);
setRequest(httpRequest);
}
public Object execute () {
String result = "";
beginTask();
try {
progressMade(1, "Connecting to the Server");
SwingMLLogger.getInstance().log(SwingMLLogger.INFO, "Connecting to: " + getAddress());
URL theUrl = URLHandler.handle(getAddress());
URLConnection theUrlConnection = theUrl.openConnection();
// set the cookie so we get the previous session
// SwingMLLogger.getInstance().log(SwingMLLogger.DEBUG, "POST
// cookie session: " + getSessionId());
if (getSessionId() != null) {
theUrlConnection.setRequestProperty("Cookie", getSessionId());
}
theUrlConnection.setUseCaches(false);
theUrlConnection.setDoOutput(true);
progressMade(1, "Sending Data to the Server");
ByteArrayOutputStream theByteStream = new ByteArrayOutputStream(BUFFER_SIZE);
PrintWriter theOutput = new PrintWriter(theByteStream, true);
if (getRequest() != null && getRequest().length() > 100) {
SwingMLLogger.getInstance().log(SwingMLLogger.INFO, "Adding parameters: " + getRequest().substring(0, 100) + "...");
} else {
SwingMLLogger.getInstance().log(SwingMLLogger.INFO, "Adding parameters: " + getRequest());
}
theOutput.print(getRequest());
theOutput.flush();
theUrlConnection.setRequestProperty("Content-Length", theByteStream.size() + "");
theUrlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
theByteStream.writeTo(theUrlConnection.getOutputStream());
// Receive Http Response.
progressMade(1, "Processing");
BufferedReader theBufferedReader = new BufferedReader(new InputStreamReader(theUrlConnection.getInputStream()));
StringBuffer theHttpResponse = new StringBuffer();
char[] readChars = new char[BUFFER_SIZE];
int numCharsRead = theBufferedReader.read(readChars);
while (numCharsRead > 0) {
theHttpResponse.append(new String(readChars, 0, numCharsRead));
numCharsRead = theBufferedReader.read(readChars);
}
// Get the session id and store it
setSessionId(theUrlConnection);
progressMade(1, "Receiving Response");
result = theHttpResponse.toString();
theBufferedReader.close();
theByteStream.close();
theOutput.close();
progressMade(1, "Processing Response");
} catch (MalformedURLException e) {
SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
result = getErrorResponse(ISwingMLError.ERROR_SERVER_COMMUNICATION, "Invalid server URL.");
} catch (IOException e) {
SwingMLLogger.getInstance().log(ILogCapable.ERROR, e);
if (e instanceof FileNotFoundException) {
result = getErrorResponse(ISwingMLError.ERROR_INVALID_SERVER_RESPONSE, null);
} else {
result = getErrorResponse(ISwingMLError.ERROR_SERVER_COMMUNICATION, null);
}
}
return result;
}
public Object execute (ITaskMonitor monitor) throws Exception {
addTaskMonitor(monitor);
return execute();
}
public String getAddress () {
return address;
}
public String getName () {
return "Connecting to Server";
}
public String getRequest () {
return request;
}
/**
* 6 steps - Connect, Send, Receive, Process, Done, OnComplete
*/
public int getSteps () {
return 5;
}
/**
* Simply return the response xml we retreived in the execute.
*/
public Object onComplete (Object result) {
String xml = (String) result;
SwingMLServerResponse finalResult = parseServerResponse(xml);
progressMade(1, "Finished");
endTask();
return finalResult;
}
public void setAddress (String anAddress) {
address = anAddress;
}
public void setRequest (String aRequest) {
request = aRequest;
}
}
private static URL codeBase;
private static final int BUFFER_SIZE = 32000;
private static String serverURL;
private static String sessionId = null;
/**
* Uses the parent parameter as a starting point for building the parameters
* to use during a submit() operation.
*
* @param parent
* A reference to the Container to use as the root during the
* construction of the document's parameters.
*/
public static String buildHttpRequest (Container aContainer) {
StringBuffer theFormParameters = new StringBuffer();
processFormParameters(aContainer, theFormParameters);
if (theFormParameters.length() != 0) {
theFormParameters.deleteCharAt(theFormParameters.length() - 1);
}
return theFormParameters.toString();
}
private static String createErrorTag (int type, String message) {
return "<" + ISwingMLResponseConstants.ELEMENT_ERROR + " " + ISwingMLResponseConstants.ATTRIBUTE_ERROR_TYPE + "=\"" + type + "\">" + message
+ createTag(ISwingMLResponseConstants.ELEMENT_ERROR, true);
}
private static String createTag (String elementName) {
return createTag(elementName, false);
}
private static String createTag (String elementName, boolean isEndTag) {
return "<" + (isEndTag ? "/" : "") + elementName + ">";
}
public static URL getCodeBase () {
return codeBase;
}
/**
* Return an error panel saying that the server could not be connected to.
*
* @return
*/
public static String getConnectionErrorSpec () {
return "<FRAME LAYOUT=\"BorderLayout\" NAME=\"ServerNotFoundWindow\" TEXT=\"Server Unavailable\" WIDTH=\"300\" HEIGHT=\"150\" >"
+ "<PANEL NAME=\"ServerUnavailablePanel\" LAYOUT=\"BorderLayout\" ORIENTATION=\"Center\">" + "<PANEL NAME=\"LabelPanel\" ORIENTATION=\"Center\">"
+ "<LABEL NAME=\"ErrorLabel\" TEXT=\"Unable to connect to the server. Application will now exit.\" />" + "</PANEL>"
+ "<PANEL NAME=\"OkButtonOuterPanel\" ORIENTATION=\"South\" LAYOUT=\"BorderLayout\">" + "<PANEL NAME=\"OkButtonPanel\" ORIENTATION=\"Center\" LAYOUT=\"FlowLayout\">"
+ "<BUTTON ENABLED=\"True\" NAME=\"okButton\" TEXT=\"OK\" ORIENTATION=\"Center\">" + "<LISTENER EVENT=\"ActionListener.actionPerformed\">"
+ "<EXTERNAL-ACTION COMPONENT=\"ServerNotFoundWindow\" EXTERNAL-CLASS=\"com.yell.common.swingmlclient.controller.DesktopEventHandler\">"
+ "<ACTION-PARAM NAME=\"EXIT\" VALUE=\"ServerNotFound\" />" + "<ACTION-PARAM NAME=\"EVENT-SOURCE\" VALUE=\"okButton\" />" + "</EXTERNAL-ACTION>" + "</LISTENER>" + "</BUTTON>"
+ "</PANEL>" + "</PANEL>" + "</PANEL>" + "</FRAME>";
}
private static String getErrorResponse (int errorType, String message) {
String result = createTag(ISwingMLResponseConstants.ELEMENT_RESPONSE);
result += createTag(ISwingMLResponseConstants.ELEMENT_HEAD);
result += createTag(ISwingMLResponseConstants.ELEMENT_ERRORS);
// find and add the system message
int matchedType = ISwingMLError.ERROR_UNKNOWN;
switch (errorType) {
case ISwingMLError.ERROR_INVALID_SERVER_RESPONSE:
matchedType = ISwingMLError.ERROR_INVALID_SERVER_RESPONSE;
result += createErrorTag(ISwingMLError.ERROR_INVALID_SERVER_RESPONSE, "The server returned an invalid response.");
break;
case ISwingMLError.ERROR_NO_SERVER_RESPONSE:
matchedType = ISwingMLError.ERROR_NO_SERVER_RESPONSE;
result += createErrorTag(ISwingMLError.ERROR_NO_SERVER_RESPONSE, "The server did not return a response");
break;
case ISwingMLError.ERROR_SERVER_COMMUNICATION:
matchedType = ISwingMLError.ERROR_SERVER_COMMUNICATION;
result += createErrorTag(ISwingMLError.ERROR_SERVER_COMMUNICATION, "Unable to connect to the server.");
break;
default:
result += createErrorTag(ISwingMLError.ERROR_UNKNOWN, "An unknown error occurred.");
}
// add the specific error message passed in
if (message != null && message.length() > 0) {
result += createErrorTag(matchedType, message);
}
result += createTag(ISwingMLResponseConstants.ELEMENT_ERRORS, true);
result += createTag(ISwingMLResponseConstants.ELEMENT_HEAD, true);
result += createTag(ISwingMLResponseConstants.ELEMENT_RESPONSE, true);
return result;
}
public static String getInvalidTargetErrorSpec () {
return "<FRAME LAYOUT=\"BorderLayout\" NAME=\"InvalidTargetWindow\" TEXT=\"Invalid Target URL\" WIDTH=\"375\" HEIGHT=\"150\" >"
+ "<PANEL NAME=\"InvalidTargetPanel\" LAYOUT=\"BorderLayout\" ORIENTATION=\"Center\">" + "<PANEL NAME=\"LabelPanel\" ORIENTATION=\"Center\">"
+ "<LABEL NAME=\"ErrorLabel\" WRAP-TEXT=\"True\" TEXT=\"Invalid component name was specified. No server URL could be found.\" />" + "</PANEL>"
+ "<PANEL NAME=\"OkButtonOuterPanel\" ORIENTATION=\"South\" LAYOUT=\"BorderLayout\">" + "<PANEL NAME=\"OkButtonPanel\" ORIENTATION=\"Center\" LAYOUT=\"FlowLayout\">"
+ "<BUTTON ENABLED=\"True\" NAME=\"okButton\" TEXT=\"OK\" ORIENTATION=\"Center\">" + "<LISTENER EVENT=\"ActionListener.actionPerformed\">"
+ "<EXTERNAL-ACTION COMPONENT=\"InvalidTargetWindow\" EXTERNAL-CLASS=\"com.yell.common.swingmlclient.controller.DesktopEventHandler\">"
+ "<ACTION-PARAM NAME=\"EXIT\" VALUE=\"InvalidTarget\" />" + "<ACTION-PARAM NAME=\"EVENT-SOURCE\" VALUE=\"okButton\" />" + "</EXTERNAL-ACTION>" + "</LISTENER>" + "</BUTTON>"
+ "</PANEL>" + "</PANEL>" + "</PANEL>" + "</FRAME>";
}
/**
* Gets the JSESSIONID that is being set if one exists.
*
* @param httpConnection -
* The URLConnection
* @return The JSESSIONID
*/
protected static String getJSessionId (URLConnection httpConnection) {
return httpConnection.getHeaderField("Set-Cookie");
}
public static String getServerURL () {
return serverURL;
}
public static String getSessionId () {
return sessionId;
}
/**
* Performs the equivalent of an HTTP Get call to the given URL, but doesn't
* show progress.
*/
public static SwingMLServerResponse getSpec (String address) {
return getSpec(address, null);
}
/**
* Performs the equivalent of an HTTP Get call to the given URL, indicating
* progress as it processes.
*/
public static SwingMLServerResponse getSpec (String address, Container container) {
return (SwingMLServerResponse) TaskExecutor.getInstance().runTask(new HttpGetTask(address, StatusBar.findStatusBarFor(container)));
}
/**
* Parse the XML returned from the server into a SwingMLResponse object
*
* @param xml
* @return
*/
private static SwingMLServerResponse parseServerResponse (String xml) {
SwingMLServerResponse result = new NullSwingMLResponse();
if (xml != null && xml.length() > 0) {
try {
ServerResponseFilter filter = new ServerResponseFilter();
OutputFormat format = new OutputFormat(Method.XML, null, true);
format.setOmitXMLDeclaration(true);
format.setPreserveSpace(true);
StringWriter writer = new StringWriter();
ContentHandler xmlSerializer = new XMLSerializer(writer, format).asContentHandler();
InputSource inputSource = new InputSource(new StringReader(xml));
filter.setContentHandler(xmlSerializer);
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
XMLReader inputReader = new ParserAdapter(parser.getParser());
inputReader.setContentHandler(filter);
inputReader.parse(inputSource);
result = filter.getResponse();
result.setSwingMLSpec(writer.toString());
} catch (ParserConfigurationException e) {
SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
} catch (SAXException e) {
SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
} catch (FactoryConfigurationError e) {
SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
} catch (IOException e) {
SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
}
}
return result;
}
public static void processDocumentBase (String aSpecLocation) {
int theLastIndex = aSpecLocation.lastIndexOf("/");
String theDocumentBase = aSpecLocation.substring(0, theLastIndex + 1);
setServerURL(theDocumentBase);
}
public static void processFormParameters (Container aContainer, StringBuffer aFormParameters) {
try {
Component theComponent = null;
XMLTranslatable theXMLTranslatableComponent = null;
// process the container first
if (aContainer instanceof XMLTranslatable) {
theXMLTranslatableComponent = (XMLTranslatable) aContainer;
aFormParameters.append(aContainer.getName() + "=");
aFormParameters.append(URLEncoder.encode(theXMLTranslatableComponent.getXMLValue() + "", "UTF-8") + "&");
}
Component[] aComponents = aContainer.getComponents();
for (int i = 0; i < aComponents.length; i++) {
theComponent = aComponents[i];
processFormParameters((Container) theComponent, aFormParameters);
}
} catch (UnsupportedEncodingException e) {
SwingMLLogger.getInstance().log(e);
}
}
public static void setCodeBase (URL base) {
HttpSubmitController.codeBase = base;
}
private static void setServerURL (String someLocation) {
HttpSubmitController.serverURL = someLocation;
}
public static void setSessionId (URLConnection aConnection) {
String sid = getJSessionId(aConnection);
// SwingMLLogger.getInstance().log(SwingMLLogger.DEBUG, "Set session id:
// " + sid);
if (sid != null) {
sessionId = sid;
}
}
public static SwingMLServerResponse submit (String address, Container submitter, String parameters, boolean showProgress) {
SwingMLServerResponse result = null;
// Create the HTTP request.
String theHttpRequest = buildHttpRequest(submitter);
// Append parameters, if necessary
StringBuffer sb = new StringBuffer(theHttpRequest);
if (parameters != null) {
sb.append("&");
sb.append(parameters);
theHttpRequest = sb.toString();
}
if (showProgress) {
result = submit(address, theHttpRequest, submitter);
} else {
result = submit(address, theHttpRequest, null);
}
return result;
}
/**
* Performs the equivalent of an HTTP POST to the given address, with the
* given parameters.
*
* @param address
* @param request
* @param container
* @return
*/
public static SwingMLServerResponse submit (String address, String request, Container container) {
ITaskMonitor taskMonitor = StatusBar.findStatusBarFor(container);
HttpPostTask postTask = new HttpPostTask(address, request, taskMonitor);
return (SwingMLServerResponse) TaskExecutor.getInstance().runTask(postTask);
}
public static SwingMLServerResponse submitRemoteAction (String anAddress, RemoteAction action, Container aContainer) {
String httpRequest = action.createParamString();
return submit(anAddress, httpRequest, aContainer);
}
}
|