Permalink
Cannot retrieve contributors at this time
/* | |
* To change this template, choose Tools | Templates | |
* and open the template in the editor. | |
*/ | |
package com.eas.client; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
import com.eas.application.Loader; | |
import com.eas.client.metadata.Fields; | |
import com.eas.client.metadata.Parameter; | |
import com.eas.client.metadata.Parameters; | |
import com.eas.client.published.PublishedFile; | |
import com.eas.client.queries.Query; | |
import com.eas.client.serial.QueryJSONReader; | |
import com.eas.client.xhr.FormData; | |
import com.eas.client.xhr.ProgressEvent; | |
import com.eas.client.xhr.ProgressHandler; | |
import com.eas.client.xhr.ProgressHandlerAdapter; | |
import com.eas.client.xhr.XMLHttpRequest2; | |
import com.eas.core.Cancellable; | |
import com.eas.core.Utils; | |
import com.google.gwt.core.client.Callback; | |
import com.google.gwt.core.client.GWT; | |
import com.google.gwt.core.client.JavaScriptObject; | |
import com.google.gwt.core.client.JsArrayString; | |
import com.google.gwt.core.client.Scheduler; | |
import com.google.gwt.dom.client.AnchorElement; | |
import com.google.gwt.dom.client.Element; | |
import com.google.gwt.dom.client.NodeList; | |
import com.google.gwt.event.dom.client.LoadEvent; | |
import com.google.gwt.event.dom.client.LoadHandler; | |
import com.google.gwt.http.client.RequestBuilder; | |
import com.google.gwt.http.client.Response; | |
import com.google.gwt.http.client.URL; | |
import com.google.gwt.regexp.shared.MatchResult; | |
import com.google.gwt.regexp.shared.RegExp; | |
import com.google.gwt.safehtml.shared.SafeUri; | |
import com.google.gwt.user.client.Timer; | |
import com.google.gwt.user.client.ui.Frame; | |
import com.google.gwt.user.client.ui.RootPanel; | |
import com.google.gwt.xhr.client.ReadyStateChangeHandler; | |
import com.google.gwt.xhr.client.XMLHttpRequest; | |
import com.google.gwt.xhr.client.XMLHttpRequest.ResponseType; | |
import com.google.gwt.xml.client.Document; | |
import com.google.gwt.xml.client.XMLParser; | |
/** | |
* | |
* @author mg | |
*/ | |
public class AppClient { | |
// | |
private static final RegExp httpPrefixPattern = RegExp.compile("https?://.*"); | |
public static final String APPLICATION_URI = "/application"; | |
private static String sourcePath = "/"; | |
private static boolean simpleModules; | |
public static final String REPORT_LOCATION_CONTENT_TYPE = "text/platypus-report-location"; | |
// | |
private static AppClient appClient; | |
private boolean cacheBustEnabled; | |
private String apiUrl; | |
private String principal; | |
private Map<String, Document> documents = new HashMap<String, Document>(); | |
private Map<String, ModuleStructure> modulesStructures = new HashMap<String, ModuleStructure>(); | |
private Map<String, Query> queries = new HashMap<String, Query>(); | |
private Map<String, Object> serverModules = new HashMap<>(); | |
public static class ModuleStructure { | |
protected Set<String> structure = new HashSet<>(); | |
protected Set<String> clientDependencies = new HashSet<>(); | |
protected Set<String> serverDependencies = new HashSet<>(); | |
protected Set<String> queriesDependencies = new HashSet<>(); | |
public ModuleStructure(String aRelativeFileName) { | |
super(); | |
structure.add(aRelativeFileName); | |
} | |
public ModuleStructure(Set<String> aStructure, Set<String> aClientDependencies, Set<String> aServerDependencies, Set<String> aQueriesDependencies) { | |
super(); | |
structure.addAll(aStructure); | |
clientDependencies.addAll(aClientDependencies); | |
serverDependencies.addAll(aServerDependencies); | |
queriesDependencies.addAll(aQueriesDependencies); | |
} | |
public ModuleStructure(String aRelativeFileName, JsArrayString prefetchedResources, JsArrayString autoDependencies, JsArrayString rpcDependencies, JsArrayString entitiesDependencies) { | |
this(aRelativeFileName); | |
if (prefetchedResources != null) { | |
for (int i = 0; i < prefetchedResources.length(); i++) { | |
structure.add(prefetchedResources.get(i)); | |
} | |
} | |
if (autoDependencies != null) { | |
for (int i = 0; i < autoDependencies.length(); i++) { | |
clientDependencies.add(autoDependencies.get(i)); | |
} | |
} | |
if (rpcDependencies != null) { | |
for (int i = 0; i < rpcDependencies.length(); i++) { | |
serverDependencies.add(rpcDependencies.get(i)); | |
} | |
} | |
if (entitiesDependencies != null) { | |
for (int i = 0; i < entitiesDependencies.length(); i++) { | |
queriesDependencies.add(entitiesDependencies.get(i)); | |
} | |
} | |
} | |
public Set<String> getStructure() { | |
return Collections.unmodifiableSet(structure); | |
} | |
public Set<String> getClientDependencies() { | |
return Collections.unmodifiableSet(clientDependencies); | |
} | |
public Set<String> getQueriesDependencies() { | |
return Collections.unmodifiableSet(queriesDependencies); | |
} | |
public Set<String> getServerDependencies() { | |
return Collections.unmodifiableSet(serverDependencies); | |
} | |
} | |
public static String remoteApiUri() { | |
NodeList<com.google.gwt.dom.client.Element> metas = com.google.gwt.dom.client.Document.get().getHead().getElementsByTagName("meta"); | |
for (int i = 0; i < metas.getLength(); i++) { | |
com.google.gwt.dom.client.Element meta = metas.getItem(i); | |
if ("platypus-server".equalsIgnoreCase(meta.getAttribute("name"))) { | |
return meta.getAttribute("content"); | |
} | |
} | |
return relativeUri(); | |
} | |
public static String relativeUri() { | |
String pageUrl = GWT.getHostPageBaseURL(); | |
pageUrl = pageUrl.substring(0, pageUrl.length() - 1); | |
return pageUrl; | |
} | |
public static AppClient getInstance() { | |
if (appClient == null) { | |
appClient = new AppClient(remoteApiUri() + APPLICATION_URI); | |
} | |
return appClient; | |
} | |
/** | |
* Only for tests! Don't call this method from application code! | |
* | |
* @param aClient | |
*/ | |
public static void setInstance(AppClient aClient) { | |
appClient = aClient; | |
} | |
public static boolean isSimpleModules() { | |
return simpleModules; | |
} | |
public static void setSimpleModules(boolean aValue) { | |
simpleModules = aValue; | |
} | |
public static String getSourcePath() { | |
return sourcePath; | |
} | |
public static void setSourcePath(String aValue) { | |
if (aValue != null && !aValue.isEmpty()) { | |
sourcePath = aValue; | |
if (!sourcePath.endsWith("/")) { | |
sourcePath = sourcePath + "/"; | |
} | |
if (!sourcePath.startsWith("/")) { | |
sourcePath = "/" + sourcePath; | |
} | |
} else { | |
sourcePath = "/"; | |
} | |
} | |
public SafeUri getResourceUri(final String aResourceName) { | |
return new SafeUri() { | |
@Override | |
public String asString() { | |
MatchResult htppMatch = httpPrefixPattern.exec(aResourceName); | |
if (htppMatch != null) { | |
return aResourceName; | |
} else { | |
return relativeUri() + getSourcePath() + aResourceName; | |
} | |
} | |
}; | |
} | |
public static String toFilyAppModuleId(String aRelative, String aStartPoint) { | |
Element moduleIdNormalizer = com.google.gwt.dom.client.Document.get().createDivElement(); | |
moduleIdNormalizer.setInnerHTML("<a href=\"" + aStartPoint + "/" + aRelative + "\">o</a>"); | |
String mormalizedAbsoluteModuleUrl = URL.decode(moduleIdNormalizer.getFirstChildElement().<AnchorElement> cast().getHref()); | |
String hostContextPrefix = AppClient.relativeUri() + AppClient.getSourcePath(); | |
Element hostContextNormalizer = com.google.gwt.dom.client.Document.get().createDivElement(); | |
hostContextNormalizer.setInnerHTML("<a href=\"" + hostContextPrefix + "\">o</a>"); | |
String mormalizedHostContextPrefix = URL.decode(hostContextNormalizer.getFirstChildElement().<AnchorElement> cast().getHref()); | |
return mormalizedAbsoluteModuleUrl.substring(mormalizedHostContextPrefix.length()); | |
} | |
public static Object jsLoad(String aResourceName, final JavaScriptObject onSuccess, final JavaScriptObject onFailure) throws Exception { | |
return _jsLoad(aResourceName, true, onSuccess, onFailure); | |
} | |
public static Object jsLoadText(String aResourceName, final JavaScriptObject onSuccess, final JavaScriptObject onFailure) throws Exception { | |
return _jsLoad(aResourceName, false, onSuccess, onFailure); | |
} | |
public static Object _jsLoad(final String aResourceName, boolean aBinary, final JavaScriptObject onSuccess, final JavaScriptObject onFailure) throws Exception { | |
final String callerDir = Utils.lookupCallerJsDir(); | |
SafeUri uri = AppClient.getInstance().getResourceUri(aResourceName.startsWith("./") || aResourceName.startsWith("../") ? toFilyAppModuleId(aResourceName, callerDir) : aResourceName); | |
if (onSuccess != null) { | |
AppClient.getInstance().startRequest(uri, aBinary ? ResponseType.ArrayBuffer : ResponseType.Default, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
protected void doWork(XMLHttpRequest aResult) throws Exception { | |
if (aResult.getStatus() == Response.SC_OK) { | |
String responseType = aResult.getResponseType(); | |
if (ResponseType.ArrayBuffer.getResponseTypeString().equalsIgnoreCase(responseType)) { | |
Utils.JsObject buffer = (Utils.JsObject) Utils.toJs(aResult.getResponseArrayBuffer()); | |
int length = buffer.getInteger("byteLength"); | |
buffer.setInteger("length", length); | |
Utils.executeScriptEventVoid(onSuccess, onSuccess, buffer); | |
} else { | |
Utils.executeScriptEventVoid(onSuccess, onSuccess, Utils.toJs(aResult.getResponseText())); | |
} | |
} else { | |
if (onFailure != null) { | |
Utils.executeScriptEventVoid(onFailure, onFailure, Utils.toJs(aResult.getStatusText())); | |
} | |
} | |
} | |
@Override | |
public void onFailure(XMLHttpRequest aResult) { | |
if (onFailure != null) { | |
try { | |
Utils.executeScriptEventVoid(onFailure, onFailure, | |
Utils.toJs(aResult.getStatus() != 0 ? aResult.getStatusText() : "Request has been cancelled. See browser's console for more details.")); | |
} catch (Exception ex) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
}); | |
} else { | |
XMLHttpRequest2 executed = AppClient.getInstance().syncRequest(uri.asString(), ResponseType.Default); | |
if (executed != null) { | |
if (executed.getStatus() == Response.SC_OK) { | |
String responseType = executed.getResponseType(); | |
if (ResponseType.ArrayBuffer.getResponseTypeString().equalsIgnoreCase(responseType)) { | |
Utils.JsObject buffer = (Utils.JsObject) executed.getResponseArrayBuffer(); | |
int length = buffer.getInteger("byteLength"); | |
buffer.setInteger("length", length); | |
return buffer; | |
} else { | |
return Utils.toJs(executed.getResponseText()); | |
} | |
} else { | |
throw new Exception(executed.getStatusText()); | |
} | |
} | |
} | |
return null; | |
} | |
public static JavaScriptObject jsUpload(PublishedFile aFile, String aName, final JavaScriptObject aCompleteCallback, final JavaScriptObject aProgresssCallback, | |
final JavaScriptObject aErrorCallback) { | |
if (aFile != null) { | |
Cancellable cancellable = AppClient.getInstance().startUploadRequest(aFile, aName, new Callback<ProgressEvent, String>() { | |
protected boolean completed; | |
public void onSuccess(ProgressEvent aResult) { | |
try { | |
if (!completed) { | |
if (aProgresssCallback != null) { | |
Utils.executeScriptEventVoid(aProgresssCallback, aProgresssCallback, aResult); | |
} | |
if (aResult.isComplete() && aResult.getRequest() != null) { | |
completed = true; | |
if (aCompleteCallback != null) { | |
Utils.executeScriptEventVoid(aCompleteCallback, aCompleteCallback, Utils.JsObject.parseJSON(aResult.getRequest().getResponseText())); | |
} | |
} | |
} | |
} catch (Exception ex) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
public void onFailure(String reason) { | |
if (aErrorCallback != null) { | |
try { | |
Utils.executeScriptEventVoid(aErrorCallback, aErrorCallback, Utils.toJs(reason)); | |
} catch (Exception ex) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
}); | |
return Utils.publishCancellable(cancellable); | |
} else | |
return null; | |
} | |
public Cancellable startUploadRequest(final PublishedFile aFile, String aName, final Callback<ProgressEvent, String> aCallback) { | |
final XMLHttpRequest2 req = XMLHttpRequest.create().<XMLHttpRequest2> cast(); | |
req.open("post", apiUrl); | |
final ProgressHandler handler = new ProgressHandlerAdapter() { | |
@Override | |
public void onProgress(ProgressEvent aEvent) { | |
try { | |
if (aCallback != null) | |
aCallback.onSuccess(aEvent); | |
} catch (Exception ex) { | |
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
public void onLoadEnd(XMLHttpRequest xhr) { | |
try { | |
if (aCallback != null) | |
aCallback.onSuccess(ProgressEvent.create(aFile.getSize(), aFile.getSize(), null)); | |
} catch (Exception ex) { | |
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
}; | |
@Override | |
public void onTimeOut(XMLHttpRequest xhr) { | |
if (aCallback != null) { | |
try { | |
aCallback.onFailure("timeout"); | |
} catch (Exception ex) { | |
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
@Override | |
public void onAbort(XMLHttpRequest xhr) { | |
if (aCallback != null) { | |
try { | |
aCallback.onFailure("aborted"); | |
} catch (Exception ex) { | |
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
@Override | |
public void onError(XMLHttpRequest xhr) { | |
if (aCallback != null) { | |
try { | |
aCallback.onFailure(xhr.getStatusText()); | |
} catch (Exception ex) { | |
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
}; | |
if (req.getUpload() != null) { | |
req.getUpload().setOnProgress(handler); | |
req.getUpload().setOnLoadEnd(handler); | |
req.getUpload().setOnAbort(handler); | |
req.getUpload().setOnError(handler); | |
req.getUpload().setOnTimeOut(handler); | |
} | |
FormData fd = FormData.create(); | |
fd.append(aFile.getName(), aFile, aName); | |
req.overrideMimeType("multipart/form-data"); | |
// Must set the onreadystatechange handler before calling send(). | |
req.setOnReadyStateChange(new ReadyStateChangeHandler() { | |
@Override | |
public void onReadyStateChange(XMLHttpRequest xhr) { | |
if (xhr.getReadyState() == XMLHttpRequest.DONE) { | |
xhr.clearOnReadyStateChange(); | |
if (xhr.getStatus() == Response.SC_OK) { | |
try { | |
if (aCallback != null) | |
aCallback.onSuccess(ProgressEvent.create(aFile.getSize(), aFile.getSize(), xhr)); | |
} catch (Exception ex) { | |
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} else { | |
if (xhr.getStatus() == 0) | |
handler.onAbort(xhr); | |
else | |
handler.onError(xhr); | |
} | |
} | |
} | |
}); | |
req.send(fd); | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
req.abort(); | |
} | |
}; | |
} | |
public Cancellable submitForm(String aAction, RequestBuilder.Method aMethod, String aContentType, Map<String, String> aFormData, final Callback<XMLHttpRequest, XMLHttpRequest> aCallback) { | |
final XMLHttpRequest req = XMLHttpRequest.create().cast(); | |
String urlPath = aAction != null ? aAction : ""; | |
List<String> parameters = new ArrayList<String>(); | |
for (String paramName : aFormData.keySet()) { | |
parameters.add(param(paramName, aFormData.get(paramName))); | |
} | |
String paramsData = params(parameters.toArray(new String[] {})); | |
if(aMethod != RequestBuilder.POST){ | |
urlPath += "?" + paramsData; | |
} | |
req.open(aMethod.toString(), urlPath); | |
req.setRequestHeader("Content-Type", aContentType); | |
req.setOnReadyStateChange(new ReadyStateChangeHandler() { | |
@Override | |
public void onReadyStateChange(final XMLHttpRequest xhr) { | |
if (xhr.getReadyState() == XMLHttpRequest.DONE) { | |
xhr.clearOnReadyStateChange(); | |
if (aCallback != null) { | |
try { | |
if (xhr.getStatus() == Response.SC_OK) { | |
aCallback.onSuccess(xhr); | |
} else { | |
aCallback.onFailure(xhr); | |
} | |
} catch (Exception ex) { | |
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
} | |
}); | |
if(aMethod == RequestBuilder.POST){ | |
req.send(paramsData); | |
} else{ | |
req.send(); | |
} | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
req.abort(); | |
} | |
}; | |
} | |
public static String param(String aName, String aValue) { | |
return aName + "=" + (aValue != null ? URL.encodePathSegment(aValue) : ""); | |
} | |
public static String params(String... aParams) { | |
String res = ""; | |
for (int i = 0; i < aParams.length; i++) { | |
if (aParams[i] != null && !aParams[i].isEmpty()) { | |
if (!res.isEmpty()) { | |
res += "&"; | |
} | |
res += aParams[i]; | |
} | |
} | |
return res; | |
} | |
public AppClient(String aApiUrl) { | |
super(); | |
apiUrl = aApiUrl; | |
} | |
public Document getModelDocument(String aModuleName) { | |
ModuleStructure structure = modulesStructures.get(aModuleName); | |
for (String part : structure.getStructure()) { | |
if (part.toLowerCase().endsWith(".model")) { | |
return documents.get(part); | |
} | |
} | |
return null; | |
} | |
public Document getFormDocument(String aModuleName) { | |
ModuleStructure structure = modulesStructures.get(aModuleName); | |
for (String part : structure.getStructure()) { | |
if (part.toLowerCase().endsWith(".layout")) { | |
return documents.get(part); | |
} | |
} | |
return null; | |
} | |
private String params(Parameters parameters) { | |
String[] res = new String[parameters.getParametersCount()]; | |
for (int i = 0; i < parameters.getParametersCount(); i++) { | |
Parameter p = parameters.get(i + 1);// parameters and fields are | |
// 1-based | |
String sv = Utils.jsonStringify(p.getJsValue()); | |
res[i] = param(p.getName(), sv); | |
} | |
return params(res); | |
} | |
public JavaScriptObject jsLogout(final JavaScriptObject onSuccess, final JavaScriptObject onFailure) throws Exception { | |
return Utils.publishCancellable(requestLogout(new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
protected void doWork(XMLHttpRequest aResult) throws Exception { | |
Utils.invokeJsFunction(onSuccess); | |
} | |
@Override | |
public void onFailure(XMLHttpRequest reason) { | |
try { | |
Utils.executeScriptEventVoid(onFailure, onFailure, Utils.toJs(reason.getStatusText())); | |
} catch (Exception ex) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
})); | |
} | |
public Cancellable requestLogout(final Callback<XMLHttpRequest, XMLHttpRequest> aCallback) throws Exception { | |
String query = param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqLogout)); | |
return startApiRequest(null, query, null, RequestBuilder.GET, null, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
protected void doWork(XMLHttpRequest aResult) throws Exception { | |
principal = null; | |
aCallback.onSuccess(aResult); | |
} | |
@Override | |
public void onFailure(XMLHttpRequest reason) { | |
aCallback.onFailure(reason); | |
} | |
}); | |
} | |
public Cancellable startApiRequest(String aUrlPrefix, final String aUrlQuery, String aBody, RequestBuilder.Method aMethod, String aContentType, Callback<XMLHttpRequest, XMLHttpRequest> aCallback) | |
throws Exception { | |
String url = apiUrl + (aUrlPrefix != null ? aUrlPrefix : "") + (aUrlQuery != null ? "?" + aUrlQuery : ""); | |
final XMLHttpRequest req = XMLHttpRequest.create(); | |
req.open(aMethod.toString(), url); | |
if (aContentType != null && !aContentType.isEmpty()) { | |
req.setRequestHeader("Content-Type", aContentType); | |
} | |
interceptRequest(req); | |
req.setRequestHeader("Pragma", "no-cache"); | |
return startRequest(req, aBody, aCallback); | |
} | |
public Cancellable startRequest(SafeUri aUri, ResponseType aResponseType, Callback<XMLHttpRequest, XMLHttpRequest> aCallback) throws Exception { | |
final XMLHttpRequest req = XMLHttpRequest.create(); | |
req.open(RequestBuilder.GET.toString(), aUri.asString()); | |
interceptRequest(req); | |
if (aResponseType != null && aResponseType != ResponseType.Default) | |
req.setResponseType(aResponseType); | |
req.setRequestHeader("Pragma", "no-cache"); | |
return startRequest(req, null, aCallback); | |
} | |
public Cancellable startRequest(SafeUri aUri, Callback<XMLHttpRequest, XMLHttpRequest> aCallback) throws Exception { | |
return startRequest(aUri, ResponseType.Default, aCallback); | |
} | |
public Cancellable startRequest(final XMLHttpRequest req, String aBody, final Callback<XMLHttpRequest, XMLHttpRequest> aCallback) throws Exception { | |
// Must set the onreadystatechange handler before calling send(). | |
req.setOnReadyStateChange(new ReadyStateChangeHandler() { | |
public void onReadyStateChange(XMLHttpRequest xhr) { | |
if (xhr.getReadyState() == XMLHttpRequest.DONE) { | |
xhr.clearOnReadyStateChange(); | |
/* | |
* We cannot use cancel here because it would clear the | |
* contents of the JavaScript XmlHttpRequest object so we | |
* manually null out our reference to the JavaScriptObject | |
*/ | |
String errorMsg = XMLHttpRequest2.getBrowserSpecificFailure(xhr); | |
if (errorMsg != null) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, errorMsg); | |
try { | |
if (aCallback != null) | |
aCallback.onFailure(xhr); | |
} catch (Exception ex) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} else { | |
try { | |
if (xhr.getStatus() == Response.SC_OK) { | |
if (aCallback != null) | |
aCallback.onSuccess(xhr); | |
} else { | |
if (aCallback != null) | |
aCallback.onFailure(xhr); | |
} | |
} catch (Exception ex) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
} | |
}); | |
if (aBody != null && !aBody.isEmpty()) | |
req.send(aBody); | |
else | |
req.send(); | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
req.clearOnReadyStateChange(); | |
req.abort(); | |
} | |
}; | |
} | |
public void startDownloadRequest(String aUrlPrefix, final int aRequestType, Map<String, String> aParams, RequestBuilder.Method aMethod) throws Exception { | |
final Frame frame = new Frame(); | |
frame.setVisible(false); | |
frame.addLoadHandler(new LoadHandler() { | |
@Override | |
public void onLoad(LoadEvent event) { | |
Timer timer = new Timer() { | |
@Override | |
public void run() { | |
frame.removeFromParent(); | |
} | |
}; | |
timer.schedule(2000); | |
} | |
}); | |
String query = ""; | |
for (Map.Entry<String, String> ent : aParams.entrySet()) { | |
query += param(ent.getKey(), ent.getValue()) + "&"; | |
} | |
query += param(PlatypusHttpRequestParams.TYPE, String.valueOf(aRequestType)); | |
frame.setUrl(apiUrl + aUrlPrefix + "?" + query); | |
RootPanel.get().add(frame); | |
} | |
public XMLHttpRequest2 syncRequest(String aUrl, ResponseType aResponseType) throws Exception { | |
final XMLHttpRequest2 req = syncRequest(aUrl, aResponseType, null, RequestBuilder.GET); | |
if (req.getStatus() == Response.SC_OK) | |
return req; | |
else | |
throw new Exception(req.getStatus() + " " + req.getStatusText()); | |
} | |
public XMLHttpRequest2 syncApiRequest(String aUrlPrefix, final String aUrlQuery, ResponseType aResponseType) throws Exception { | |
String url = apiUrl + (aUrlPrefix != null ? aUrlPrefix : "") + "?" + aUrlQuery; | |
final XMLHttpRequest2 req = syncRequest(url, aResponseType, null, RequestBuilder.GET); | |
if (req.getStatus() == Response.SC_OK) | |
return req; | |
else | |
throw new Exception(req.getStatus() + " " + req.getStatusText()); | |
} | |
public XMLHttpRequest2 syncRequest(String aUrl, ResponseType aResponseType, String aBody, RequestBuilder.Method aMethod) throws Exception { | |
final XMLHttpRequest2 req = XMLHttpRequest.create().<XMLHttpRequest2> cast(); | |
aUrl = Loader.URL_QUERY_PROCESSOR.process(aUrl); | |
req.open(aMethod.toString(), aUrl, false); | |
interceptRequest(req); | |
/* | |
* Since W3C standard about sync XmlHttpRequest and response type. if | |
* (aResponseType != null && aResponseType != ResponseType.Default) | |
* req.setResponseType(aResponseType); | |
*/ | |
req.setRequestHeader("Pragma", "no-cache"); | |
if (aBody != null) | |
req.send(aBody); | |
else | |
req.send(); | |
if (req.getStatus() == Response.SC_OK) | |
return req; | |
else | |
throw new Exception(req.getStatus() + " " + req.getStatusText()); | |
} | |
protected void interceptRequest(XMLHttpRequest req) { | |
// No-op here. Some implementation is in the tests. | |
} | |
public Cancellable requestCommit(final JavaScriptObject changeLog, final Callback<Void, String> aCallback) throws Exception { | |
String query = param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqCommit)); | |
return startApiRequest(null, query, Utils.JsObject.writeJSON(changeLog), RequestBuilder.POST, "application/json; charset=utf-8", new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
public void doWork(XMLHttpRequest aResponse) throws Exception { | |
Logger.getLogger(AppClient.class.getName()).log(Level.INFO, "Commit succeded: " + aResponse.getStatus() + " " + aResponse.getStatusText()); | |
if (aCallback != null) | |
aCallback.onSuccess(null); | |
} | |
@Override | |
public void onFailure(XMLHttpRequest aResponse) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.INFO, "Commit failed: " + aResponse.getStatus() + " " + aResponse.getStatusText()); | |
if (aCallback != null) | |
aCallback.onFailure(aResponse.getStatusText()); | |
} | |
}); | |
} | |
public void jsLoggedInUser(final JavaScriptObject onSuccess, final JavaScriptObject onFailure) throws Exception { | |
requestLoggedInUser(new CallbackAdapter<String, String>() { | |
@Override | |
protected void doWork(String aResult) throws Exception { | |
if (onSuccess != null) { | |
onSuccess.<Utils.JsObject> cast().call(null, Utils.toJs(aResult)); | |
} | |
} | |
@Override | |
public void onFailure(String reason) { | |
if (onFailure != null) { | |
onFailure.<Utils.JsObject> cast().call(null, Utils.toJs(reason)); | |
} | |
} | |
}); | |
} | |
public void requestLoggedInUser(final Callback<String, String> aCallback) throws Exception { | |
if (principal == null) { | |
String query = param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqCredential)); | |
startApiRequest(null, query, "", RequestBuilder.GET, null, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
protected void doWork(XMLHttpRequest aResponse) throws Exception { | |
if (isJsonResponse(aResponse)) { | |
String respText = aResponse.getResponseText(); | |
Object oResult = respText != null && !respText.isEmpty() ? Utils.toJava(Utils.jsonParse(respText)) : null; | |
assert oResult == null || oResult instanceof JavaScriptObject : "Credential request expects null or JavaScriptObject value as a response."; | |
JavaScriptObject jsObject = (JavaScriptObject) oResult; | |
Object oUserName = jsObject.<Utils.JsObject> cast().getJava("userName"); | |
assert oUserName == null || oUserName instanceof String : "Credential request expects null or String value as a user name."; | |
principal = (String) oUserName; | |
if (principal == null || principal.isEmpty()) | |
principal = "anonymous" + String.valueOf(IdGenerator.genId()); | |
if (aCallback != null) { | |
aCallback.onSuccess(principal); | |
} | |
} else { | |
if (aCallback != null) { | |
aCallback.onFailure(aResponse.getResponseText()); | |
} | |
} | |
} | |
@Override | |
public void onFailure(XMLHttpRequest reason) { | |
principal = "anonymous" + String.valueOf(IdGenerator.genId()); | |
if (aCallback != null) | |
aCallback.onFailure(reason.getStatus() + " : " + reason.getStatusText()); | |
} | |
}); | |
} else { | |
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { | |
@Override | |
public void execute() { | |
if (aCallback != null) { | |
aCallback.onSuccess(principal); | |
} | |
} | |
}); | |
} | |
} | |
public ModuleStructure getModuleStructure(String aModuleName) { | |
return modulesStructures.get(aModuleName); | |
} | |
public ModuleStructure putModuleStructure(String aModuleName, ModuleStructure aStructure) { | |
return modulesStructures.put(aModuleName, aStructure); | |
} | |
private native static void checkModulesIndex(AppClient aClient)/*-{ | |
if ($wnd.define) { | |
var index = $wnd.define['modules-index']; | |
for ( var fileName in index) { | |
var structure = index[fileName]; | |
var mstructure = @com.eas.client.AppClient.ModuleStructure::new(Ljava/lang/String;Lcom/google/gwt/core/client/JsArrayString;Lcom/google/gwt/core/client/JsArrayString;Lcom/google/gwt/core/client/JsArrayString;Lcom/google/gwt/core/client/JsArrayString;)(fileName, structure.prefetched, structure['global-deps'], structure.rpc, structure.entities); | |
var defaultModuleName = fileName; | |
if (defaultModuleName.endsWith('.js')) { | |
defaultModuleName = defaultModuleName.substring(0, defaultModuleName.length - 3); | |
} | |
aClient.@com.eas.client.AppClient::putModuleStructure(Ljava/lang/String;Lcom/eas/client/AppClient$ModuleStructure;)(defaultModuleName, mstructure); | |
if (structure.modules) { | |
for ( var i = 0; i < structure.modules.length; i++) { | |
aClient.@com.eas.client.AppClient::putModuleStructure(Ljava/lang/String;Lcom/eas/client/AppClient$ModuleStructure;)(structure.modules[i], mstructure); | |
} | |
} | |
} | |
$wnd.define['modules-index'] = {}; | |
} | |
}-*/; | |
public Cancellable requestModuleStructure(final String aModuleName, final Callback<ModuleStructure, XMLHttpRequest> aCallback) throws Exception { | |
checkModulesIndex(this); | |
if (modulesStructures.containsKey(aModuleName)) { | |
if (aCallback != null) { | |
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { | |
@Override | |
public void execute() { | |
aCallback.onSuccess(modulesStructures.get(aModuleName)); | |
} | |
}); | |
} | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
} | |
}; | |
} else if (simpleModules) { | |
if (aCallback != null) { | |
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { | |
@Override | |
public void execute() { | |
String fakeRelativeFileName = aModuleName; | |
if (!fakeRelativeFileName.toLowerCase().endsWith(".js")) { | |
fakeRelativeFileName = fakeRelativeFileName + ".js"; | |
} | |
ModuleStructure s = new ModuleStructure(fakeRelativeFileName); | |
aCallback.onSuccess(s); | |
} | |
}); | |
} | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
} | |
}; | |
} else { | |
String query = params(param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqModuleStructure)), param(PlatypusHttpRequestParams.MODULE_NAME, aModuleName)); | |
query = Loader.URL_QUERY_PROCESSOR.process(query); | |
return startApiRequest(null, query, "", RequestBuilder.GET, null, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
public void doWork(XMLHttpRequest aResponse) throws Exception { | |
if (isJsonResponse(aResponse)) { | |
// Some post processing | |
String text = aResponse.getResponseText(); | |
JavaScriptObject _doc = text != null && !text.isEmpty() ? Utils.JsObject.parseJSON(text) : null; | |
Utils.JsObject doc = _doc.cast(); | |
// | |
Set<String> structure = new HashSet<String>(); | |
Set<String> clientDependencies = new HashSet<String>(); | |
Set<String> queryDependencies = new HashSet<String>(); | |
Set<String> serverModuleDependencies = new HashSet<String>(); | |
Utils.JsObject jsStructure = doc.getJs("structure").cast(); | |
Utils.JsObject jsClientDependencies = doc.getJs("clientDependencies").cast(); | |
Utils.JsObject jsQueryDependencies = doc.getJs("queryDependencies").cast(); | |
Utils.JsObject jsServerDependencies = doc.getJs("serverDependencies").cast(); | |
for (int i = 0; i < jsStructure.length(); i++) { | |
structure.add(jsStructure.getStringSlot(i)); | |
} | |
for (int i = 0; i < jsClientDependencies.length(); i++) { | |
clientDependencies.add(jsClientDependencies.getStringSlot(i)); | |
} | |
for (int i = 0; i < jsQueryDependencies.length(); i++) { | |
queryDependencies.add(jsQueryDependencies.getStringSlot(i)); | |
} | |
for (int i = 0; i < jsServerDependencies.length(); i++) { | |
serverModuleDependencies.add(jsServerDependencies.getStringSlot(i)); | |
} | |
ModuleStructure moduleStructure = new ModuleStructure(structure, clientDependencies, serverModuleDependencies, queryDependencies); | |
modulesStructures.put(aModuleName, moduleStructure); | |
if (aCallback != null) { | |
aCallback.onSuccess(moduleStructure); | |
} | |
} else { | |
if (aCallback != null) | |
aCallback.onFailure(aResponse); | |
} | |
} | |
@Override | |
public void onFailure(XMLHttpRequest reason) { | |
if (aCallback != null) | |
aCallback.onFailure(reason); | |
} | |
}); | |
} | |
} | |
public Cancellable requestDocument(final String aResourceName, final Callback<Document, XMLHttpRequest> aCallback) throws Exception { | |
if (documents.containsKey(aResourceName)) { | |
final Document doc = documents.get(aResourceName); | |
// doc may be null, because of application elements without a | |
// xml-dom, plain scripts for example. | |
if (aCallback != null) { | |
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { | |
@Override | |
public void execute() { | |
aCallback.onSuccess(doc); | |
} | |
}); | |
} | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
// no op here because of no request have been sent | |
} | |
}; | |
} else { | |
SafeUri documentUri = new SafeUri() { | |
@Override | |
public String asString() { | |
return checkedCacheBust(relativeUri() + getSourcePath() + aResourceName); | |
} | |
}; | |
return startRequest(documentUri, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
public void doWork(XMLHttpRequest aResponse) throws Exception { | |
// Some post processing | |
String text = aResponse.getResponseText(); | |
Document doc = text != null && !text.isEmpty() ? XMLParser.parse(text) : null; | |
documents.put(aResourceName, doc); | |
// | |
if (aCallback != null) | |
aCallback.onSuccess(doc); | |
} | |
@Override | |
public void onFailure(XMLHttpRequest reason) { | |
if (aCallback != null) | |
aCallback.onFailure(reason); | |
} | |
}); | |
} | |
} | |
public Cancellable requestServerModule(final String aModuleName, final Callback<Void, String> aCallback) throws Exception { | |
if (isServerModule(aModuleName)) { | |
if (aCallback != null) { | |
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { | |
@Override | |
public void execute() { | |
aCallback.onSuccess(null); | |
} | |
}); | |
} | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
// no op here because of no request have been sent | |
} | |
}; | |
} else { | |
String query = params(param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqCreateServerModule)), param(PlatypusHttpRequestParams.MODULE_NAME, aModuleName)); | |
return startApiRequest(null, query, "", RequestBuilder.GET, null, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
public void doWork(XMLHttpRequest aResponse) throws Exception { | |
// Some post processing | |
if (isJsonResponse(aResponse)) { | |
addServerModule(aModuleName, aResponse.getResponseText()); | |
if (aCallback != null) { | |
aCallback.onSuccess(null); | |
} | |
} else { | |
onFailure(aResponse); | |
} | |
} | |
@Override | |
public void onFailure(XMLHttpRequest aResponse) { | |
if (aCallback != null) { | |
String responseText = aResponse.getResponseText(); | |
aCallback.onFailure(responseText != null && !responseText.isEmpty() ? responseText : aResponse.getStatusText()); | |
} | |
} | |
}); | |
} | |
} | |
public Object getServerModule(String aModuleName) { | |
return serverModules.get(aModuleName); | |
} | |
public void addServerModule(String aModuleName, String aStructure) throws Exception { | |
serverModules.put(aModuleName, Utils.jsonParse(aStructure)); | |
} | |
public boolean isServerModule(String aModuleName) throws Exception { | |
return serverModules.containsKey(aModuleName); | |
} | |
public static native JavaScriptObject createReport(JavaScriptObject Report, String reportLocation)/*-{ | |
return new Report(reportLocation); | |
}-*/; | |
public boolean isCacheBustEnabled() { | |
return cacheBustEnabled; | |
} | |
public void setCacheBustEnabled(boolean aValue) { | |
cacheBustEnabled = aValue; | |
} | |
public Object requestServerMethodExecution(final String aModuleName, final String aMethodName, final JsArrayString aParams, final JavaScriptObject onSuccess, final JavaScriptObject onFailure, | |
final JavaScriptObject aReportConstructor) throws Exception { | |
String[] convertedParams = new String[aParams.length()]; | |
for (int i = 0; i < aParams.length(); i++) | |
convertedParams[i] = param(PlatypusHttpRequestParams.PARAMS_ARRAY, aParams.get(i)); | |
String query = params(param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqExecuteServerModuleMethod)), param(PlatypusHttpRequestParams.MODULE_NAME, aModuleName), | |
param(PlatypusHttpRequestParams.METHOD_NAME, aMethodName), params(convertedParams)); | |
if (onSuccess != null) { | |
startApiRequest(null, null, query, RequestBuilder.POST, "application/x-www-form-urlencoded; charset=utf-8", new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
public void doWork(XMLHttpRequest aResponse) throws Exception { | |
if (isJsonResponse(aResponse)) { | |
Utils.executeScriptEventVoid(onSuccess, onSuccess, Utils.toJs(aResponse.getResponseText())); | |
// WARNING!!!Don't edit to Utils.jsonParse! | |
// It is parsed in high-level js-code. | |
} else if (isReportResponse(aResponse)) { | |
Utils.executeScriptEventVoid(onSuccess, onSuccess, createReport(aReportConstructor, aResponse.getResponseText())); | |
} else { | |
Utils.executeScriptEventVoid(onSuccess, onSuccess, Utils.toJs(aResponse.getResponseText())); | |
} | |
} | |
@Override | |
public void onFailure(XMLHttpRequest aResponse) { | |
if (onFailure != null) { | |
try { | |
String responseText = aResponse.getResponseText(); | |
if (isJsonResponse(aResponse)) { | |
Utils.executeScriptEventVoid(onFailure, onFailure, Utils.jsonParse(responseText)); | |
} else { | |
Utils.executeScriptEventVoid(onFailure, onFailure, Utils.toJs(responseText != null && !responseText.isEmpty() ? responseText : aResponse.getStatusText())); | |
} | |
} catch (Exception ex) { | |
Logger.getLogger(AppClient.class.getName()).log(Level.SEVERE, null, ex); | |
} | |
} | |
} | |
}); | |
return null; | |
} else { | |
XMLHttpRequest2 executed = syncApiRequest(null, query, ResponseType.Default); | |
if (executed != null) { | |
if (executed.getStatus() == Response.SC_OK) { | |
String responseType = executed.getResponseHeader("content-type"); | |
if (responseType != null) { | |
if (isJsonResponse(executed)) { | |
// WARNING!!!Don't edit to Utils.jsonParse! | |
// It is parsed in high-level js-code. | |
return Utils.toJs(executed.getResponseText()); | |
} else if (responseType.toLowerCase().contains(REPORT_LOCATION_CONTENT_TYPE)) { | |
return createReport(aReportConstructor, executed.getResponseText()); | |
} else { | |
return Utils.toJs(executed.getResponseText()); | |
} | |
} else { | |
return Utils.toJs(executed.getResponseText()); | |
} | |
} else { | |
String responseText = executed.getResponseText(); | |
throw new Exception(responseText != null && !responseText.isEmpty() ? responseText : executed.getStatusText()); | |
} | |
} else { | |
return null; | |
} | |
} | |
} | |
public Cancellable requestAppQuery(final String queryName, final Callback<Query, String> aCallback) throws Exception { | |
final Query alreadyQuery = queries.get(queryName); | |
if (alreadyQuery != null) { | |
if (aCallback != null) { | |
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { | |
@Override | |
public void execute() { | |
aCallback.onSuccess(alreadyQuery); | |
} | |
}); | |
} | |
return new Cancellable() { | |
@Override | |
public void cancel() { | |
// no op here because of no request have been sent | |
} | |
}; | |
} else { | |
String urlQuery = params(param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqAppQuery)), param(PlatypusHttpRequestParams.QUERY_ID, queryName)); | |
return startApiRequest(null, urlQuery, "", RequestBuilder.GET, null, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
public void doWork(XMLHttpRequest aResponse) throws Exception { | |
if (isJsonResponse(aResponse)) { | |
// Some post processing | |
Query query = readQuery(aResponse); | |
query.setClient(AppClient.this); | |
// | |
queries.put(queryName, query); | |
if (aCallback != null) | |
aCallback.onSuccess(query); | |
} else { | |
if (aCallback != null) { | |
aCallback.onFailure(aResponse.getResponseText()); | |
} | |
} | |
} | |
private Query readQuery(XMLHttpRequest aResponse) throws Exception { | |
return QueryJSONReader.read(Utils.JsObject.parseJSON(aResponse.getResponseText())); | |
} | |
@Override | |
public void onFailure(XMLHttpRequest aResponse) { | |
if (aCallback != null) { | |
aCallback.onFailure(aResponse.getStatusText()); | |
} | |
} | |
}); | |
} | |
} | |
public Query getCachedAppQuery(String aQueryId) { | |
Query query = queries.get(aQueryId); | |
if (query != null) { | |
AppClient client = query.getClient(); | |
query = query.copy(); | |
query.setClient(client); | |
} | |
return query; | |
} | |
public Cancellable requestData(String aQueryName, Parameters aParams, final Fields aExpectedFields, final Callback<JavaScriptObject, String> aCallback) throws Exception { | |
String query = params(param(PlatypusHttpRequestParams.TYPE, String.valueOf(Requests.rqExecuteQuery)), param(PlatypusHttpRequestParams.QUERY_ID, aQueryName), params(aParams)); | |
return startApiRequest(null, query, "", RequestBuilder.GET, null, new CallbackAdapter<XMLHttpRequest, XMLHttpRequest>() { | |
@Override | |
public void doWork(XMLHttpRequest aResponse) throws Exception { | |
if (isJsonResponse(aResponse)) { | |
JavaScriptObject parsed = Utils.JsObject.parseJSONDateReviver(aResponse.getResponseText()); | |
if (aCallback != null) | |
aCallback.onSuccess(parsed); | |
} else { | |
if (aCallback != null) | |
aCallback.onFailure(aResponse.getResponseText()); | |
} | |
} | |
@Override | |
public void onFailure(XMLHttpRequest aResponse) { | |
if (aCallback != null) { | |
int status = aResponse.getStatus(); | |
String statusText = aResponse.getStatusText(); | |
if (statusText == null || statusText.isEmpty()) | |
statusText = null; | |
if (status == 0) | |
Logger.getLogger(AppClient.class.getName()).log(Level.WARNING, "Data recieving is aborted"); | |
aCallback.onFailure(statusText); | |
} | |
} | |
}); | |
} | |
public String checkedCacheBust(String aUrl) { | |
return cacheBustEnabled ? aUrl + "?" + PlatypusHttpRequestParams.CACHE_BUSTER + "=" + IdGenerator.genId() : aUrl; | |
} | |
private boolean isJsonResponse(XMLHttpRequest aResponse) { | |
String responseType = aResponse.getResponseHeader("content-type"); | |
if (responseType != null) { | |
responseType = responseType.toLowerCase(); | |
return responseType.contains("application/json") || responseType.contains("application/javascript") || responseType.contains("text/json") || responseType.contains("text/javascript"); | |
} else { | |
return false; | |
} | |
} | |
private boolean isReportResponse(XMLHttpRequest aResponse) { | |
String responseType = aResponse.getResponseHeader("content-type"); | |
if (responseType != null) { | |
responseType = responseType.toLowerCase(); | |
return responseType.contains(REPORT_LOCATION_CONTENT_TYPE); | |
} else { | |
return false; | |
} | |
} | |
} |