Java tutorial
/*! * Copyright 2002 - 2017 Webdetails, a Hitachi Vantara company. All rights reserved. * * This software was developed by Webdetails and is provided under the terms * of the Mozilla Public License, Version 2.0, or any later version. You may not use * this file except in compliance with the license. If you need a copy of the license, * please go to http://mozilla.org/MPL/2.0/. The Initial Developer is Webdetails. * * Software distributed under the Mozilla Public License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to * the license for the specific language governing your rights and limitations. */ package org.pentaho.cdf.render; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.Charset; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.json.JSONException; import org.json.JSONObject; import org.pentaho.cdf.CdfConstants; import org.pentaho.cdf.context.ContextEngine; import org.pentaho.cdf.environment.CdfEngine; import org.pentaho.cdf.environment.packager.ICdfHeadersProvider; import org.pentaho.cdf.environment.templater.ITemplater; import org.pentaho.cdf.environment.templater.ITemplater.Section; import org.pentaho.cdf.storage.StorageEngine; import org.pentaho.cdf.util.Parameter; import pt.webdetails.cpf.Util; import pt.webdetails.cpf.localization.MessageBundlesHelper; import pt.webdetails.cpf.repository.api.IBasicFile; import pt.webdetails.cpf.repository.api.IContentAccessFactory; import pt.webdetails.cpf.repository.api.IRWAccess; import pt.webdetails.cpf.repository.api.IReadAccess; import pt.webdetails.cpf.repository.util.RepositoryHelper; import pt.webdetails.cpf.utils.CharsetHelper; public class CdfHtmlRenderer { private static Log logger = LogFactory.getLog(CdfHtmlRenderer.class); public void execute(final OutputStream out, final String solution, final String path, String templateName, String style, String dashboardsMessagesBaseFilename, HashMap<String, String> parameterMap, String user, int inactiveInterval) throws Exception { execute(out, solution, path, templateName, style, dashboardsMessagesBaseFilename, parameterMap, user, inactiveInterval, false, false); } public void execute(final OutputStream out, final String solution, final String path, String templateName, String style, String dashboardsMessagesBaseFilename, HashMap<String, String> parameterMap, String user, int inactiveInterval, boolean isRequire, boolean loadTheme) throws Exception { IBasicFile dashboardTemplateFile = HtmlDashboardRenderer.getDashboardTemplate(solution, path, templateName); execute(out, dashboardTemplateFile, style, dashboardsMessagesBaseFilename, parameterMap, user, inactiveInterval, isRequire, loadTheme); } public void execute(final OutputStream out, final String templatePath, String style, String dashboardsMessagesBaseFilename, HashMap<String, String> parameterMap, String user, int inactiveInterval) throws Exception { execute(out, style, templatePath, dashboardsMessagesBaseFilename, parameterMap, user, inactiveInterval, false, false); } public void execute(final OutputStream out, final String templatePath, String style, String dashboardsMessagesBaseFilename, HashMap<String, String> parameterMap, String user, int inactiveInterval, boolean isRequire, boolean loadTheme) throws Exception { IBasicFile dashboardTemplateFile = HtmlDashboardRenderer.getDashboardTemplate(templatePath); execute(out, dashboardTemplateFile, style, dashboardsMessagesBaseFilename, parameterMap, user, inactiveInterval, isRequire, loadTheme); } public void execute(OutputStream out, IBasicFile dashboardTemplateFile, String style, String dashboardsMessagesBaseFilename, HashMap<String, String> parameterMap, String user, int inactiveInterval, boolean isRequire, boolean loadTheme) throws Exception { String intro = ""; //$NON-NLS-1$ String footer = ""; //$NON-NLS-1$ IReadAccess systemAccess = getPluginSystemReader(null); style = StringUtils.isEmpty(style) ? "" : "-" + style; final String dashboardTemplate = "template-dashboard" + style + ".html"; //$NON-NLS-1$ ArrayList<String> i18nTagsList = new ArrayList<String>(); final String requireDashboardTemplate = "template-dashboard" + style + "-require.html"; IBasicFile templateResourceFile = null; IReadAccess pluginRepoAccess = getPluginRepositoryReader("templates/"); if (isRequire && pluginRepoAccess.fileExists(requireDashboardTemplate)) { templateResourceFile = pluginRepoAccess.fetchFile(requireDashboardTemplate); } else if (isRequire && systemAccess.fileExists(requireDashboardTemplate)) { templateResourceFile = systemAccess.fetchFile(requireDashboardTemplate); } else if (pluginRepoAccess.fileExists(dashboardTemplate)) { templateResourceFile = pluginRepoAccess.fetchFile(dashboardTemplate); } else if (systemAccess.fileExists(dashboardTemplate)) { // then try in system templateResourceFile = systemAccess.fetchFile(dashboardTemplate); } String templateContent; if (templateResourceFile != null) { //if a file was obtained correctly templateContent = getContentString(templateResourceFile.getContents()); } else { //if not get a default one logger.error( "Template " + dashboardTemplate + " not available on cdf/templates, loading fallback instead"); templateContent = getContentString(systemAccess.fetchFile("template-dashboard.html").getContents()); } if (!isRequire) { // Process i18n on dashboard outer template templateContent = updateUserLanguageKey(templateContent); templateContent = processi18nTags(templateContent, i18nTagsList); // Process i18n on dashboard outer template - end } ITemplater templater = getTemplater(); intro = templater.getTemplateSection(templateContent, Section.HEADER); footer = templater.getTemplateSection(templateContent, Section.FOOTER); final String dashboardContent = getDashboardContent(dashboardTemplateFile.getContents(), i18nTagsList); // Merge dashboard related message file with global message file and save it in the dashboard cache String path = StringUtils.defaultIfEmpty( FilenameUtils.getPathNoEndSeparator(dashboardTemplateFile.getPath()), getPluginRepositoryDir()); path = !path.startsWith(String.valueOf(RepositoryHelper.SEPARATOR)) ? RepositoryHelper.SEPARATOR + path : path; if (!isRequire) { intro = getMessageBundlesHelper(path).replaceParameters(intro, i18nTagsList); } /* * Add cdf libraries */ // final Date startDate = new Date(); final int headIndex = intro.indexOf("<head>"); final int length = intro.length(); // final Hashtable addedFiles = new Hashtable(); out.write(intro.substring(0, headIndex + 6).getBytes(CharsetHelper.getEncoding())); if (!isRequire) { // Concat libraries to html head content getHeadersInternal(dashboardContent, parameterMap, out); } else { // add the webcontext dependency checking if webcontext should load pentaho active theme getWebContextHeader(out, loadTheme); } out.write(intro.substring(headIndex + 6, length).getBytes(CharsetHelper.getEncoding())); if (!isRequire) { // Add context try { generateContext(out, parameterMap, inactiveInterval); } catch (Exception e) { logger.error("Error generating cdf context.", e); } // Add storage try { generateStorage(out, user); } catch (Exception e) { logger.error("Error in cdf storage.", e); } } else { out.write( MessageFormat .format(CdfConstants.INLINE_SCRIPT, "requireCfg.config = requireCfg.config || {};\n" + "requireCfg.config['cdf/dashboard/Dashboard'] = " + getConfiguration(path, parameterMap, inactiveInterval) + ";\n" + "requirejs.config(requireCfg);") .getBytes(CharsetHelper.getEncoding())); } out.write("<div id=\"dashboardContent\">".getBytes(CharsetHelper.getEncoding())); out.write(dashboardContent.getBytes(CharsetHelper.getEncoding())); out.write("</div>".getBytes(CharsetHelper.getEncoding())); out.write(footer.getBytes(CharsetHelper.getEncoding())); } protected String getConfiguration(String path, HashMap<String, String> parameterMap, int inactiveInterval) throws JSONException { return ContextEngine.getInstance().getConfig(path, parameterMap, inactiveInterval); } protected void getWebContextHeader(OutputStream out, boolean loadTheme) throws Exception { String webcontext = "<script language=\"javascript\" type=\"text/javascript\" src=\"webcontext" + ".js?context=cdf&application=pentaho-cdf" + (loadTheme ? "" : "&requireJsOnly=true") + "\"></script>"; out.write(webcontext.getBytes(CharsetHelper.getEncoding())); } public boolean matchComponent(int keyIndex, final String key, final String content) { for (int i = keyIndex - 1; i > 0; i--) { if (content.charAt(i) == ':' || content.charAt(i) == '"' || ("" + content.charAt(i)).trim().equals("")) { // noinspection UnnecessaryContinue continue; } else { if ((i - 3) > 0 && content.substring((i - 3), i + 1).equals("type")) { return true; } break; } } keyIndex = content.indexOf(key, keyIndex + key.length()); if (keyIndex != -1) { return matchComponent(keyIndex, key, content); } return false; } protected String getDashboardContent(InputStream is, ArrayList<String> i18nTagsList) throws Exception { // Fixed ISSUE #CDF-113 // BufferedReader reader = new BufferedReader(new InputStreamReader(is)); BufferedReader reader = new BufferedReader( new InputStreamReader(is, Charset.forName(CdfEngine.getEnvironment().getSystemEncoding()))); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { // Process i18n for each line of the dashboard output line = processi18nTags(line, i18nTagsList); // Process i18n - end sb.append(line + "\n"); //$NON-NLS-1$ } is.close(); return sb.toString(); } protected String processi18nTags(String content, ArrayList<String> tagsList) { String tagPattern = "CDF.i18n\\(\""; //$NON-NLS-1$ String[] test = content.split(tagPattern); if (test.length == 1) { return content; } StringBuffer resBuffer = new StringBuffer(); int i; String tagValue; resBuffer.append(test[0]); for (i = 1; i < test.length; i++) { // First tag is processed differently that other because is the only case where I don't // have key in first position resBuffer.append("<span id=\""); //$NON-NLS-1$ if (i != 0) { // Right part of the string with the value of the tag herein tagValue = test[i].substring(0, test[i].indexOf("\")")); //$NON-NLS-1$ tagsList.add(tagValue); resBuffer.append(updateSelectorName(tagValue)); resBuffer.append("\"></span>"); //$NON-NLS-1$ resBuffer.append(test[i].substring(test[i].indexOf("\")") + 2, test[i].length())); //$NON-NLS-1$ } } return resBuffer.toString(); } private String updateSelectorName(String name) { // If we've the character . in the message key substitute it conventionally to _ // when dynamically generating the selector name. The "." character is not permitted in the // selector id name return name.replace(".", "_"); } private String buildMessageSetCode(ArrayList<String> tagsList) { StringBuffer messageCodeSet = new StringBuffer(); for (String tag : tagsList) { messageCodeSet.append("\\$('#").append(updateSelectorName(tag)).append("').html(jQuery.i18n.prop('") .append(tag).append("'));\n"); //$NON-NLS-1$ } return messageCodeSet.toString(); } protected String updateUserLanguageKey(String intro) { // Fill the template with the correct user locale intro = intro.replaceAll("#\\{LANGUAGE_CODE\\}", CdfEngine.getEnvironment().getLocale().getLanguage()); //$NON-NLS-1$ return intro; } public static void getHeaders(HashMap<String, String> paramMap, OutputStream out) throws Exception { String dashboardContent = StringUtils.defaultString(paramMap.get(Parameter.DASHBOARD_CONTENT)); getHeaders(dashboardContent, paramMap, out); } protected void getHeadersInternal(String dashboardContent, HashMap<String, String> paramMap, OutputStream out) throws Exception { getHeaders(dashboardContent, paramMap, out); } public static void getHeaders(String dashboardContent, HashMap<String, String> paramMap, OutputStream out) throws Exception { final String dashboardType = StringUtils.defaultIfEmpty(paramMap.get(Parameter.DASHBOARD_TYPE), "blueprint"); final boolean isDebugMode = Boolean.TRUE.toString().equalsIgnoreCase(paramMap.get(Parameter.DEBUG)); String root = StringUtils.defaultString(paramMap.get(Parameter.ROOT)); String scheme = StringUtils.defaultIfEmpty(paramMap.get(Parameter.SCHEME), "http"); boolean absolute = StringUtils.defaultIfEmpty(paramMap.get(Parameter.ABSOLUTE), "false").equals("true"); getHeaders(dashboardContent, dashboardType, absolute, root, scheme, isDebugMode, out); } public static void getHeaders(String dashboardContent, String dashboardType, boolean absolute, String root, String scheme, boolean isDebugMode, OutputStream out) throws Exception { ICdfHeadersProvider cdfHeaders = CdfEngine.getEnvironment().getCdfHeadersProvider(); // Identify which extra JSs and CSSs to add to header, according to components being used List<String> componentTypes = new ArrayList<String>(CdfConstants.DASHBOARD_COMPONENT_TYPES.length); if (dashboardContent != null) { componentTypes = new ArrayList<String>(); // search for component types in dashboardsContent (e.g. template.html) for (String[] componenType : CdfConstants.DASHBOARD_COMPONENT_TYPES) { // Screen Scrap to get component types from dashboardContent if (Pattern.compile(String.format("type:\\s*[\"'](?i)%s[a-z]*[\"']", componenType[0])) .matcher(dashboardContent).find()) { componentTypes.add(componenType[1]); } } } if (absolute) { String webRoot; // some dashboards need full absolute urls if (!StringUtils.isEmpty(root)) { if (root.contains("/")) { // file paths are already absolute, which didn't happen before root = root.substring(0, root.indexOf("/")); } webRoot = scheme + "://" + root; } else { webRoot = CdfEngine.getEnvironment().getPathProvider().getWebappContextRoot(); } out.write(cdfHeaders.getHeaders(dashboardType, isDebugMode, webRoot, componentTypes) .getBytes(CharsetHelper.getEncoding())); } else { out.write(cdfHeaders.getHeaders(dashboardType, isDebugMode, componentTypes) .getBytes(CharsetHelper.getEncoding())); } } protected void generateStorage(final OutputStream out, final String user) throws Exception { JSONObject result = StorageEngine.getInstance().read(user); StringBuilder s = new StringBuilder(); s.append("\n<script language=\"javascript\" type=\"text/javascript\">\n"); s.append(" Dashboards.storage = "); s.append(result.toString(2)).append("\n"); s.append("</script>\n"); // setResponseHeaders(MIME_PLAIN,0,null); out.write(s.toString().getBytes(CharsetHelper.getEncoding())); } protected void generateContext(final OutputStream out, HashMap parameterMap, int inactiveInterval) throws Exception { ContextEngine.getInstance().generateContext(out, parameterMap, inactiveInterval); } protected IReadAccess getPluginSystemReader(String path) { return CdfEngine.getPluginSystemReader(path); } protected IReadAccess getPluginRepositoryReader(String path) { return CdfEngine.getPluginRepositoryReader(path); } protected String getPluginRepositoryDir() { return CdfEngine.getEnvironment().getCdfPluginRepositoryDir(); } protected Locale getLocale() { return CdfEngine.getEnvironment().getLocale(); } protected MessageBundlesHelper getMessageBundlesHelper(String path) throws IOException { IContentAccessFactory factory = CdfEngine.getEnvironment().getContentAccessFactory(); String cdfStaticBaseUrl = CdfEngine.getEnvironment().getPathProvider().getPluginStaticBaseUrl(); IRWAccess cdfSystemWriter = factory.getPluginSystemWriter(null); return new MessageBundlesHelper(path, Util.getAppropriateReadAccess(path, factory, CdfEngine.getEnvironment().getPluginId(), CdfEngine.getEnvironment().getSystemDir(), getPluginRepositoryDir()), cdfSystemWriter, CdfEngine.getEnvironment().getLocale(), cdfStaticBaseUrl); } protected String getContentString(InputStream inputStream) throws IOException { return Util.toString(inputStream); } protected ITemplater getTemplater() { return CdfEngine.getEnvironment().getTemplater(); } }