blob: 26796510aeb754c64b003f4b10c6484689b916f3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.stanbol.enhancer.benchmark.impl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.clerezza.rdf.core.Graph;
import org.apache.clerezza.rdf.core.serializedform.Serializer;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.stanbol.enhancer.benchmark.Benchmark;
import org.apache.stanbol.enhancer.benchmark.BenchmarkParser;
import org.apache.stanbol.enhancer.servicesapi.Chain;
import org.apache.stanbol.enhancer.servicesapi.ChainManager;
import org.apache.stanbol.enhancer.servicesapi.ContentItemFactory;
import org.apache.stanbol.enhancer.servicesapi.EnhancementJobManager;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.apache.velocity.tools.generic.EscapeTool;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Front-end servlet for the benchmark module */
@Component(immediate=true, metatype=false)
@SuppressWarnings("serial")
public class BenchmarkServlet extends HttpServlet {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference
private HttpService httpService;
@Reference
private BenchmarkParser parser;
@Reference
private EnhancementJobManager jobManager;
@Reference
private ContentItemFactory ciFactory;
@Reference
private Serializer graphSerializer;
/**
* Needed to lookup active enhancement changes as parsed by {@link ChainState}
*/
@Reference
private ChainManager chainManager;
public static final String PARAM_CONTENT = "content";
private static final String PARAM_CHAIN = "chain";
public static final String DEFAULT_MOUNT_PATH = "/benchmark";
public static final String DEFAULT_BENCHMARK = "default.txt";
public static final String EXAMPLE_BENCHMARKS_RESOURCE_ROOT = "/examples";
@Property(value=DEFAULT_MOUNT_PATH)
public static final String MOUNT_PATH_PROPERTY = "mount.path";
private String mountPath;
private final VelocityEngine velocity = new VelocityEngine();
// Formatter for benchmark graphs
public static class GraphFormatter {
private final Serializer serializer;
GraphFormatter(Serializer s) {
serializer = s;
}
public String format(Graph g, String mimeType) throws UnsupportedEncodingException {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
serializer.serialize(bos, g, mimeType);
return bos.toString("UTF-8");
}
};
/** Register with HttpService when activated */
public void activate(ComponentContext ctx) throws ServletException, NamespaceException {
mountPath = (String)ctx.getProperties().get(MOUNT_PATH_PROPERTY);
if(mountPath == null) {
mountPath = DEFAULT_MOUNT_PATH;
}
if(mountPath.endsWith("/")) {
mountPath = mountPath.substring(mountPath.length() - 1);
}
httpService.registerServlet(mountPath, this, null, null);
log.info("Servlet mounted at {}", mountPath);
final Properties config = new Properties();
config.put("class.resource.loader.description", "Velocity Classpath Resource Loader");
config.put("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
config.put("resource.loader","class");
velocity.init(config);
}
public void deactivate(ComponentContext ctx) {
httpService.unregister(mountPath);
}
@Override
public String getServletInfo() {
return "Apache Stanbol Enhancer Benchmarks";
}
private VelocityContext getVelocityContext(HttpServletRequest request, String pageTitle) {
final VelocityContext ctx = new VelocityContext();
ctx.put("title", getServletInfo() + " - " + pageTitle);
ctx.put("contextPath", request.getContextPath());
ctx.put("cssPath", request.getContextPath() + mountPath + "/benchmark.css");
ctx.put("esc", new EscapeTool());
return ctx;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final String path = request.getPathInfo() == null ? "" : request.getPathInfo();
if(path.endsWith(".css")) {
// Serve our css
final Template t = getTemplate("/velocity/benchmark.css");
response.setContentType("text/css");
response.setCharacterEncoding("UTF-8");
t.merge(getVelocityContext(request, null), response.getWriter());
} else if(path.length() < 2){
// No benchmark specified -> redirect to default
response.sendRedirect(getExampleBenchmarkPath(request, DEFAULT_BENCHMARK));
} else {
// Benchmark input form pre-filled with selected example
final Template t = getTemplate("/velocity/benchmark-input.html");
final VelocityContext ctx = getVelocityContext(request, "Benchmark Input");
ctx.put("formAction", request.getContextPath() + mountPath);
ctx.put("benchmarkText", getBenchmarkText(path));
ctx.put("benchmarkPaths", getExampleBenchmarkPaths(request));
ctx.put("currentBenchmarkPath", path);
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
t.merge(ctx, response.getWriter());
}
}
/**
* @return
*/
private Template getTemplate(String templatePath) {
final Template t;
ClassLoader tcl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(BenchmarkServlet.class.getClassLoader());
try {
t = velocity.getTemplate(templatePath);
} finally {
Thread.currentThread().setContextClassLoader(tcl);
}
return t;
}
private String getExampleBenchmarkPath(HttpServletRequest request, String name) {
return request.getContextPath() + mountPath + "/" + name;
}
private List<String> getExampleBenchmarkPaths(HttpServletRequest request) throws IOException {
// TODO how to enumerate bundle resources?
final String list = getBenchmarkText("/LIST.txt");
final LineIterator it = new LineIterator(new StringReader(list));
final List<String> result = new LinkedList<String>();
while(it.hasNext()) {
result.add(getExampleBenchmarkPath(request, it.nextLine()));
}
return result;
}
/** Return example benchmark text from our class resources */
private String getBenchmarkText(String path) throws IOException {
final InputStream is = getClass().getResourceAsStream(EXAMPLE_BENCHMARKS_RESOURCE_ROOT + path);
if(is == null) {
return "";
}
try {
return IOUtils.toString(is);
} finally {
is.close();
}
}
@Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
final String content = request.getParameter(PARAM_CONTENT);
if(content == null) {
throw new ServletException("Missing " + PARAM_CONTENT + " parameter");
}
String chainName = request.getParameter(PARAM_CHAIN);
final Template t = AccessController.doPrivileged(new PrivilegedAction<Template>() {
@Override
public Template run() {
return getTemplate("/velocity/benchmark-results.html");
}
});
final VelocityContext ctx = getVelocityContext(request, "Benchmark Results");
ctx.put("contentItemFactory", ciFactory);
ctx.put("jobManager", jobManager);
List<? extends Benchmark> benchmarks = parser.parse(new StringReader(content));
if(chainName != null && !chainName.isEmpty()){
Chain chain = chainManager.getChain(chainName);
if(chain == null){
response.setStatus(404);
PrintWriter w = response.getWriter();
w.println("Unable to perform benchmark on EnhancementChain '"
+chainName+"' because no chain with that name is active!");
IOUtils.closeQuietly(w);
return;
}
for(Benchmark benchmark : benchmarks){
benchmark.setChain(chain);
}
}
ctx.put("benchmarks", benchmarks);
ctx.put("graphFormatter", new GraphFormatter(graphSerializer));
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws IOException{
t.merge(ctx, response.getWriter());
return null;
}
});
} catch (PrivilegedActionException pae) {
Exception e = pae.getException();
if(e instanceof IOException){
throw (IOException)e;
} else {
throw RuntimeException.class.cast(e);
}
}
}
}