Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jboss.resteasy.jsapi.JSAPIWriter Maven / Gradle / Ivy
package org.jboss.resteasy.jsapi;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.zip.GZIPOutputStream;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jboss.resteasy.jsapi.i18n.LogMessages;
import org.jboss.resteasy.jsapi.i18n.Messages;
import org.jboss.resteasy.util.PathHelper;
/**
* @author Stéphane Épardaud
*/
public class JSAPIWriter {
private static final long serialVersionUID = -1985015444704126795L;
public void writeJavaScript(String base, HttpServletRequest req, HttpServletResponse resp,
Map serviceRegistries) throws IOException {
LogMessages.LOGGER.debug(Messages.MESSAGES.startResteasyClient());
// RESTEASY-776
// before writing generated javascript, we generate Etag and compare it with client request.
// If nothing changed, we send back 304 Not Modified for client browser to use cached js.
String ifNoneMatch = req.getHeader("If-None-Match");
String etag = generateEtag(serviceRegistries);
resp.setHeader("Etag", etag);
if (ifNoneMatch != null && ifNoneMatch.equals(etag)) {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
for (Map.Entry entry : serviceRegistries.entrySet()) {
String uri = base;
if (entry.getKey() != null) {
uri = resolveDoubleSlash(uri, entry.getKey(), true);
}
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(new BufferedWriter(stringWriter));
writeJavaScript(uri, writer, entry.getValue());
writer.flush();
writer.close();
if (clientIsGzipSupported(req)) {
ByteArrayOutputStream compressedContent = new ByteArrayOutputStream();
GZIPOutputStream gzipstream = new GZIPOutputStream(compressedContent);
gzipstream.write(stringWriter.toString().getBytes());
gzipstream.finish();
// get the compressed content
byte[] compressedBytes = compressedContent.toByteArray();
// set appropriate HTTP headers
resp.setContentLength(compressedBytes.length);
resp.addHeader("Content-Encoding", "gzip");
ServletOutputStream output = resp.getOutputStream();
output.write(compressedBytes);
output.flush();
output.close();
} else {
ServletOutputStream output = resp.getOutputStream();
byte[] bytes = stringWriter.toString().getBytes();
resp.setContentLength(bytes.length);
output.write(bytes);
output.flush();
output.close();
}
}
}
private boolean clientIsGzipSupported(HttpServletRequest req) {
String encoding = req.getHeader("Accept-Encoding");
return encoding != null && encoding.contains("gzip");
}
public void writeJavaScript(String uri, PrintWriter writer,
ServiceRegistry serviceRegistry) throws IOException {
copyResource("/resteasy-client.js", writer);
LogMessages.LOGGER.debug(Messages.MESSAGES.startJaxRsApi());
LogMessages.LOGGER.debug(Messages.MESSAGES.restApiUrl(uri));
writer.println("REST.apiURL = '" + uri + "';");
Set declaredPrefixes = new HashSet();
printService(writer, serviceRegistry, declaredPrefixes, uri);
}
private String generateEtag(Map serviceRegistries) {
StringBuilder etagBuilder = new StringBuilder();
for (Map.Entry entry : serviceRegistries.entrySet()) {
if (entry.getKey() != null)
etagBuilder.append(entry.getKey()).append(':');
generateEtag(entry.getValue(), etagBuilder);
}
return String.valueOf(Math.abs(etagBuilder.toString().hashCode()));
}
private void generateEtag(ServiceRegistry serviceRegistry, StringBuilder etagBuilder) {
for (MethodMetaData methodMetaData : serviceRegistry.getMethodMetaData()) {
etagBuilder.append(methodMetaData.hashCode());
for (ServiceRegistry subService : serviceRegistry.getLocators()) {
generateEtag(subService, etagBuilder);
}
}
}
private void printService(PrintWriter writer,
ServiceRegistry serviceRegistry, Set declaredPrefixes, String uri) {
for (MethodMetaData methodMetaData : serviceRegistry.getMethodMetaData()) {
LogMessages.LOGGER.debug(Messages.MESSAGES.path(methodMetaData.getUri()));
LogMessages.LOGGER.debug(Messages.MESSAGES.invoker(methodMetaData.getInvoker()));
String declaringPrefix = methodMetaData.getFunctionPrefix(); // TODO Add prefix path segment
declarePrefix(writer, declaringPrefix, declaredPrefixes);
for (String httpMethod : methodMetaData.getHttpMethods()) {
print(writer, httpMethod, methodMetaData, uri);
}
}
for (ServiceRegistry subService : serviceRegistry.getLocators())
printService(writer, subService, declaredPrefixes, uri);
}
private void declarePrefix(PrintWriter writer, String declaringPrefix, Set declaredPrefixes) {
if (declaredPrefixes.add(declaringPrefix)) {
int lastDot = declaringPrefix.lastIndexOf(".");
if (lastDot == -1)
writer.println("var " + declaringPrefix + " = {};");
else {
declarePrefix(writer, declaringPrefix.substring(0, lastDot), declaredPrefixes);
writer.println(declaringPrefix + " = {};");
}
}
}
private void copyResource(String name, PrintWriter writer)
throws IOException {
Reader reader = new InputStreamReader(getClass()
.getResourceAsStream(name));
char[] array = new char[1024];
int read;
while ((read = reader.read(array)) >= 0) {
writer.write(array, 0, read);
}
reader.close();
}
private void print(PrintWriter writer, String httpMethod,
MethodMetaData methodMetaData, String uri) {
String methodUri = methodMetaData.getUri();
writer.println("// " + httpMethod + " " + methodUri);
writer
.println(methodMetaData.getFunctionName() + " = function(_params){");
writer.println(" var params = _params ? _params : {};");
writer.println(" var request = new REST.Request();");
writer.println(" request.setMethod('" + httpMethod + "');");
writer
.println(" var uri = params.$apiURL ? params.$apiURL : REST.apiURL;");
if (methodUri.contains("{")) {
printURIParams(methodUri, writer);
} else {
String resolvedMethodUri = resolveDoubleSlash(uri, methodUri, false);
writer.println(" uri += '" + resolvedMethodUri + "';");
}
printOtherParams(methodMetaData, writer);
writer.println(" request.setURI(uri);");
writer.println(" if(params.$username && params.$password)");
writer
.println(" request.setCredentials(params.$username, params.$password);");
writer.println(" if(params.$accepts)");
writer.println(" request.setAccepts(params.$accepts);");
if (methodMetaData.getWants() != null) {
writer.println(" else");
writer.println(" request.setAccepts('" + methodMetaData.getWants()
+ "');");
}
writer.println("if (REST.antiBrowserCache == true) {");
writer.println(" request.addQueryParameter('resteasy_jsapi_anti_cache', (new Date().getTime()));");
writer.println(" var cached_obj = REST._get_cache_signature(REST._generate_cache_signature(uri));");
writer.println(
" if (cached_obj != null) { request.addHeader('If-Modified-Since', cached_obj[1]['Last-Modified']); request.addHeader('If-None-Match', cached_obj[1]['Etag']);}");
writer.println("}");
writer.println(" if(params.$contentType)");
writer.println(" request.setContentType(params.$contentType);");
writer.println(" else");
writer.println(" request.setContentType('"
+ methodMetaData.getConsumesMIMEType() + "');");
writer.println(" if(params.$callback){");
writer.println(" request.execute(params.$callback);");
writer.println(" }else{");
writer.println(" var returnValue;");
writer.println(" request.setAsync(false);");
writer
.println(" var callback = function(httpCode, xmlHttpRequest, value){ returnValue = value;};");
writer.println(" request.execute(callback);");
writer.println(" return returnValue;");
writer.println(" }");
writer.println("};");
}
private void printOtherParams(MethodMetaData methodMetaData,
PrintWriter writer) {
List params = methodMetaData.getParameters();
for (MethodParamMetaData methodParamMetaData : params) {
printParameter(methodParamMetaData, writer);
}
}
private void printParameter(MethodParamMetaData metaData,
PrintWriter writer) {
switch (metaData.getParamType()) {
case QUERY_PARAMETER:
print(metaData, writer, "QueryParameter");
break;
case HEADER_PARAMETER:
print(metaData, writer, "Header");
// FIXME: warn about forbidden headers:
// http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader-method
break;
case COOKIE_PARAMETER:
print(metaData, writer, "Cookie");
break;
case MATRIX_PARAMETER:
print(metaData, writer, "MatrixParameter");
break;
case FORM_PARAMETER:
print(metaData, writer, "FormParameter");
break;
case FORM:
print(metaData, writer, "Form");
break;
case ENTITY_PARAMETER:
// the entity
writer.println(" if(params.$entity)");
writer.println(" request.setEntity(params.$entity);");
break;
}
}
private void print(MethodParamMetaData metaData, PrintWriter writer,
String type) {
String paramName = metaData.getParamName();
writer.println(
String.format(" if(Object.prototype.hasOwnProperty.call(params, '%s'))\n request.add%s('%s', params.%s);",
paramName, type, paramName, paramName));
}
private void printURIParams(String uri, PrintWriter writer) {
String replacedCurlyURI = PathHelper.replaceEnclosedCurlyBraces(uri);
Matcher matcher = PathHelper.URI_PARAM_PATTERN.matcher(replacedCurlyURI);
int i = 0;
while (matcher.find()) {
if (matcher.start() > i) {
writer.println(" uri += '"
+ replacedCurlyURI.substring(i, matcher.start()) + "';");
}
String name = matcher.group(1);
writer.println(" uri += REST.Encoding.encodePathSegment(params." + name + ");");
i = matcher.end();
}
if (i < replacedCurlyURI.length())
writer.println(" uri += '" + replacedCurlyURI.substring(i) + "';");
}
/**
* Resolves the case of {@code uri} ending with "/" and {@code uriToAppend} starting with "/" so that the combination
* of both ends up with only one "/" instead of "//".
*
*
*
* Example:
* http://localhost:8080/Uri//UriToAppend -> http://localhost:8080/Uri/UriToAppend
*
* @param uri the base URI with the possible extra "/" at the end.
* @param uriToAppend the URI being appended to the base one, with possible extra "/" at the beginning.
* @param appendToUri true if the {@code uriToAppend} should be appended to the {@code uri}, false if the
* {@code uriToAppend} should have the "/" removed without appending it to the {@code uri}.
* @return The {@code uriToAppend} appended to the {@code uri} if the {@code appendToUri} is true, the {@code uriToAppend}
* without the extra "/" at the beginning if the {@code appendToUri} is false. In both cases there are no two "//"
* between the {@code uri} and the {@code uriToAppend}.
*/
private String resolveDoubleSlash(String uri, String uriToAppend, boolean appendToUri) {
if (uri.endsWith("/") && uriToAppend.startsWith("/")) {
// Remove the extra "/" at the beginning of uriToAppend
if (uriToAppend.length() > 1) {
if (appendToUri) {
return uri.concat(uriToAppend.substring(1));
} else {
return uriToAppend.substring(1);
}
}
// Edge case if the uriToAppend is just "/"
else {
if (appendToUri) {
return uri;
}
return "";
}
}
// If the
if (appendToUri) {
return uri.concat(uriToAppend);
}
return uriToAppend;
}
}