pt.webdetails.cdf.dd.model.inst.writer.cggrunjs.CggRunJsGenericComponentWriter.java Source code

Java tutorial

Introduction

Here is the source code for pt.webdetails.cdf.dd.model.inst.writer.cggrunjs.CggRunJsGenericComponentWriter.java

Source

/*!
 * Copyright 2002 - 2015 Webdetails, a Pentaho 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 pt.webdetails.cdf.dd.model.inst.writer.cggrunjs;

import java.io.ByteArrayInputStream;

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 pt.webdetails.cdf.dd.CdeEngine;
import pt.webdetails.cdf.dd.model.core.Thing;
import pt.webdetails.cdf.dd.model.core.UnsupportedThingException;
import pt.webdetails.cdf.dd.model.core.writer.IThingWriteContext;
import pt.webdetails.cdf.dd.model.core.writer.IThingWriter;
import pt.webdetails.cdf.dd.model.core.writer.IThingWriterFactory;
import pt.webdetails.cdf.dd.model.core.writer.ThingWriteException;
import pt.webdetails.cdf.dd.model.core.writer.js.JsWriterAbstract;
import pt.webdetails.cdf.dd.model.inst.Dashboard;
import pt.webdetails.cdf.dd.model.inst.DataSourceComponent;
import pt.webdetails.cdf.dd.model.inst.GenericComponent;
import pt.webdetails.cdf.dd.model.inst.writer.cdfrunjs.legacy.CdfRunJsThingWriterFactory;
import pt.webdetails.cdf.dd.model.inst.writer.cdfrunjs.dashboard.CdfRunJsDashboardWriteContext;
import pt.webdetails.cdf.dd.model.inst.writer.cdfrunjs.dashboard.CdfRunJsDashboardWriteOptions;
import pt.webdetails.cdf.dd.util.Utils;
import pt.webdetails.cpf.repository.api.IUserContentAccess;
import pt.webdetails.cpf.utils.CharsetHelper;
import pt.webdetails.cdf.dd.model.meta.ComponentType;
import pt.webdetails.cdf.dd.model.meta.Resource;

import static pt.webdetails.cdf.dd.CdeConstants.Writer.*;

public class CggRunJsGenericComponentWriter extends JsWriterAbstract implements IThingWriter {
    private static final Log _logger = LogFactory.getLog(CggRunJsGenericComponentWriter.class);
    private static final String CGG_EXTENSION = ".js";
    private boolean writeScript = true;

    public CggRunJsGenericComponentWriter(boolean canWrite) {
        this.writeScript = canWrite;
    }

    public void write(Object output, IThingWriteContext context, Thing t) throws ThingWriteException {
        this.write((IUserContentAccess) output, (CggRunJsDashboardWriteContext) context, (GenericComponent) t);
    }

    public void write(IUserContentAccess access, CggRunJsDashboardWriteContext context, GenericComponent comp)
            throws ThingWriteException {
        if (!this.canWrite()) {
            return;
        }

        String dashboardFilePath = context.getDashboard().getSourcePath();
        String dashboardFileDir = FilenameUtils.getFullPath(dashboardFilePath);
        String dashboardFileName = FilenameUtils.getName(dashboardFilePath);

        StringBuilder out = new StringBuilder();

        out.append("lib('cdf-env.js');").append(NEWLINE).append(NEWLINE);

        this.renderChart(out, context, comp, dashboardFileDir);
        out.append(NEWLINE);

        this.renderDatasource(out, context, comp);
        out.append(NEWLINE).append(NEWLINE);

        String chartName = comp.getName();
        String compVarName = "render_" + chartName;

        out.append("cgg.render(").append(compVarName).append(");").append(NEWLINE);

        String chartScript = out.toString();

        writeFile(access, chartScript, dashboardFileDir, chartName, dashboardFileName);
        // Legacy support requires to keep generating dashboard unqualified scripts as well
        writeFile(access, chartScript, dashboardFileDir, chartName, null);
    }

    private void writeFile(IUserContentAccess access, String chartScript, String dashboardFileDir, String chartName,
            String dashboadFilName) {
        try {
            String prefix = dashboadFilName == null ? ""
                    : dashboadFilName.substring(0, dashboadFilName.lastIndexOf('.')) + '_';
            String fileName = prefix + chartName + CGG_EXTENSION;

            byte[] content = chartScript.getBytes(CharsetHelper.getEncoding());

            if (!access.saveFile(Utils.joinPath(dashboardFileDir, fileName), new ByteArrayInputStream(content))) {
                _logger.error("Failed to write CGG script file for chart '" + chartName + "'.");
            }
        } catch (Exception ex) {
            _logger.error("Failed to write script file for '" + chartName + "': " + ex.getCause().getMessage());
        }
    }

    private void renderChart(StringBuilder out, CggRunJsDashboardWriteContext context, GenericComponent comp,
            String dashDir) throws ThingWriteException {
        ComponentType compType = comp.getMeta();

        for (Resource resource : compType.getResources()) {
            Resource.Type resType = resource.getType();
            switch (resType) {
            case RAW:
                out.append(NEWLINE).append(resource.getSource()).append(NEWLINE);
                break;

            case SCRIPT:
                out.append(NEWLINE).append("load('").append(makeDashRelative(resource.getSource(), dashDir))
                        .append("');").append(NEWLINE);
                break;
            }
        }

        // Implementation
        String srcImpl = compType.getImplementationPath();
        if (StringUtils.isNotEmpty(srcImpl)) {
            out.append(NEWLINE).append("load('").append(makeDashRelative(srcImpl, dashDir)).append("');")
                    .append(NEWLINE);
        }

        // ---------------
        // TODO: HACK: Delegate writing the component definition to the corresponding CdfRunJs writer
        // Should this be done differently?
        IThingWriterFactory writerFactory = new CdfRunJsThingWriterFactory();
        IThingWriter compWriter;
        try {
            compWriter = writerFactory.getWriter(comp);
        } catch (UnsupportedThingException ex) {
            throw new ThingWriteException("Error while obtaining a writer for rendering the generic component.",
                    ex);
        }

        // Options are kind of irrelevant in this context,
        // as we're only rendering one component, not a dashboard (and not a widget component).
        CdfRunJsDashboardWriteOptions options = new CdfRunJsDashboardWriteOptions(false, false, "", "");

        // Idem
        CdfRunJsDashboardWriteContext writeContext = CdeEngine.getInstance().getEnvironment()
                .getCdfRunJsDashboardWriteContext(writerFactory, /*indent*/"", /*bypassCacheRead*/true,
                        context.getDashboard(), options);

        compWriter.write(out, writeContext, comp);
    }

    // Both are solution dir relative.
    private static String makeDashRelative(String path, String dashDir) {
        // resource -> system/pentaho-cdf-dd/resources/custom/components/InteractiveCosmos/interactiveCosmos.js
        // dashDir  -> cde/ <dashboard-is-here>
        // resource must be found relative to dashDir:
        // -> ../system/pentaho-cdf-dd/...
        // Find how many times to go back
        // Remove leading and trailing /
        dashDir = dashDir.replaceAll("^[/\\\\]*(.*?)[/\\\\]*$", "$1");

        if (!dashDir.isEmpty()) {
            int count = dashDir.split("[/\\\\]").length;
            for (int i = 0; i < count; i++) {
                path = "../" + path;
            }
        }

        return path;
    }

    private void renderDatasource(StringBuilder out, CggRunJsDashboardWriteContext context, GenericComponent comp)
            throws ThingWriteException {
        Dashboard dash = context.getDashboard();
        String dataSourceName = comp.tryGetPropertyValue("dataSource", null);
        if (StringUtils.isNotEmpty(dataSourceName)) {
            DataSourceComponent dsComp = dash.getDataSource(dataSourceName);

            IThingWriterFactory factory = context.getFactory();
            IThingWriter dsWriter;
            try {
                dsWriter = factory.getWriter(dsComp);
            } catch (UnsupportedThingException ex) {
                throw new ThingWriteException(ex);
            }

            CggRunJsComponentWriteContext compContext = new CggRunJsComponentWriteContext(factory, dash, comp);
            dsWriter.write(out, compContext, dsComp);
        }
    }

    public boolean canWrite() {
        return this.writeScript;
    }
}