Added support for bundling .js files to shave off some loading time.

For GetRowsCommand, tried to use jsonp but that didn't seem to improve performance much.
Gzip http responses of various text-based mime types.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@1122 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-07-31 06:51:11 +00:00
parent 717ccdaf41
commit f069780bfa
9 changed files with 140 additions and 43 deletions

View File

@ -17,9 +17,14 @@ import edu.mit.simile.butterfly.MountPoint;
public class ClientSideResourceManager {
final static Logger logger = LoggerFactory.getLogger("gridworks_clientSideResourceManager");
static public class QualifiedPath {
public ButterflyModule module;
public String path;
public String fullPath;
}
static public class ClientSideResourceBundle {
final protected Set<String> _pathSet = new HashSet<String>();
final protected List<String> _pathList = new ArrayList<String>();
final protected List<QualifiedPath> _pathList = new ArrayList<QualifiedPath>();
}
final static protected Map<String, ClientSideResourceBundle> s_bundles
@ -43,18 +48,23 @@ public class ClientSideResourceManager {
break;
}
if (!bundle._pathSet.contains(fullPath)) {
QualifiedPath qualifiedPath = new QualifiedPath();
qualifiedPath.module = module;
qualifiedPath.path = path;
qualifiedPath.fullPath = fullPath;
bundle._pathSet.add(fullPath);
bundle._pathList.add(fullPath);
bundle._pathList.add(qualifiedPath);
}
}
}
static public String[] getPaths(String bundleName) {
static public QualifiedPath[] getPaths(String bundleName) {
ClientSideResourceBundle bundle = s_bundles.get(bundleName);
if (bundle == null) {
return new String[] {};
return new QualifiedPath[] {};
} else {
String[] paths = new String[bundle._pathList.size()];
QualifiedPath[] paths = new QualifiedPath[bundle._pathList.size()];
bundle._pathList.toArray(paths);
return paths;
}

View File

@ -1,6 +1,7 @@
package com.metaweb.gridworks.commands.row;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;
import javax.servlet.ServletException;
@ -30,10 +31,21 @@ public class GetRowsCommand extends Command {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
internalRespond(request, response);
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
internalRespond(request, response);
}
protected void internalRespond(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
Engine engine = getEngine(request, project);
String callback = request.getParameter("callback");
int start = Math.min(project.rows.size(), Math.max(0, getIntegerParameter(request, "start", 0)));
int limit = Math.min(project.rows.size() - start, Math.max(0, getIntegerParameter(request, "limit", 20)));
@ -45,12 +57,18 @@ public class GetRowsCommand extends Command {
options.put("pool", pool);
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
response.setHeader("Content-Type", callback == null ? "application/json" : "text/javascript");
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
PrintWriter writer = response.getWriter();
if (callback != null) {
writer.write(callback);
writer.write("(");
}
RowWritingVisitor rwv = new RowWritingVisitor(start, limit, writer, options);
JSONWriter jsonWriter = new JSONWriter(writer);
jsonWriter.object();
RowWritingVisitor rwv = new RowWritingVisitor(start, limit, jsonWriter, options);
JSONObject sortingJson = null;
try{
@ -73,12 +91,12 @@ public class GetRowsCommand extends Command {
}
}
writer.key("mode"); writer.value("row-based");
writer.key("rows"); writer.array();
jsonWriter.key("mode"); jsonWriter.value("row-based");
jsonWriter.key("rows"); jsonWriter.array();
filteredRows.accept(project, visitor);
writer.endArray();
writer.key("filtered"); writer.value(rwv.total);
writer.key("total"); writer.value(project.rows.size());
jsonWriter.endArray();
jsonWriter.key("filtered"); jsonWriter.value(rwv.total);
jsonWriter.key("total"); jsonWriter.value(project.rows.size());
} else {
FilteredRecords filteredRecords = engine.getFilteredRecords();
RecordVisitor visitor = rwv;
@ -92,20 +110,24 @@ public class GetRowsCommand extends Command {
}
}
writer.key("mode"); writer.value("record-based");
writer.key("rows"); writer.array();
jsonWriter.key("mode"); jsonWriter.value("record-based");
jsonWriter.key("rows"); jsonWriter.array();
filteredRecords.accept(project, visitor);
writer.endArray();
writer.key("filtered"); writer.value(rwv.total);
writer.key("total"); writer.value(project.recordModel.getRecordCount());
jsonWriter.endArray();
jsonWriter.key("filtered"); jsonWriter.value(rwv.total);
jsonWriter.key("total"); jsonWriter.value(project.recordModel.getRecordCount());
}
writer.key("start"); writer.value(start);
writer.key("limit"); writer.value(limit);
writer.key("pool"); pool.write(writer, options);
jsonWriter.key("start"); jsonWriter.value(start);
jsonWriter.key("limit"); jsonWriter.value(limit);
jsonWriter.key("pool"); pool.write(jsonWriter, options);
writer.endObject();
jsonWriter.endObject();
if (callback != null) {
writer.write(")");
}
} catch (Exception e) {
respondException(response, e);
}

View File

@ -28,4 +28,16 @@
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>GzipFilter</filter-name>
<filter-class>org.mortbay.servlet.GzipFilter</filter-class>
<init-param>
<param-name>mimeTypes</param-name>
<param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,text/javascript,application/javascript,application/json,image/svg+xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>GzipFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

View File

@ -1,6 +1,7 @@
var html = "text/html";
var encoding = "UTF-8";
var ClientSideResourceManager = Packages.com.metaweb.gridworks.ClientSideResourceManager;
var bundle = true;
var templatedFiles = {
// Requests with last path segments mentioned here
@ -18,8 +19,6 @@ function init() {
"project/scripts",
module,
[
"wirings.js",
"externals/jquery-1.4.2.min.js",
"externals/jquery.cookie.js",
"externals/suggest/suggest-1.2.min.js",
@ -136,13 +135,71 @@ function process(path, request, response) {
var slash = path.lastIndexOf("/");
var lastSegment = slash >= 0 ? path.substring(slash + 1) : path;
if (lastSegment in templatedFiles) {
var context = {};
context.scripts = ClientSideResourceManager.getPaths(lastSegment + "/scripts");
context.styles = ClientSideResourceManager.getPaths(lastSegment + "/styles");
context.projectID = request.getParameter("project");
if (path.endsWith("-bundle.js")) {
lastSegment = lastSegment.substring(0, lastSegment.length - "-bundle.js".length);
send(request, response, path + ".vt", context);
response.setContentType("text/javascript");
response.setCharacterEncoding(encoding);
var output = response.getWriter();
try {
var paths = ClientSideResourceManager.getPaths(lastSegment + "/scripts");
for each (var qualifiedPath in paths) {
var input = null;
try {
var url = qualifiedPath.module.getResource(qualifiedPath.path);
var urlConnection = url.openConnection();
input = new Packages.java.io.BufferedReader(
new Packages.java.io.InputStreamReader(urlConnection.getInputStream()));
output.write("/* ===== ");
output.write(qualifiedPath.fullPath);
output.write(" ===== */\n\n");
Packages.org.apache.commons.io.IOUtils.copy(input, output);
output.write("\n\n");
} catch (e) {
// silent
} finally {
if (input != null) input.close();
}
}
} catch (e) {
// silent
} finally {
butterfly.responded();
}
return true;
} else {
if (lastSegment in templatedFiles) {
var context = {};
context.projectID = request.getParameter("project");
var styles = ClientSideResourceManager.getPaths(lastSegment + "/styles");
var styleInjection = [];
for each (var qualifiedPath in styles) {
styleInjection.push(
'<link type="text/css" rel="stylesheet" href="' + qualifiedPath.fullPath + '" />');
}
context.styleInjection = styleInjection.join("\n");
if (bundle) {
context.scriptInjection = '<script type="text/javascript" src="' + path + '-bundle.js"></script>';
} else {
var scripts = ClientSideResourceManager.getPaths(lastSegment + "/scripts");
var scriptInjection = [];
for each (var qualifiedPath in scripts) {
scriptInjection.push(
'<script type="text/javascript" src="' + qualifiedPath.fullPath + '"></script>');
}
context.scriptInjection = scriptInjection.join("\n");
}
send(request, response, path + ".vt", context);
}
}
}
}

View File

@ -2,18 +2,14 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Freebase Gridworks</title>
<link rel="icon" type="image/png" href="images/favicon.png" />
<script type="text/javascript">var theProject = { id : $projectID };</script>
#foreach($path in $styles)
<link type="text/css" rel="stylesheet" href="$path" />
#end
#foreach($path in $scripts)
<script type="text/javascript" src="$path"></script>
#end
<script type="text/javascript">var theProject = { id : $projectID };</script>
<script type="text/javascript" src="wirings.js"></script>
$scriptInjection
<link rel="icon" type="image/png" href="images/favicon.png" />
$styleInjection
</head>
<body>

View File

@ -346,7 +346,7 @@ Gridworks.fetchRows = function(start, limit, onDone, sorting) {
}
$.post(
"/command/get-rows?" + $.param({ project: theProject.id, start: start, limit: limit }),
"/command/get-rows?" + $.param({ project: theProject.id, start: start, limit: limit }) + "&callback=?",
body,
function(data) {
theProject.rowModel = data;
@ -367,7 +367,7 @@ Gridworks.fetchRows = function(start, limit, onDone, sorting) {
onDone();
}
},
"json"
"jsonp"
);
};