/* * © Copyright IBM Corp. 2012 * * 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.ibm.sbt.jslibrary.servlet; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import com.ibm.commons.runtime.Context; 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.json.JsonGenerator; 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.JsonReference; import com.ibm.sbt.jslibrary.SBTEnvironment.Property; import com.ibm.sbt.service.proxy.Proxy; import com.ibm.sbt.service.proxy.ProxyConfigException; import com.ibm.sbt.service.proxy.ProxyFactory; import com.ibm.sbt.services.client.ClientServicesException; import com.ibm.sbt.services.endpoints.Endpoint; import com.ibm.sbt.services.endpoints.EndpointFactory; import com.ibm.sbt.services.endpoints.GadgetOAuthEndpoint; import com.ibm.sbt.services.endpoints.OAuth2Endpoint; import com.ibm.sbt.services.endpoints.OAuthEndpoint; import com.ibm.sbt.services.endpoints.js.JSReference; import com.ibm.sbt.services.util.AuthUtil; import com.ibm.sbt.util.SBTException; /** * Handles initialising the Social Business Toolkit library with the appropriate bridge to the underlying JavaScript library i.e. dojo or jquery or ... This class need to be thread safe, only a single instance will be created. * * @author mwallace * @author cmanias */ abstract public class AbstractLibrary { private final String libraryName; private final String minimumVersion; private final String maximumVersion; public static boolean minify = false; public static final String REFERER = "Referer"; //$NON-NLS-1$ public static final String APPLICATION_JAVASCRIPT = "application/javascript"; //$NON-NLS-1$ public static final String UTF8 = "utf-8"; //$NON-NLS-1$ public static final String PROP_API_VERSION = "apiVersion"; public static final String PROP_TRANSPORT = "transport"; public static final String PROP_INVALID = "invalid"; public static final String PROP_AUTHENTICATOR = "authenticator"; public static final String PROP_PROXY_PATH = "proxyPath"; public static final String PROP_PROXY = "proxy"; public static final String PROP_BASE_URL = "baseUrl"; public static final String PROP_TOOLKIT_URL = "sbtUrl"; public static final String PROP_SERVICE_URL = "serviceUrl"; public static final String PROP_LIBRARY_URL = "libraryUrl"; public static final String PROP_AUTH_TYPE = "authType"; public static final String PROP_LOGIN_PAGE = "loginPage"; public static final String PROP_LOGIN_DIALOG_PAGE = "loginDialogPage"; public static final String PROP_LOGIN_UI = "loginUi"; public static final String PROP_AUTO_AUTHENTICATE = "autoAuthenticate"; public static final String IS_AUTHENTICATED = "isAuthenticated"; public static final String PROP_AUTHENTICATION_ERROR_CODE = "authenticationErrorCode"; public static final String PROP_ENDPOINT_ALIAS = "name"; public static final String PROP_PLATFORM = "platform"; public static final String PROP_SERVICE_MAPPINGS = "serviceMappings"; public static final String PROP_MODULE_PREFIX = "_module"; public static final String PROP_MODULE_AUTHENTICATOR = "_moduleAuthenticator"; public static final String PROP_MODULE_TRANSPORT = "_moduleTransport"; public static final String PROP_MODULE_PROXY = "_moduleProxy"; public static final String REF_SBT_TRANSPORT = "sbtTransport"; public static final String REF_ERR_TRANSPORT = "errTransport"; public static final String REF_SBT_PROXY = "sbtProxy"; public static final String REF_SBT_AUTHENTICATOR = "sbtAuthenticator"; public static final String MODULE_SBT = "sbt"; public static final String MODULE_SBTX = "sbtx"; public static final String MODULE_DECLARE = "sbt/_bridge/declare"; public static final String MODULE_IFRAMETRANSPORT = "sbt/_bridge/IFrameTransport"; public static final String MODULE_TRANSPORT = "sbt/_bridge/Transport"; public static final String MODULE_REQUESTTRANSPORT = "sbt/_bridge/RequestTransport"; public static final String MODULE_MOCK_TRANSPORT = "sbt/MockTransport"; public static final String MODULE_DEBUG_TRANSPORT = "sbt/DebugTransport"; public static final String MODULE_ERROR_TRANSPORT = "sbt/ErrorTransport"; public static final String MODULE_GADGET_TRANSPORT = "sbt/GadgetTransport"; public static final String MODULE_CACHE = "sbt/Cache"; public static final String MODULE_CONFIG = "sbt/config"; public static final String MODULE_CONFIG_LAYER = "sbt/_config"; public static final String MODULE_DOM = "sbt/dom"; public static final String MODULE_ENDPOINT = "sbt/Endpoint"; public static final String MODULE_GADGET = "sbt/Gadget"; public static final String MODULE_IWIDGET = "sbt/IWidget"; public static final String MODULE_JSONPATH = "sbt/jsonpath"; public static final String MODULE_LANG = "sbt/lang"; public static final String MODULE_PORTLET = "sbt/Portlet"; public static final String MODULE_PROXY = "sbt/Proxy"; public static final String MODULE_WPS_PROXY = "sbt/WPSProxy"; public static final String MODULE_XML = "sbt/xml"; public static final String MODULE_XPATH = "sbt/xpath"; public static final String MODULE_XSL = "sbt/xsl"; public static final String MODULE_BASIC = "sbt/authenticator/Basic"; public static final String MODULE_OAUTH = "sbt/authenticator/OAuth"; public static final String MODULE_UTIL = "sbt/util"; public static final String PATH_SBT = "sbt"; //$NON-NLS-1$ public static final String PATH_SBTX = "sbtx"; //$NON-NLS-1$ private static final String PADDING = " "; private static final String NL = "\n"; private static String nl = NL; private static final String[][] REGISTER_EXT_MODULES = { { MODULE_SBTX, PATH_SBTX } }; static final String sourceClass = AbstractLibrary.class.getName(); static final Logger logger = Logger.getLogger(sourceClass); /** * This is used to determine how to generate the module URL * */ protected enum ModuleType { SBT_MODULE, SBTX_MODULE, JS_LIBRARY }; /** * @param libraryName * @param minimumVersion * @param maximumVersion * @throws ClassNotFoundException */ public AbstractLibrary(String libraryName, String minimumVersion, String maximumVersion) { this.libraryName = libraryName; this.minimumVersion = normalizeVersion(minimumVersion); this.maximumVersion = normalizeVersion(maximumVersion); } /** * Return true if the associated <code>BaseLibrary</code> can handle this request. * * @param request * @return true if the associated <code>BaseLibrary</code> can handle this request */ public boolean isMatch(LibraryRequest request) { String jsLib = request.getJsLib(); if (!libraryName.equals(jsLib)) { return false; } String jsVersion = request.getJsVersion(); if (!StringUtil.isEmpty(jsVersion) && !isSupportedVersion(jsVersion)) { return false; } return true; } /** * * @param request * @return String * @throws LibraryException */ public String generateJavaScript(LibraryRequest request) throws LibraryException { try { // populate list of endpoint/properties Map<String, JsonObject> endpoints = populateEndpoints(request); JsonObject properties = populateProperties(request); minify = !request.isDebug(); nl = minify ? "" : NL; // concrete library generates the script return generateJavaScript(request, endpoints, properties); } catch (Exception e) { throw new LibraryException(e); } } /** * @param request * @throws LibraryException */ protected void doGet(LibraryRequest request) throws LibraryException { if (logger.isLoggable(Level.FINEST)) { logger.entering(sourceClass, "doGet", request); } try { // populate list of endpoint/properties Map<String, JsonObject> endpoints = populateEndpoints(request); JsonObject properties = populateProperties(request); minify = !request.isDebug(); nl = minify ? "" : NL; // write response HttpServletResponse response = request.getHttpResponse(); PrintWriter writer = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), UTF8)); try { // concrete library generates the script String script = generateJavaScript(request, endpoints, properties); // response is of type aplication/javascript response.setStatus(HttpServletResponse.SC_OK); response.setContentType(APPLICATION_JAVASCRIPT); writer.write(script); } finally { writer.flush(); } } catch (Exception e) { throw new LibraryException(e); } if (logger.isLoggable(Level.FINEST)) { logger.exiting(sourceClass, "doGet"); } } /** * * @return String */ protected String newLine(){ return nl; } /** * @param sb */ protected StringBuilder indent(StringBuilder sb) { return indent(sb, 1); } /** * @param sb * @param ammount */ protected StringBuilder indent(StringBuilder sb, int ammount) { for (int i = 0; !minify && i < ammount; i++) { sb.append(PADDING); } return sb; } /** * @param request * @throws ServletException * @throws IOException */ protected Map<String, JsonObject> populateEndpoints(LibraryRequest request) throws LibraryException { if (logger.isLoggable(Level.FINEST)) { logger.entering(sourceClass, "populateEndpoints", request); } Map<String, JsonObject> jsonEndpoints = new HashMap<String, JsonObject>(); // Read the list of endpoint com.ibm.sbt.jslibrary.SBTEnvironment.Endpoint[] endpoints = request.getEnvironment().getEndpointsArray(); if (endpoints != null) { for (com.ibm.sbt.jslibrary.SBTEnvironment.Endpoint endpoint : endpoints) { String endpointAlias = endpoint.getAlias(); String endpointName = endpoint.getName(); // is an alias in use? if (endpointAlias == null) { endpointAlias = endpointName; } Endpoint theEndpoint = EndpointFactory.getEndpointUnchecked(endpointName); JsonObject jsonEndpoint = createJsonForEndpoint(request, theEndpoint, endpointAlias, endpointName); jsonEndpoints.put(endpointAlias, jsonEndpoint); } } if (logger.isLoggable(Level.FINEST)) { logger.exiting(sourceClass, "populateEndpoints", endpoints); } return jsonEndpoints; } private JsonReference addMakeAbsoluteUrl(String url){ StringBuilder sb = new StringBuilder("util.makeAbsoluteUrl('").append(url).append("')"); return new JsonReference(sb.toString()); } /** * @param request * @return JsonObject * @throws ServletException * @throws IOException */ protected JsonObject populateProperties(LibraryRequest request) throws ServletException, IOException { if (logger.isLoggable(Level.FINEST)) { logger.entering(sourceClass, "populateProperties", request); } JsonObject jsonProperties = new JsonJavaObject(); // add the built-in properties jsonProperties.putJsonProperty(PROP_TOOLKIT_URL, addMakeAbsoluteUrl(request.getToolkitJsUrl())); jsonProperties.putJsonProperty(PROP_SERVICE_URL, addMakeAbsoluteUrl(request.getServiceUrl())); jsonProperties.putJsonProperty(PROP_LIBRARY_URL, addMakeAbsoluteUrl(request.getLibraryUrl())); // add the requested properties Property[] properties = request.getEnvironment().getPropertiesArray(); if (properties != null) { Context context = Context.get(); for (Property property : properties) { String value = property.getValue(); if (StringUtil.isEmpty(value)) { value = context.getProperty(property.getName()); } if (value != null) { jsonProperties.putJsonProperty(property.getName(), value); } } } if (logger.isLoggable(Level.FINEST)) { logger.exiting(sourceClass, "populateProperties", properties); } return jsonProperties; } /** * @param request * @param endpoint * @param endpointAlias * @param endpointName * * TODO: Need a unit test for this method */ protected JsonObject createJsonForEndpoint(LibraryRequest request, Endpoint endpoint, String endpointAlias, String endpointName) throws LibraryException { if (logger.isLoggable(Level.FINEST)) { logger.entering(sourceClass, "createJsonForEndpoint", new Object[] { request, endpoint, endpointAlias, endpointName }); } JsonObject jsonEndpoint = new JsonJavaObject(); // use the base url from the endpoint if (isValid(request, endpoint)) { // set the endpoint api version String apiVersion = endpoint.getApiVersion(); if (StringUtil.isNotEmpty(apiVersion)) { jsonEndpoint.putJsonProperty(PROP_API_VERSION, apiVersion); } jsonEndpoint.putJsonProperty(PROP_ENDPOINT_ALIAS, endpointAlias); // set the endpoint url jsonEndpoint.putJsonProperty(PROP_BASE_URL, endpoint.getUrl()); try { jsonEndpoint.putJsonProperty(IS_AUTHENTICATED, endpoint.isAuthenticated()); } catch (ClientServicesException e) { jsonEndpoint.putJsonProperty(IS_AUTHENTICATED, false); } jsonEndpoint.putJsonProperty(PROP_SERVICE_MAPPINGS, endpoint.getServiceMappings()); // configure endpoint to use proxy if (endpoint.isUseProxy()) { JsonReference proxyRef = createProxyRef(request, endpoint, endpointName); if (proxyRef != null) { jsonEndpoint.putJsonProperty(PROP_PROXY, proxyRef); String moduleName = getProxy(request, endpoint, endpointName).getModuleName(); jsonEndpoint.putJsonProperty(PROP_MODULE_PROXY, moduleName); } String proxyPath = endpoint.getProxyPath(endpointName); if (!StringUtil.isEmpty(proxyPath)) { jsonEndpoint.putJsonProperty(PROP_PROXY_PATH, proxyPath); } } // configure endpoint to use authenticator JsonReference authenticatorRef = createAuthenticatorRef(request, endpoint, endpointName); if (authenticatorRef != null) { jsonEndpoint.putJsonProperty(PROP_AUTHENTICATOR, authenticatorRef); String moduleName = endpoint.getAuthenticator(endpointName, request.getToolkitJsUrl()).getModuleName(); jsonEndpoint.putJsonProperty(PROP_MODULE_AUTHENTICATOR, moduleName); } // configure the transport JsonReference transportRef = createTransportRef(request, endpoint, endpointName); if (transportRef != null) { jsonEndpoint.putJsonProperty(PROP_TRANSPORT, transportRef); String moduleName = getTransport(request, endpoint, endpointName).getModuleName(); jsonEndpoint.putJsonProperty(PROP_MODULE_TRANSPORT, moduleName); } // configure the authentication jsonEndpoint.putJsonProperty(PROP_AUTH_TYPE, AuthUtil.INSTANCE.getAuthValue(endpoint)); if (endpoint.getLoginPage() != null) { jsonEndpoint.putJsonProperty(PROP_LOGIN_PAGE, endpoint.getLoginPage()); } if (endpoint.getDialogLoginPage() != null) { jsonEndpoint.putJsonProperty(PROP_LOGIN_DIALOG_PAGE, endpoint.getDialogLoginPage()); } if (endpoint.getLoginUi() != null) { jsonEndpoint.putJsonProperty(PROP_LOGIN_UI, endpoint.getLoginUi()); } if (endpoint.getAutoAuthenticate() != null) { jsonEndpoint.putJsonProperty(PROP_AUTO_AUTHENTICATE, endpoint.getAutoAuthenticate()); } if (endpoint.getPlatform() != null) { jsonEndpoint.putJsonProperty(PROP_PLATFORM, endpoint.getPlatform()); } jsonEndpoint.putJsonProperty(PROP_AUTHENTICATION_ERROR_CODE, endpoint.getAuthenticationErrorCode()); // configure client properties Map<String, Object> params = endpoint.getClientParams(); Iterator<String> keys = params.keySet().iterator(); while(keys.hasNext()) { String key = keys.next(); Object value = params.get(key); jsonEndpoint.putJsonProperty(key, value); } } else { // set the endpoint url jsonEndpoint.putJsonProperty(PROP_INVALID, "true"); // configure a error transport String message = getInvalidEndpointMessage(request, endpoint, endpointName); jsonEndpoint.putJsonProperty(PROP_TRANSPORT, new JsonReference("new ErrorTransport('" + endpointName + "','" + message + "')")); } if (logger.isLoggable(Level.FINEST)) { logger.exiting(sourceClass, "createJsonForEndpoint", jsonEndpoint); } return jsonEndpoint; } protected StringBuilder generateModuleBlock(LibraryRequest request, String[][] registerModules, String[][] registerExtModules, String[] requireModules, int indentationLevel) { StringBuilder sb = new StringBuilder(); // register the module paths and required modules generateRegisterModules(sb, indentationLevel, request, registerModules, ModuleType.SBT_MODULE); if (registerExtModules != null) { generateRegisterModules(sb, indentationLevel, request, registerExtModules, ModuleType.SBTX_MODULE); } generateRequireModules(sb, indentationLevel, requireModules); return sb; } /** * @param request * @param endpoints * @param properties * @param indentationLevel * @return StringBuilder * @throws LibraryException */ protected StringBuilder generateSbtConfigDefine(LibraryRequest request, Map<String, JsonObject> endpoints, JsonObject properties, int indentationLevel) throws LibraryException { StringBuilder sb = new StringBuilder(); // open the define invocation String[] dependModules = getDependModules(request, endpoints); String[] moduleNames = getModuleNames(dependModules); String dmList = toQuotedString(dependModules, ","); String dmNames = toString(moduleNames, ","); indent(sb, indentationLevel).append("define('").append(request.isLayer()?getDefineModuleLayer():getDefineModule()).append("',[") .append(dmList).append("],function(").append(dmNames).append("){").append(newLine()); indentationLevel++; // Create the sbt object indent(sb, indentationLevel).append("var sbt = {};").append(newLine()); // define the properties Iterator<String> jsonProps = properties.getJsonProperties(); if (jsonProps.hasNext()) { indent(sb, indentationLevel).append("sbt.Properties=").append(toJson(properties)).append(";").append(newLine()); } // define the endpoints if (!endpoints.isEmpty()) { indent(sb, indentationLevel).append("sbt.Endpoints={").append(newLine()); Iterator<Map.Entry<String, JsonObject>> entrySet = endpoints.entrySet().iterator(); indentationLevel++; while (entrySet.hasNext()) { Map.Entry<String, JsonObject> entry = entrySet.next(); String name = entry.getKey(); JsonObject endpoint = entry.getValue(); JsonObject endpointParams = removeModuleProperties(endpoint); indent(sb, indentationLevel).append("'").append(toJavaScriptString(name)) .append("':new Endpoint(").append(toJson(endpointParams)).append(")"); if (entrySet.hasNext()) { sb.append(",").append(newLine()); } else { sb.append(newLine()); indentationLevel--; indent(sb, indentationLevel).append("};").append(newLine()); // Close sbt.Endpoints={ } } } // define the sbt.findEndpoint(endpointName) function indent(sb, indentationLevel).append("sbt.findEndpoint=function(endpointName) {\n"); indentationLevel++; indent(sb, indentationLevel).append("return this.Endpoints[endpointName];\n"); indentationLevel--; indent(sb, indentationLevel).append("};\n"); // close define invocation indent(sb, indentationLevel).append("return sbt;").append(newLine()); indentationLevel--; indent(sb, indentationLevel).append("});").append(newLine()); return sb; } /** * Generate the JavaScript to be returned for the specified <code>LibraryRequest</code> * * @param request * LibraryRequest for which the script is being created * @param endpoints * Map of JSonObjects representing the endpoints to be created in the JavaScript * @param properties * JSonObject representing the properties to be included in the script * @throws LibraryException * if an error occurs while generating the JavaScript */ protected String generateJavaScript(LibraryRequest request, Map<String, JsonObject> endpoints, JsonObject properties) throws LibraryException { if (logger.isLoggable(Level.FINEST)) { logger.entering(sourceClass, "generateJavaScript", new Object[] { request, endpoints, properties }); } StringBuilder sb = new StringBuilder(); int indentationLevel = 1; if (request.isInitJs()) { if (!request.isRegPath()) { sb.append("dojo.provide(\"sbt.config\");").append(newLine()); } else { sb.append(generateProvide()).append(newLine()); } sb.append("(function() {").append(newLine()); } // make sure the library is only defined once (open if) sb.append("if(typeof _sbt=='undefined' || window._sbt_bridge_compat){").append(newLine()); indent(sb).append("_sbt=0;").append(newLine()); boolean closeElse = false; boolean isInnerBlock = false; if (!request.isLayer()) { if (enableDefineCheck(request.getJsVersion())) { indent(sb).append("if(typeof define=='undefined'){").append(newLine()); String[][] registerModules = getRegisterModules(request); String[][] registerExtModules = StringUtil.isNotEmpty(request.getToolkitExtUrl()) ? getRegisterExtModules(request) : null; String[] requireModules = getRequireModules(); indentationLevel++; sb.append(generateModuleBlock(request, registerModules, registerExtModules, requireModules, indentationLevel)); indentationLevel--; indent(sb).append("} else {").append(newLine()); closeElse = true; isInnerBlock = true; } // register the module paths and required modules String[][] registerModulesAmd = getRegisterModulesAmd(request); String toolkitExtUrl = request.getToolkitExtUrl(); String[][] registerExtModulesAmd = StringUtil.isNotEmpty(toolkitExtUrl) ? getRegisterExtModulesAmd(request) : null; String[] requireModulesAmd = getRequireModulesAmd(); if (isInnerBlock) { indentationLevel++; } sb.append(generateModuleBlock(request, registerModulesAmd, registerExtModulesAmd, requireModulesAmd, indentationLevel)); if (isInnerBlock) { indentationLevel--; } if (closeElse) { indent(sb).append("}").append(newLine()); } } sb.append(generateSbtConfigDefine(request, endpoints, properties, indentationLevel)); sb.append("}").append(newLine()); if (request.isInitJs()) { sb.append("})();").append(newLine()); } if (logger.isLoggable(Level.FINEST)) { logger.exiting(sourceClass, "generateJavaScript", sb.toString()); } return sb.toString(); } /** * @param sb * @param requireModules */ protected void generateRequireModules(StringBuilder sb, int indentationLevel, String[] requireModules) { for (String requireModule : requireModules) { indent(sb, indentationLevel).append(generateRequire(requireModule)); } } /** * @param sb * @param request * @param registerModules */ protected void generateRegisterModules(StringBuilder sb, int indentationLevel, LibraryRequest request, String[][] registerModules, ModuleType type) { if (registerModules == null || !request.isRegPath()) { return; } for (String[] registerModule : registerModules) { String moduleUrl = getModuleUrl(request, registerModule[1], type); indent(sb, indentationLevel).append( generateRegisterModulePath(request, registerModule[0], moduleUrl)); } } /** * @param request * @param endpoints * @return String[] */ protected String[] getDependModules(LibraryRequest request, Map<String, JsonObject> endpoints) { List<String> modules = new ArrayList<String>(); Collection<JsonObject> jsonObjects = endpoints.values(); for (JsonObject jsonObject : jsonObjects) { if (jsonObject.getJsonProperty(PROP_INVALID) != null) { // add the error transport if (!modules.contains(MODULE_ERROR_TRANSPORT)) { modules.add(MODULE_ERROR_TRANSPORT); } } else { // is proxy being used for this endpoint if (jsonObject.getJsonProperty(PROP_PROXY) != null) { // add proxy module if not already in the list String proxyModule = (String) jsonObject.getJsonProperty(PROP_MODULE_PROXY); if (StringUtil.isEmpty(proxyModule)) { proxyModule = MODULE_PROXY; } if (!modules.contains(proxyModule)) { modules.add(proxyModule); } } // which transport is being used for this endpoint if (jsonObject.getJsonProperty(PROP_TRANSPORT) != null) { String transportModule = (String) jsonObject.getJsonProperty(PROP_MODULE_TRANSPORT); // add the transport module to the list if (!modules.contains(transportModule)) { modules.add(transportModule); } } // is an authenticator being used for this endpoint if (jsonObject.getJsonProperty(PROP_AUTHENTICATOR) != null) { String authenticatorModule = (String) jsonObject .getJsonProperty(PROP_MODULE_AUTHENTICATOR); // add the authenticator module to the list if (!modules.contains(authenticatorModule)) { modules.add(authenticatorModule); } } } // add endpoint module is not already in the list if (!modules.contains(MODULE_ENDPOINT)) { modules.add(MODULE_ENDPOINT); } } modules.add(MODULE_UTIL); return modules.toArray(new String[modules.size()]); } protected String getModuleUrl(LibraryRequest request, String modulePath, ModuleType type) { if (logger.isLoggable(Level.FINEST)) { logger.entering(sourceClass, "getModuleUrl", new Object[] { request, modulePath }); } String jsUrl = ""; String moduleUrl = ""; switch (type) { case SBT_MODULE: jsUrl = request.getToolkitJsUrl(); break; case SBTX_MODULE: jsUrl = request.getToolkitExtJsUrl(); break; case JS_LIBRARY: jsUrl = request.getJsLibraryUrl(); break; default: moduleUrl = modulePath; break; } moduleUrl = moduleUrl.isEmpty() ? PathUtil.concat(jsUrl, modulePath, '/') : moduleUrl; if (logger.isLoggable(Level.FINEST)) { logger.exiting(sourceClass, "getModuleUrl", moduleUrl); } return moduleUrl; } /** * @param properties * @return String * @throws LibraryException */ protected String toJson(JsonObject properties) throws LibraryException { try { return JsonGenerator.toJson(JsonJavaFactory.instanceEx, properties, true); } catch (Exception e) { throw new LibraryException(e); } } /** * @param modules * @return module names String[] */ protected String[] getModuleNames(String[] modules) { List<String> names = new ArrayList<String>(); for (String module : modules) { names.add(getModuleParamName(module)); } return names.toArray(new String[names.size()]); } /** * @param module * @return String */ protected String getModuleParamName(String module) { int index = module.lastIndexOf('/'); if (index != -1) { module = module.substring(index + 1); } return module; } /** * @param array * @param delim * @return String */ protected String toQuotedString(String[] array, String delim) { StringBuilder sb = new StringBuilder(); int count = 0; for (String str : array) { if (count > 0) { sb.append(delim); } sb.append("'").append(str).append("'"); count++; } return sb.toString(); } /** * @param array * @param delim * @return String */ protected String toString(String[] array, String delim) { StringBuilder sb = new StringBuilder(); int count = 0; for (String str : array) { if (count > 0) { sb.append(delim); } sb.append(str); count++; } return sb.toString(); } /** * Convert the endpoint json to a new object which can be used to create endpoint parameters * * @param jsonObject * @return JsonObject */ protected JsonObject removeModuleProperties(JsonObject jsonObject) { JsonObject params = new JsonJavaObject(); Iterator<String> properties = jsonObject.getJsonProperties(); while (properties.hasNext()) { // add regular properties String property = properties.next(); if (!property.startsWith(PROP_MODULE_PREFIX)) { params.putJsonProperty(property, jsonObject.getJsonProperty(property)); } } return params; } /** * @param endpoint * @param logicalName * @return JsonReference * @throws LibraryException */ protected JsonReference createAuthenticatorRef(LibraryRequest request, Endpoint endpoint, String logicalName) throws LibraryException { JSReference authenticator = endpoint.getAuthenticator(logicalName, request.getToolkitJsUrl()); if (authenticator != null) { try { Map<String, Object> params = authenticator.getProperties(); Iterator<String> keys = params.keySet().iterator(); StringBuilder sb = new StringBuilder(); String paramName = getModuleParamName(authenticator.getModuleName()); sb.append("new ").append(paramName).append("({"); while(keys.hasNext()) { String key = keys.next(); String value = (String)params.get(key); sb.append(key).append(":").append(addMakeAbsoluteUrl(value).getRef()); if (keys.hasNext()) { sb.append(","); } } sb.append("})"); return new JsonReference(sb.toString()); } catch (Exception e) { throw new LibraryException(e); } } return null; } /** * @param request * @param endpoint * @param logicalName * @return JsonReference * @throws LibraryException */ protected JsonReference createTransportRef(LibraryRequest request, Endpoint endpoint, String logicalName) throws LibraryException { JSReference transport = getTransport(request, endpoint, logicalName); if (transport != null) { try { String paramValues = JsonGenerator.toJson(JsonJavaFactory.instanceEx, transport.getProperties()); String paramName = getModuleParamName(transport.getModuleName()); return new JsonReference("new " + paramName + "(" + paramValues + ")"); } catch (Exception e) { throw new LibraryException(e); } } return null; } /* * Return the JSReference for the Transport module to use */ protected JSReference getTransport(LibraryRequest request, Endpoint endpoint, String endpointName) { return endpoint.getTransport(endpointName, getDefaultTransport(request)); } /* * Return the JSReference for the Proxy module to use */ protected JSReference getProxy(LibraryRequest request, Endpoint endpoint, String endpointName) { return endpoint.getProxy(endpointName, getDefaultProxy(request)); } /* * Return the JSReference for the Transport module to use */ protected String getDefaultTransport(LibraryRequest request) { if (request.isDebugTransport()) { return MODULE_DEBUG_TRANSPORT; } else if (request.isMockTransport()) { return MODULE_MOCK_TRANSPORT; } return MODULE_TRANSPORT; } /* * Return the JSReference for the Proxy module to use */ protected String getDefaultProxy(LibraryRequest request) { return MODULE_PROXY; } /* * Return true if the endpoint is valid for the specified request */ protected boolean isValid(LibraryRequest request, Endpoint endpoint) { if (endpoint == null) { return false; } if (!endpoint.isAllowClientAccess()) { return false; } try { endpoint.checkValid(); return true; } catch(SBTException ex) { return false; } } /* * */ protected boolean useGadgetTransport(Endpoint endpoint) { if (endpoint instanceof GadgetOAuthEndpoint) { return true; } return false; } /* * Return error message to be associated with an invalid endpoint */ protected String getInvalidEndpointMessage(LibraryRequest request, Endpoint endpoint, String logicalName) { if(endpoint!=null) { if (useGadgetTransport(endpoint)) { String serviceName = getServiceName(endpoint); if (StringUtil.isEmpty(serviceName)) { return "OAuth service name not available for: " + logicalName; } } if (!endpoint.isAllowClientAccess()) { return "Client access disallowed for: " + logicalName; } try { endpoint.checkValid(); } catch(SBTException ex) { return ex.getMessage(); } } return "Required endpoint is not available: " + logicalName; } /* * @param endpoint * @return */ protected String getServiceName(Endpoint endpoint) { if (endpoint instanceof OAuthEndpoint) { return ((OAuthEndpoint) endpoint).getServiceName(); } else if (endpoint instanceof OAuth2Endpoint) { return ((OAuth2Endpoint) endpoint).getServiceName(); } return null; } /** * @param request * @param endpoint * @return JsonReference * @throws LibraryException */ protected JsonReference createProxyRef(LibraryRequest request, Endpoint endpoint, String logicalName) throws LibraryException { // If a proxy config has been defined explicitly for the endpoint use it if(endpoint.getProxyConfig()!=null){ Proxy proxy; try { proxy = ProxyFactory.getProxyConfig(endpoint.getProxyConfig()); String proxyUrl = proxy.getProxyUrl(); if(!(UrlUtil.isAbsoluteUrl(proxyUrl))){ // if proxy url specified in proxy config is relative, assume server same as of SBT // Url is relative, append server to it proxyUrl = UrlUtil.makeUrlAbsolute(request.getHttpRequest(),proxyUrl); } proxyUrl = addMakeAbsoluteUrl(proxyUrl).getRef(); String proxyClass = proxy.getProxyModule(); return new JsonReference("new "+proxyClass+"({proxyUrl:" + proxyUrl + "})"); } catch (ProxyConfigException e) { if (logger.isLoggable(Level.SEVERE)) { logger.entering(sourceClass, "createProxyRef failed", e.getMessage()); } } } // define the proxy URL if (endpoint.isUseProxy()) { String proxyUrl = PathUtil.concat(request.getServiceUrl(), endpoint.getProxyHandlerPath(), '/'); proxyUrl = addMakeAbsoluteUrl(proxyUrl).getRef(); return new JsonReference("new Proxy({proxyUrl:" + proxyUrl + "})"); } return null; } /** * @param endpoints * @return boolean */ protected boolean invalidEndpoints(Map<String, JsonObject> endpoints) { Collection<JsonObject> jsonObjects = endpoints.values(); for (JsonObject jsonObject : jsonObjects) { String baseUrl = (String) jsonObject.getJsonProperty(PROP_BASE_URL); if (StringUtil.isEmpty(baseUrl)) { return true; } } return false; } /** * @param endpoints * @return boolean */ protected boolean validEndpoints(Map<String, JsonObject> endpoints) { Collection<JsonObject> jsonObjects = endpoints.values(); for (JsonObject jsonObject : jsonObjects) { String baseUrl = (String) jsonObject.getJsonProperty(PROP_BASE_URL); if (!StringUtil.isEmpty(baseUrl)) { return true; } } return false; } /* * Return true if the version is supported by this library */ protected boolean isSupportedVersion(String version) { version = normalizeVersion(version); if (StringUtil.isEmpty(version)) { return true; } if (!StringUtil.isEmpty(minimumVersion)) { if (version.compareTo(minimumVersion) < 0) { return false; } } if (!StringUtil.isEmpty(maximumVersion)) { if (version.compareTo(maximumVersion) > 0) { return false; } } return true; } /* * Return true if the version is supported by this library */ protected boolean isExceedsVersion(String version, String normalizedMinimumVersion) { version = normalizeVersion(version); if (StringUtil.isEmpty(version)) { return false; } if (!StringUtil.isEmpty(normalizedMinimumVersion)) { if (version.compareTo(normalizedMinimumVersion) >= 0) { return true; } } return false; } /* * Normalize the version number to simplify matching */ protected String normalizeVersion(String version) { if (StringUtil.isEmpty(version)) { return ""; } String[] split = StringUtil.splitString(version, '.'); StringBuilder sb = new StringBuilder(); for (String part : split) { sb.append(String.format("%4s", part)); } return sb.toString(); } /** * @return String[][] */ protected String[][] getRegisterExtModules(LibraryRequest request) { return REGISTER_EXT_MODULES; } /** * @return String[][] */ protected String[][] getRegisterExtModulesAmd(LibraryRequest request) { return REGISTER_EXT_MODULES; } // // Abstract stuff // /** * */ abstract public boolean enableDefineCheck(String version); /** * Return the library name * * @return the library name */ abstract public String getName(); /** * @return String[][] */ abstract protected String[][] getRegisterModules(LibraryRequest request); /** * @return String[][] */ abstract protected String[][] getRegisterModulesAmd(LibraryRequest request); /** * @return String */ abstract protected String getDefineModule(); /** * @return String */ abstract protected String getDefineModuleLayer(); /** * @return String[] */ abstract protected String[] getRequireModules(); /** * @return String[] */ abstract protected String[] getRequireModulesAmd(); /** * @param request * TODO * @return String */ abstract protected String generateRegisterModulePath(LibraryRequest request, String moduleName, String moduleUrl); /** * @return String */ abstract protected String generateRequire(String module); /** * @return String */ abstract protected String generateProvide(); // // Internals // // // JavaScript generation utilities // /** Minimum printable ASCII character */ private static final int ASCII_MIN = 32; /** Maximum printable ASCII character */ private static final int ASCII_MAX = 126; /** * Utility for changing a string so that its compatbile in javascript and does not prevent backslashes * * @param b * @param s * converted to comply with javascript */ public static void appendJavaScriptString(StringBuilder b, String s) { appendJavaScriptString(b, s, false); } /** * Utility for changing a string so that its compatbile in javascript * * @param b * String being constructed * @param s * converted to comply with javascript * @param preventBackslash */ public static void appendJavaScriptString(StringBuilder b, String s, boolean preventBackslash) { int length = s.length(); for (int i = 0; i < length; i++) { char c = s.charAt(i); switch (c) { case '\b': b.append("\\b");break; //$NON-NLS-1$ case '\t': b.append("\\t");break; //$NON-NLS-1$ case '\n': b.append("\\n");break; //$NON-NLS-1$ case '\f': b.append("\\f");break; //$NON-NLS-1$ case '\r': b.append("\\r");break; //$NON-NLS-1$ case '\'': b.append("\\'");break; //$NON-NLS-1$ case '\"': b.append("\\\"");break; //$NON-NLS-1$ case '\\': if (!preventBackslash) { b.append("\\\\");}break; //$NON-NLS-1$ default: { if ((c < ASCII_MIN) || (c > ASCII_MAX)) { b.append("\\u"); //$NON-NLS-1$ b.append(StringUtil.toUnsignedHex(c, 4)); } else { b.append(c); } } } } } /** * Utility for changing a string so that its compatbile in javascript * * @param s * to convert * @return string converted to comply with javascript */ public static String toJavaScriptString(String s) { StringBuilder b = new StringBuilder(s.length() + 64); appendJavaScriptString(b, s); return b.toString(); } }