package nsf.playground.playground;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nsf.playground.beans.DataAccessBean;
import nsf.playground.beans.OptionsBean;
import nsf.playground.environments.PlaygroundEnvironment;
import nsf.playground.extension.JavaScriptPreviewExtension;
import nsf.playground.extension.PlaygroundExtensionFactory;
import com.ibm.commons.runtime.util.ParameterProcessor;
import com.ibm.commons.runtime.util.UrlUtil;
import com.ibm.commons.util.PathUtil;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.util.io.ReaderInputStream;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.commons.util.io.json.JsonObject;
import com.ibm.commons.util.io.json.JsonParser;
import com.ibm.xsp.context.DojoLibrary;
import com.ibm.xsp.context.DojoLibraryFactory;
import com.ibm.xsp.extlib.util.ExtLibUtil;
import com.ibm.xsp.minifier.DojoDependencyList;
import com.ibm.xsp.minifier.DojoResource;
import com.ibm.xsp.minifier.MinifierResourceProvider;
import com.ibm.xsp.minifier.ResourceFactory;
import com.ibm.xsp.sbtsdk.servlets.JavaScriptLibraries;
public class PreviewJavaScriptHandler extends PreviewHandler {
private static final String LAST_REQUEST = "javascriptsnippet.lastrequest";
public static class RequestParams implements Serializable {
private static final long serialVersionUID = 1L;
public String html;
public String js;
public String css;
public JsonJavaObject options = new JsonJavaObject();
public Properties properties = new Properties();
public RequestParams(String sOptions, String html, String js, String css, String sProperties) {
this.html = html;
this.js = js;
this.css = css;
if(StringUtil.isNotEmpty(sOptions)) {
try {
options = (JsonJavaObject)JsonParser.fromJson(JsonJavaFactory.instanceEx, sOptions);
} catch(Exception ex) {}
}
if(StringUtil.isNotEmpty(sProperties)) {
try {
// Pass the properties from the file
if(StringUtil.isNotEmpty(sProperties)) {
this.properties.load(new ReaderInputStream(new StringReader(sProperties)));
}
} catch(Exception ex) {}
}
}
}
// Utilities...
protected static Pattern amdRequireRegEx = Pattern.compile("require\\s*\\(\\s*\\[(.*)\\]");
protected static Pattern amdRequireRegEx2 = Pattern.compile("[\'\"]([^\'\"]*)[\'\"]");
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String sOptions = req.getParameter("fm_options");
String html = req.getParameter("fm_html");
String js = req.getParameter("fm_js");
String css = req.getParameter("fm_css");
String properties = req.getParameter("fm_properties");
RequestParams requestParams = new RequestParams(sOptions,html,js,css,properties);
req.getSession().setAttribute(LAST_REQUEST, requestParams);
resp.sendRedirect(UrlUtil.getRequestUrl(req));
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestParams requestParams = (RequestParams)req.getSession().getAttribute(LAST_REQUEST);
if(requestParams!=null) {
findRenderer(req, resp, requestParams).execRequest();
} else {
PrintWriter pw = resp.getWriter();
pw.println("Social Business Toolkit Playground - JavaScript Snippet Preview Servlet");
pw.flush();
}
}
public Renderer findRenderer(HttpServletRequest req, HttpServletResponse resp, RequestParams requestParams) throws IOException {
List<JavaScriptPreviewExtension> pgExtensions = (List<JavaScriptPreviewExtension>)PlaygroundExtensionFactory.getExtensions(JavaScriptPreviewExtension.class);
// Find the first renderer that handles it, from the registered extensions
Renderer r = null;
for(int i=0; i<pgExtensions.size(); i++) {
r = pgExtensions.get(i).findRenderer(req, resp, requestParams, false);
if(r!=null) {
break;
}
}
if(r==null) {
for(int i=0; i<pgExtensions.size(); i++) {
r = pgExtensions.get(i).findRenderer(req, resp, requestParams, true);
if(r!=null) {
break;
}
}
}
if(r==null) {
r = new Renderer(req, resp, requestParams);
}
r.init();
return r;
}
public static class Renderer extends BaseRenderer {
protected HttpServletRequest req;
protected HttpServletResponse resp;
protected RequestParams requestParams;
protected boolean debug;
protected String envName;
protected PlaygroundEnvironment env;
protected EnvParameterProvider prov;
protected JavaScriptLibraries.JSLibrary jsLib;
protected String jsLibraryPath;
protected boolean isDojo;
protected String serverUrl;
protected String dbUrl;
protected String bodyTheme;
protected Renderer(HttpServletRequest req, HttpServletResponse resp, RequestParams requestParams) throws IOException {
this.req = req;
this.resp = resp;
this.requestParams = requestParams;
}
protected void init() throws IOException {
// Check if we are in a debug environment
this.debug = requestParams.options.getBoolean("debug");
// Prepare the current environment
this.envName = requestParams.options.getString("env");
this.env = DataAccessBean.get().getEnvironment(envName);
this.prov = new EnvParameterProvider(env);
env.prepareEndpoints();
// Push the dynamic parameters to the user session
JsonObject p = (JsonObject)requestParams.options.get("params");
if(p!=null) {
for(Iterator<String> it= p.getJsonProperties(); it.hasNext(); ) {
String name = it.next();
String value = (String)p.getJsonProperty(name);
env.pushSessionParams(name, value);
}
}
// Compose the URLs
this.serverUrl = composeServerUrl(req);
this.dbUrl = composeDatabaseUrl(req,serverUrl);
// Find the library to use
int libIdx = Math.max(0, requestParams.options.getInt("lib"));
this.jsLib = JavaScriptLibraries.LIBRARIES[libIdx];
this.isDojo = jsLib.getLibType()==JavaScriptLibraries.LibType.DOJO;
this.jsLibraryPath = jsLib.getLibUrl();
if(libIdx==0) {
this.jsLibraryPath = getDefautLibraryPath(serverUrl);
}
if(jsLibraryPath.endsWith("/")) {
this.jsLibraryPath = jsLibraryPath.substring(0,jsLibraryPath.length()-1);
}
}
protected void execRequest() throws ServletException, IOException {
resp.setContentType("text/html");
// Map m = req.getParameterMap();
// for(Object k: m.keySet()) {
// Object v = m.get(k);
// System.out.println("Key:"+k+", Value:"+StringUtil.toString(v,32));
// }
PrintWriter pw = resp.getWriter();
pw.println("<!DOCTYPE html>");
pw.println("<html lang=\"en\">");
generateHead(pw);
generateBody(pw);
pw.println("</html>");
pw.flush();
pw.close();
}
public void generateHead(PrintWriter pw) throws IOException {
pw.println("<head>");
generateHeadTitle(pw);
generateHeadTheme(pw);
generateHeadJSLibrary(pw);
generateHeadFirebug(pw);
pw.println("</head>");
}
protected void generateHeadTitle(PrintWriter pw) throws IOException {
pw.println(" <title>Social Business Playground</title>");
}
protected void generateHeadTheme(PrintWriter pw) throws IOException {
String theme = requestParams.properties.getProperty("theme");
boolean isDojo = jsLib.getLibType()==JavaScriptLibraries.LibType.DOJO;
if(StringUtil.equals(theme, "bootstrap")) {
pw.println(" <style type=\"text/css\">");
pw.println(" @import \"/xsp/.ibmxspres/.sbtsdk/bootstrap/css/bootstrap.min.css\";");
pw.println(" </style>");
} else if( (ExtLibUtil.isXPages853() && StringUtil.equals(theme, "oneui")) || StringUtil.equals(theme, "oneuiv2.1")) {
pw.println(" <style type=\"text/css\">");
if(isDojo) {
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/claro/claro.css\";");
pw.println(" @import \""+jsLibraryPath+"/dojo/resources/dojo.css\";");
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/dijit.css\";");
}
pw.println(" @import \"/xsp/.ibmxspres/domino/oneuiv2.1/base/core.css\";");
pw.println(" @import \"/xsp/.ibmxspres/domino/oneuiv2.1/base/dojo.css\";");
if(isDojo) {
pw.println(" @import \"/xsp/.ibmxspres/domino/oneuiv2.1/defaultTheme/defaultTheme.css\";");
pw.println(" @import \"/xsp/.ibmxspres/domino/oneuiv2.1/defaultTheme/dojoTheme.css\";");
}
pw.println(" </style>");
bodyTheme = "lotusui";
} else if( (!ExtLibUtil.isXPages853() && StringUtil.equals(theme, "oneui")) || StringUtil.equals(theme, "oneui302")) {
pw.println(" <style type=\"text/css\">");
if(isDojo) {
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/claro/claro.css\";");
pw.println(" @import \""+jsLibraryPath+"/dojo/resources/dojo.css\";");
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/dijit.css\";");
}
pw.println(" @import \"/xsp/.ibmxspres/.oneuiv302/oneui/css/base/core.css\";");
pw.println(" @import \"/xsp/.ibmxspres/.oneuiv302/oneui/css/base/dojo.css\";");
pw.println(" @import \"/xsp/.ibmxspres/.oneuiv302/oneui/css/defaultTheme/defaultTheme.css\";");
if(isDojo) {
pw.println(" @import \"/xsp/.ibmxspres/.oneuiv302/oneui/css/defaultTheme/dojoTheme.css\";");
pw.println(" @import \"/xsp/.ibmxspres/.oneuiv302/oneui/dojoTheme/lotusui30dojo/lotusui30dojo.css\";");
}
pw.println(" </style>");
bodyTheme = "lotusui30_body lotusui30_fonts lotusui30 lotusui30dojo";
} else if(StringUtil.equals(theme, "dojo") || StringUtil.equals(theme, "dojo-claro")) {
pw.println(" <style type=\"text/css\">");
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/claro/claro.css\";");
pw.println(" @import \""+jsLibraryPath+"/dojo/resources/dojo.css\";");
pw.println(" </style>");
bodyTheme = "claro";
} else if(StringUtil.equals(theme, "dojo-tundra")) {
pw.println(" <style type=\"text/css\">");
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/tundra/tundra.css\";");
pw.println(" @import \""+jsLibraryPath+"/dojo/resources/dojo.css\";");
pw.println(" </style>");
bodyTheme = "tundra";
} else if(StringUtil.equals(theme, "dojo-soria")) {
pw.println(" <style type=\"text/css\">");
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/soria/soria.css\";");
pw.println(" @import \""+jsLibraryPath+"/dojo/resources/dojo.css\";");
pw.println(" </style>");
bodyTheme = "soria";
} else if(StringUtil.equals(theme, "dojo-nihilo")) {
pw.println(" <style type=\"text/css\">");
pw.println(" @import \""+jsLibraryPath+"/dijit/themes/nihilo/nihilo.css\";");
pw.println(" @import \""+jsLibraryPath+"/dojo/resources/dojo.css\";");
pw.println(" </style>");
bodyTheme = "soria";
}
}
protected void generateHeadJSLibrary(PrintWriter pw) throws IOException {
int jsAggregator = OptionsBean.JS_AGG_NONE;
switch(jsLib.getLibType()) {
case DOJO: {
// Only for the default library (bundled with Domino)
if(jsLib==JavaScriptLibraries.LIBRARIES[0]) {
jsAggregator = OptionsBean.get().getJavaScriptAggregator();
}
switch(jsAggregator) {
case OptionsBean.JS_AGG_NONE:
case OptionsBean.JS_AGG_XPAGES: {
pw.println(" <script type=\"text/javascript\">");
pw.println(" dojoConfig = {");
pw.println(" parseOnLoad: true,");
if(jsLib.isAsync()) {
pw.println(" async: true,");
}
if(debug) {
pw.println(" isDebug: true,");
}
pw.println(" };");
pw.println(" </script>");
String dojoPath = PathUtil.concat(jsLibraryPath,"/dojo/dojo.js",'/');
pw.println(" <script type=\"text/javascript\" src=\""+dojoPath+"\"></script>");
if(jsAggregator==OptionsBean.JS_AGG_XPAGES) {
String xpagesLayer = aggregatorAddModules(serverUrl,requestParams.js,true);
pw.println(" <script type=\"text/javascript\" src=\""+xpagesLayer+"\"></script>");
}
} break;
case OptionsBean.JS_AGG_SDK: {
// Using the dojo layers
//jsLibraryPath = PathUtil.concat(jsLibraryPath,"/dojo/dojo.js",'/');
pw.println(" <script type=\"text/javascript\">");
pw.println(" dojoConfig = {");
pw.println(" parseOnLoad: true,");
if(jsLib.isAsync()) {
pw.println(" async: true,");
}
if(debug) {
pw.println(" isDebug: true,");
}
emitDojoAggregatedConfig(pw, serverUrl);
pw.println(" };");
pw.println(" </script>");
String dojoPath = PathUtil.concat(jsLibraryPath,"/dojo/dojo.js",'/');
pw.println(" <script type=\"text/javascript\" src=\""+dojoPath+"\"></script>");
} break;
}
} break;
case JQUERY: {
if(true) {
String jqueryPath = PathUtil.concat(jsLibraryPath,"/jquery.min",'/');
String jqueryUiPath = PathUtil.concat(jsLibraryPath,"/jquery-ui.min",'/');
//String jqueryUiCssPath = PathUtil.concat(jsLibraryPath,"/themes/base/jquery-ui.css",'/');
String jqueryUiCssPath = "//ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js";
pw.println(" <script type=\"text/javascript\" src=\"/xsp/.ibmxspres/.sbtsdk/js/libs/require.js\"></script>");
pw.println(" <script type=\"text/javascript\">");
pw.println(" requirejs.config({");
pw.println(" paths: {");
pw.println(" 'jquery' : '"+jqueryPath+"',");
pw.println(" 'jqueryui' : '"+jqueryUiPath+"'");
pw.println(" },");
pw.println(" shim: {");
pw.println(" 'jquery/ui': {");
pw.println(" deps: ['jquery'],");
pw.println(" exports: '$'");
pw.println(" }");
pw.println(" }");
pw.println(" });");
pw.println(" </script>");
pw.println(" <link rel=\"stylesheet\" type=\"text/css\" title=\"Style\" href=\""+jqueryUiCssPath+"\">");
} else {
String jqueryPath = PathUtil.concat(jsLibraryPath,"/jquery.min.js",'/');
pw.println(" <script type=\"text/javascript\" src=\"/xsp/.ibmxspres/.sbtsdk/js/libs/require.js\"></script>");
pw.println(" <script type=\"text/javascript\" src=\""+jqueryPath+"\"></script>");
}
} break;
}
// Add the library servlet, if no dojo layer is being used
if(jsAggregator!=OptionsBean.JS_AGG_SDK) {
String libType = jsLib.getLibType().toString();
String libVersion = jsLib.getLibVersion();
pw.print(" <script type=\"text/javascript\" src=\""+composeToolkitUrl(dbUrl)+"?lib="+libType+"&ver="+libVersion);
pw.print("&env=");
pw.print(envName);
pw.println("\"></script>");
//pw.println(" <script type=\"text/javascript\" src=\""+PathUtil.concat(env.getSbt(),"toolkit",'/')+"?ver=1.6.1&\"+(Stringendpoints?endpoints)+"></script>");
}
// Script for the dojo parser
if(isDojo) {
pw.println(" <script>");
pw.println(" require(['dojo/parser']);"); // avoid dojo warning
pw.println(" </script>");
}
}
protected void generateHeadFirebug(PrintWriter pw) throws IOException {
// Add the firebug lite debugging tools
if(debug) {
pw.println(" <script type=\"text/javascript\" src=\"/xsp/.ibmxspres/.extlib/firebug/js/firebug-lite.js\"></script>\n");
}
}
protected void generateBody(PrintWriter pw) throws IOException {
generateBodyTag(pw);
generateCssTags(pw);
generateHtmlTags(pw);
generateErrorTags(pw);
generateJsTags(pw);
pw.println("</body>");
}
protected void generateBodyTag(PrintWriter pw) throws IOException {
pw.print("<body");
if(StringUtil.isNotEmpty(bodyTheme)) {
pw.print(" class=\"");
pw.print(bodyTheme);
pw.print("\"");
}
pw.println(">");
}
protected void generateCssTags(PrintWriter pw) throws IOException {
String css = requestParams.css;
css = ParameterProcessor.process(css, prov);
if(StringUtil.isNotEmpty(css)) {
String s = " <style>"+css+"</style>";
pw.println(s);
}
}
protected void generateJsTags(PrintWriter pw) throws IOException {
String js = requestParams.js;
js = ParameterProcessor.process(js, prov);
if(StringUtil.isNotEmpty(js)) {
String s = "<script>\n"
+js
+"</script>\n";
pw.println(s);
}
}
protected void generateHtmlTags(PrintWriter pw) throws IOException {
// Text content for simple output
String html = "<div id=\"content\"></div>\n";
// Custom HTML
String customHtml = requestParams.html;
html = html + ParameterProcessor.process(customHtml, prov);
// Hidden progress indicator image
html = html + "\n<div id='loading' style='visibility: hidden'><img src='../progressIndicator.gif' alt='loading...'></img></div>";
pw.println(html);
}
protected void generateErrorTags(PrintWriter pw) throws IOException {
pw.print("<div id='_jsErrors'>");
pw.print("</div>");
pw.print("<script type='text/javascript'>");
pw.print(" window.onerror = function(msg, url, linenumber) {");
pw.print(" var d = document.createElement('div');");
pw.print(" d.innerHTML += 'Unhandled error: '+msg.replace('<', '<').replace('>', '>')+'<br> in page: '+url+'<br>at: '+linenumber;");
pw.print(" document.getElementById('_jsErrors').appendChild(d);");
pw.print(" return true;");
pw.print(" }");
pw.print("</script>");
}
protected void emitDojoAggregatedConfig(PrintWriter pw, String serverUrl) throws IOException {
}
protected String aggregatorAddModules(String serverUrl, String js, boolean includeLibraryModules) throws IOException {
// XPages aggregator
ResourceFactory factory = ResourceFactory.get();
DojoLibrary dojoLibrary = DojoLibraryFactory.getDefaultLibrary(false);
String dojoLocale = "en-us";
DojoDependencyList dojoResources = new DojoDependencyList(factory,dojoLibrary,dojoLocale);
aggregatorAddDojoModules(dojoResources);
if(includeLibraryModules) {
aggregatorAddLibraryModules(dojoResources);
}
aggregatorAddJSDependencyModules(dojoResources, js);
StringBuilder b = new StringBuilder();
b.append(MinifierResourceProvider.URL_DOJO);
if(dojoLibrary.isUncompressed() || dojoLibrary!=DojoLibraryFactory.getDefaultLibrary(false)) {
b.append('-');
b.append(dojoLibrary.getVersionTag());
}
b.append('/');
b.append(dojoResources.getUrlParameter());
b.append(".js"); // $NON-NLS-1$
String fullUrl = b.toString();
String dojoAgg = PathUtil.concat(serverUrl, fullUrl, '/');
return dojoAgg;
}
protected void aggregatorAddDojoModules(DojoDependencyList dojoResources) throws IOException {
ResourceFactory factory = dojoResources.getFactory();
DojoLibrary dojoLibrary = dojoResources.getDojoLibrary();
// Common dojo resources
dojoResources.addResource(factory.getDojoResource("dojo.parser",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.date",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.date.locale",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.regexp",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.i18n",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.string",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.cache",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.text",dojoLibrary));
// Controls
dojoResources.addResource(factory.getDojoResource("dijit._WidgetBase",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dijit._TemplatedMixin",dojoLibrary));
dojoResources.addResource(factory.getDojoResource("dojo.touch",dojoLibrary));
}
protected void aggregatorAddLibraryModules(DojoDependencyList dojoResources) throws IOException {
}
protected void aggregatorAddJSDependencyModules(DojoDependencyList dojoResources, String js) throws IOException {
ResourceFactory factory = dojoResources.getFactory();
DojoLibrary dojoLibrary = dojoResources.getDojoLibrary();
//if(includeSDKModules) {
// Extract the entries from the JS file
// This might be in the SDK layer already, so we don't load them if not fully using the XPages agg but the SDK one
if(StringUtil.isNotEmpty(js)) {
Matcher matcher = amdRequireRegEx.matcher(js);
while(matcher.find()) {
String s = matcher.group(1);
Matcher matcher2 = amdRequireRegEx2.matcher(s);
while(matcher2.find()) {
String mod = StringUtil.replace(matcher2.group(1),'/','.');
DojoResource res = factory.getDojoResource(mod,dojoLibrary);
if(res!=null) {
dojoResources.addResource(res);
}
}
}
}
}
}
}