Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New features to simulate POST/PUT WebScripts #88

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion javascript-console-repo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<parent>
<groupId>de.fmaul</groupId>
<artifactId>javascript-console</artifactId>
<version>0.7-SNAPSHOT</version>
<version>0.8-SNAPSHOT</version>
</parent>

<developers>
Expand Down Expand Up @@ -84,6 +84,7 @@
<groupId>${alfresco.groupId}</groupId>
<artifactId>alfresco-repository</artifactId>
</dependency>

</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@
import org.springframework.extensions.webscripts.Container;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Description;
import org.springframework.extensions.webscripts.FormatReader;
import org.springframework.extensions.webscripts.ScriptContent;
import org.springframework.extensions.webscripts.ScriptProcessor;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.TemplateProcessor;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptRequestImpl;
import org.springframework.extensions.webscripts.WebScriptResponse;

/**
Expand Down Expand Up @@ -106,7 +108,14 @@ public void execute(WebScriptRequest request, WebScriptResponse response) throws
try {
// this isn't very precise since there is some bit of processing until here that we can't measure
PerfLog webscriptPerf = new PerfLog().start();
JavascriptConsoleRequest jsreq = JavascriptConsoleRequest.readJson(request);
JavascriptConsoleRequest jsreq = null;
if(request.getContentType().equals(WebScriptRequestImpl.MULTIPART_FORM_DATA)) {
jsreq = JavascriptConsoleRequest.readFormData(request);
}
else {
// standard json
jsreq = JavascriptConsoleRequest.readJson(request);
}

// Note: Need to use import here so the user-supplied script may also import scripts
String script = "<import resource=\"classpath:" + PRE_ROLL_SCRIPT_RESOURCE + "\">\n" + jsreq.script;
Expand Down Expand Up @@ -278,14 +287,14 @@ public JavascriptConsoleResult execute() throws Exception {
printOutput.clear();
}
return executeScriptContent(request, response, scriptContent, jsreq.template, jsreq.spaceNodeRef,
jsreq.urlargs, jsreq.documentNodeRef, printOutput);
jsreq.mockRequest, jsreq.documentNodeRef, printOutput);
}
}, jsreq.transactionReadOnly);
return result;
}

LOG.debug("Executing script script without transaction.");
result = executeScriptContent(request, response, scriptContent, jsreq.template, jsreq.spaceNodeRef, jsreq.urlargs,
result = executeScriptContent(request, response, scriptContent, jsreq.template, jsreq.spaceNodeRef, jsreq.mockRequest,
jsreq.documentNodeRef, printOutput);
return result;
}
Expand All @@ -297,7 +306,7 @@ public JavascriptConsoleResult execute() throws Exception {
* WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
private JavascriptConsoleResult executeScriptContent(WebScriptRequest req, WebScriptResponse res,
ScriptContent scriptContent, String template, String spaceNodeRef, Map<String, String> urlargs, String documentNodeRef,
ScriptContent scriptContent, String template, String spaceNodeRef, WebScriptRequest mockReq, String documentNodeRef,
List<String> printOutput) {
JavascriptConsoleResult output = new JavascriptConsoleResult();

Expand All @@ -312,10 +321,14 @@ private JavascriptConsoleResult executeScriptContent(WebScriptRequest req, WebSc
model.put("status", status);
model.put("cache", cache);

Map<String, Object> scriptModel = createScriptParameters(req, res, null, model);

augmentScriptModelArgs(scriptModel, urlargs);

Map<String, Object> scriptModel = createScriptParameters(mockReq, res, null, model);

// add object related to request type e.g. json object
FormatReader<Object> reader = getContainer().getFormatRegistry().getReader(mockReq.getContentType());
if(reader != null) {
scriptModel.putAll(reader.createScriptParameters(mockReq, res));
}

// add return model allowing script to add items to template model
Map<String, Object> returnModel = new HashMap<String, Object>(8, 1.0f);
scriptModel.put("model", returnModel);
Expand Down Expand Up @@ -407,13 +420,6 @@ private JavascriptConsoleResult executeScriptContent(WebScriptRequest req, WebSc
return output;
}

private void augmentScriptModelArgs(Map<String, Object> scriptModel, Map<String, String> additionalUrlArgs) {
@SuppressWarnings("unchecked")
Map<String, String> args = (Map<String, String>) scriptModel.get("args");

args.putAll(additionalUrlArgs);
}

/**
* Merge script generated model into template-ready model
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
package de.fme.jsconsole;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.util.Streams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptRequestImpl;
import org.springframework.extensions.webscripts.servlet.FormData.FormField;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;

import de.fme.jsconsole.request.MockFormData;
import de.fme.jsconsole.request.MockHttpServletRequest;
import de.fme.jsconsole.request.MockWebScriptRequest;

/**
* Parses and stores the input data for the Javascript Console {@link ExecuteWebscript} and contains
Expand All @@ -30,25 +44,25 @@ public class JavascriptConsoleRequest {
public final String runas;
public final boolean useTransaction;
public final boolean transactionReadOnly;
public final Map<String, String> urlargs;
public final String documentNodeRef;
public final Integer dumpLimit;
public final WebScriptRequest mockRequest;

public final String resultChannel;

private JavascriptConsoleRequest(String script, String template,
String spaceNodeRef, String transaction, String runas, String urlargs, String documentNodeRef, Integer dumpLimit, String resultChannel) {
String spaceNodeRef, String transaction, String runas, String documentNodeRef, Integer dumpLimit, String resultChannel, WebScriptRequest mockRequest) {
super();
this.script = script;
this.template = template;
this.spaceNodeRef = spaceNodeRef;
this.documentNodeRef = documentNodeRef;
this.dumpLimit = dumpLimit;
this.urlargs = parseQueryString(urlargs);
this.dumpLimit = dumpLimit;
this.transactionReadOnly = "readonly".equalsIgnoreCase(transaction);
this.useTransaction = transactionReadOnly || "readwrite".equalsIgnoreCase(transaction);
this.runas = runas;
this.resultChannel = resultChannel;
this.mockRequest = mockRequest;
}

/**
Expand All @@ -74,7 +88,93 @@ protected static Map<String, String> parseQueryString(String queryString) {

return map;
}

protected static WebScriptRequest parseMockRequest(String requestType, String requestContent, String requestHeaders, String urlargs, WebScriptRequest request) {
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
mockRequest.setCharacterEncoding("UTF-8");
mockRequest.setContentType(requestType);
mockRequest.setParameters(parseQueryString(urlargs));

JSONTokener jsonTokener = new JSONTokener(requestHeaders);
try {
JSONArray jsonHeaders = new JSONArray(jsonTokener);
for(int i = 0 ; i < jsonHeaders.length(); ++i) {
JSONObject jsonHeader = (JSONObject) jsonHeaders.get(i);
if(jsonHeader.has("name") && jsonHeader.has("value")) {
mockRequest.addHeader(jsonHeader.getString("name"), jsonHeader.getString("value"));
}
}
} catch (JSONException e) {
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
"Error reading json request (part: headers).", e);
}

mockRequest.setContent(requestContent.getBytes());

MockWebScriptRequest mockWebScript = new MockWebScriptRequest(request.getRuntime(), mockRequest, request.getServiceMatch(), null);
if(requestType.equals(WebScriptRequestImpl.MULTIPART_FORM_DATA)){

MockFormData mockFormData = new MockFormData();
FileItemFactory fileItemFactory = new DiskFileItemFactory();

JSONTokener jsonMpFieldsTokener = new JSONTokener(request.getParameter("mp-fields"));
try {
JSONArray mpFields = new JSONArray(jsonMpFieldsTokener);
for(int i = 0 ; i < mpFields.length(); ++i) {
JSONObject mpField = (JSONObject) mpFields.get(i);
String key = mpField.getString("name");
FormField formField = null;
if(mpField.getString("type").equals("param")) {
mockRequest.addParameter(key, request.getParameter(key));

FileItem fileItem = fileItemFactory.createItem(key, null, true, null);
Streams.copy(new ByteArrayInputStream(request.getParameter(key).getBytes()), fileItem.getOutputStream(), true);
formField = mockFormData.new FormField(fileItem);
} else {
// file type
formField = ((WebScriptServletRequest)request).getFileField(key);

}
mockFormData.addFormField(formField);
}
} catch (IOException | JSONException e) {
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
"Error reading json request (part: form data fields).", e);
}

mockWebScript.setMockFormData(mockFormData);
}

return mockWebScript;
}

public static JavascriptConsoleRequest readFormData(WebScriptRequest request) {
String script = request.getParameter("script");
String template = request.getParameter("template");
String spaceNodeRef = request.getParameter("spaceNodeRef");
String transaction = request.getParameter("transaction");
String urlargs = request.getParameter("urlargs");
String documentNodeRef = request.getParameter("documentNodeRef");
int dumpLimit = DEFAULT_DUMP_LIMIT;
if(request.getParameter("dumpLimit") != null){
dumpLimit = Integer.parseInt(request.getParameter("dumpLimit"));
}
//String logOutputChannel = request.getParameter("printOutputChannel");
String resultChannel = request.getParameter("resultChannel");
String requestType = request.getParameter("requestType");
String requestContent = request.getParameter("requestContent");
String requestHeaders = request.getParameter("requestHeaders");
WebScriptRequest mockRequest = parseMockRequest(requestType, requestContent, requestHeaders, urlargs, request);

String runas = request.getParameter("runas");
if (runas == null) {
runas = "";
}

return new JavascriptConsoleRequest(script, template, spaceNodeRef, transaction, runas, documentNodeRef, dumpLimit, resultChannel, mockRequest);

}

public static JavascriptConsoleRequest readJson(WebScriptRequest request) {
Content content = request.getContent();

Expand All @@ -96,14 +196,18 @@ public static JavascriptConsoleRequest readJson(WebScriptRequest request) {
}
String logOutputChannel = jsonInput.has("printOutputChannel") ? jsonInput.getString("printOutputChannel") : null;
String resultChannel = jsonInput.has("resultChannel") ? jsonInput.getString("resultChannel") : null;

String requestType = jsonInput.has("requestType") ? jsonInput.getString("requestType") : null;
String requestContent = jsonInput.has("requestContent") ? jsonInput.getString("requestContent") : null;
String requestHeaders = jsonInput.has("requestHeaders") ? jsonInput.getString("requestHeaders") : null;

String runas = jsonInput.getString("runas");
if (runas == null) {
runas = "";
}

return new JavascriptConsoleRequest(script, template, spaceNodeRef, transaction, runas, urlargs, documentNodeRef, dumpLimit, resultChannel);
WebScriptRequest mockRequest = parseMockRequest(requestType, requestContent, requestHeaders, urlargs, request);

return new JavascriptConsoleRequest(script, template, spaceNodeRef, transaction, runas, documentNodeRef, dumpLimit, resultChannel, mockRequest);
} catch (JSONException e) {
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
"Error reading json request body.", e);
Expand All @@ -114,7 +218,10 @@ public static JavascriptConsoleRequest readJson(WebScriptRequest request) {
public String toString() {
return "JavascriptConsoleRequest [script=" + script + ", template=" + template + ", spaceNodeRef=" + spaceNodeRef
+ ", runas=" + runas + ", useTransaction=" + useTransaction + ", transactionReadOnly=" + transactionReadOnly
+ ", urlargs=" + urlargs + ", documentNodeRef=" + documentNodeRef + ", dumpLimit=" + dumpLimit + ", resultChannel=" + resultChannel + "]";
+ ", documentNodeRef=" + documentNodeRef + ", dumpLimit=" + dumpLimit + ", mockRequest=" + mockRequest
+ ", resultChannel=" + resultChannel + "]";
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.fme.jsconsole.request;

import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletInputStream;

import org.springframework.util.Assert;

/**
* Delegating implementation of {@link javax.servlet.ServletInputStream}.
*
* <p>Used by {@link MockHttpServletRequest}; typically not directly
* used for testing application controllers.
*
* From package: org.springframework.spring-test 4.1.3
*
* @author Juergen Hoeller
* @since 1.0.2
* @see MockHttpServletRequest
*/
public class DelegatingServletInputStream extends ServletInputStream {

private final InputStream sourceStream;


/**
* Create a DelegatingServletInputStream for the given source stream.
* @param sourceStream the source stream (never {@code null})
*/
public DelegatingServletInputStream(InputStream sourceStream) {
Assert.notNull(sourceStream, "Source InputStream must not be null");
this.sourceStream = sourceStream;
}

/**
* Return the underlying source stream (never {@code null}).
*/
public final InputStream getSourceStream() {
return this.sourceStream;
}


@Override
public int read() throws IOException {
return this.sourceStream.read();
}

@Override
public void close() throws IOException {
super.close();
this.sourceStream.close();
}

}
Loading