/*
* Copyright 2016 predic8 GmbH, www.predic8.com
* 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 com.predic8.membrane.core.interceptor.javascript;
import com.google.common.base.Function;
import com.predic8.membrane.annot.MCElement;
import com.predic8.membrane.annot.MCTextContent;
import com.predic8.membrane.core.exchange.Exchange;
import com.predic8.membrane.core.http.Request;
import com.predic8.membrane.core.http.Response;
import com.predic8.membrane.core.interceptor.AbstractInterceptor;
import com.predic8.membrane.core.interceptor.Outcome;
import com.predic8.membrane.core.lang.javascript.JavascriptLanguageSupport;
import com.predic8.membrane.core.util.ClassFinder;
import com.predic8.membrane.core.util.TextUtil;
import org.apache.commons.lang.StringEscapeUtils;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.*;
@MCElement(name = "javascript", mixed = true)
public class JavascriptInterceptor extends AbstractInterceptor {
private String src = "";
private Function<Map<String, Object>, Object> script;
private JavascriptLanguageSupport jls;
private HashMap<String, Object> implicitClasses;
public JavascriptInterceptor() {
name = "Javascript";
}
@Override
public Outcome handleRequest(Exchange exc) throws Exception {
return runScript(exc, Flow.REQUEST);
}
@Override
public Outcome handleResponse(Exchange exc) throws Exception {
return runScript(exc, Flow.RESPONSE);
}
@Override
public void handleAbort(Exchange exc) {
try {
runScript(exc, Flow.ABORT);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void init() throws IOException, ClassNotFoundException {
if (router == null)
return;
if ("".equals(src))
return;
jls = new JavascriptLanguageSupport();
implicitClasses = getJavascriptTypesForHttpClasses();
script = jls.compileScript(router, src);
}
private Outcome runScript(Exchange exc, Flow flow) throws InterruptedException, IOException, ClassNotFoundException {
HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("exc", exc);
parameters.put("flow", flow);
parameters.put("spring", router.getBeanFactory());
addOutcomeObjects(parameters);
parameters.putAll(implicitClasses);
Object res = script.apply(parameters);
if (res instanceof Outcome) {
return (Outcome) res;
}
if (res instanceof Response) {
exc.setResponse((Response) res);
return Outcome.RETURN;
}
if (res instanceof Request) {
exc.setRequest((Request) res);
}
return Outcome.CONTINUE;
}
private HashMap<String, Object> getJavascriptTypesForHttpClasses() throws IOException, ClassNotFoundException {
return getJavascriptTypesForClasses(getHttpPackageClasses());
}
private HashMap<String, Object> getJavascriptTypesForClasses(HashMap<String, Object> classes) {
HashMap<String, Object> result = new HashMap<>();
for(Object clazz : classes.values()){
Class<?> clazzz = (Class<?>) clazz;
String scriptSrc = clazzz.getSimpleName() + ".static;";
//TODO this is hacky, do this differently ( maybe do this one time at startup )
Object jsType = jls.compileScript(router, scriptSrc).apply(classes);
result.put(clazzz.getSimpleName(),jsType);
}
return result;
}
private void addOutcomeObjects(HashMap<String, Object> parameters) {
parameters.put("Outcome", Outcome.class);
parameters.put("RETURN", Outcome.RETURN);
parameters.put("CONTINUE", Outcome.CONTINUE);
parameters.put("ABORT", Outcome.ABORT);
}
private HashMap<String, Object> getHttpPackageClasses() throws IOException, ClassNotFoundException {
String httpPackage = "com.predic8.membrane.core.http";
HashMap<String, Object> result = new HashMap<>();
List<Class<?>> classes = ClassFinder.find(router.getBeanFactory().getClassLoader(), httpPackage);
for(Class c : classes) {
if(c.getPackage().getName().equals(httpPackage) && !c.getSimpleName().isEmpty())
result.put(c.getSimpleName(), c);
}
return result;
}
public String getSrc() {
return src;
}
@MCTextContent
public void setSrc(String src) {
this.src = src;
}
@Override
public String getShortDescription() {
return "Executes a Javascript script.";
}
@Override
public String getLongDescription() {
StringBuilder sb = new StringBuilder();
sb.append(TextUtil.removeFinalChar(getShortDescription()));
sb.append(":<br/><pre style=\"overflow-x:auto\">");
sb.append(StringEscapeUtils.escapeHtml(TextUtil.removeCommonLeadingIndentation(src)));
sb.append("</pre>");
return sb.toString();
}
}