pt.webdetails.cdf.dd.render.components.ComponentManager.java Source code

Java tutorial

Introduction

Here is the source code for pt.webdetails.cdf.dd.render.components.ComponentManager.java

Source

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
package pt.webdetails.cdf.dd.render.components;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.json.JSON;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.pentaho.platform.api.engine.IFileFilter;
import org.pentaho.platform.api.engine.ISolutionFile;
import org.pentaho.platform.engine.core.system.PentahoSystem;

import pt.webdetails.cdf.dd.CdeSettings;
import pt.webdetails.cdf.dd.DashboardDesignerContentGenerator;
import pt.webdetails.cdf.dd.render.datasources.CdaDatasource;
import pt.webdetails.cdf.dd.render.properties.PropertyManager;
import pt.webdetails.cdf.dd.util.Utils;
import pt.webdetails.cpf.PluginSettings;
import pt.webdetails.cpf.plugins.PluginsAnalyzer;
import pt.webdetails.cpf.repository.RepositoryAccess;
import pt.webdetails.cpf.repository.RepositoryAccess.FileAccess;

/**
 *
 * @author pdpi
 */
public class ComponentManager {

    protected static Log logger = LogFactory.getLog(ComponentManager.class);
    private static final String PLUGIN_DIR = Utils.joinPath("system",
            DashboardDesignerContentGenerator.PLUGIN_NAME);
    private static final String BASE_COMPONENTS_DIR = Utils.joinPath(PLUGIN_DIR, "resources", "base", "components");
    private static final String COMPONENT_FILE = "component.xml";
    private static ComponentManager _engine;
    private String basePath = PentahoSystem.getApplicationContext().getSolutionPath("");
    protected Hashtable<String, BaseComponent> componentPool;
    private static final String PACKAGEHEADER = "pt.webdetails.cdf.dd.render.components.";
    private JSON cdaSettings = null;
    private String[] resourceLocations;

    protected ComponentManager() {
        init();
    }

    public static synchronized ComponentManager getInstance() {
        if (_engine == null) {
            _engine = new ComponentManager();
        }
        return _engine;
    }

    public void refresh() {
        // Start by refreshing the dependencies
        PropertyManager.getInstance().refresh();
        init();
    }

    private List<File> listAllFiles(File dir, FilenameFilter filter) {
        ArrayList<File> results = new ArrayList<File>();

        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    results.addAll(listAllFiles(file, filter));
                } else if (filter.accept(dir, file.getName())) {
                    results.add(file);
                }
            }
        }
        return results;
    }

    protected void indexBaseComponents() {
        File dir = new File(Utils.joinPath(this.basePath, BASE_COMPONENTS_DIR));
        FilenameFilter xmlFiles = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return !name.startsWith(".") && name.endsWith(".xml");
            }
        };
        // String[] files = dir.list(xmlFiles);
        List<File> files = listAllFiles(dir, xmlFiles);

        for (File file : files) {
            try {
                Document doc = XmlDom4JHelper.getDocFromFile(file.getPath(), null);

                // To support multiple definitions on the same file, we'll iterate through all
                // the //DesignerComponent nodes
                List<Node> components = doc.selectNodes("//DesignerComponent");

                for (Node component : components) {
                    // To figure out whether the component is generic or has a special implementation,
                    // we directly look for the class override in the definition
                    String className = XmlDom4JHelper.getNodeText("Override", component);
                    if (className != null) {
                        BaseComponent renderer = rendererFromClass(className);
                        if (renderer != null) {
                            componentPool.put(renderer.getName(), renderer);
                        }
                    } else {
                        GenericComponent renderer = new GenericComponent();
                        if (renderer != null) {
                            try {
                                renderer.setDefinition(component);
                                componentPool.put(renderer.getName(), renderer);
                            } catch (Exception e) {
                                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, e);
                            }
                        }
                    }

                }

            } catch (Exception e) {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, e);
            }
        }
    }

    private synchronized void indexCustomComponents() {

        ArrayList<String> locations = new ArrayList<String>();

        //add base locations;
        locations.add(RepositoryAccess.getSolutionPath(DashboardDesignerContentGenerator.PLUGIN_PATH));
        locations.add(RepositoryAccess.getSolutionPath(""));

        for (String componentsDir : CdeSettings.getComponentLocations()) {
            indexCustomComponents(componentsDir);
            locations.add(RepositoryAccess.getSolutionPath(componentsDir));
        }

        for (String componentsDir : getExternalComponentLocations()) {
            indexCustomComponents(componentsDir);
            locations.add(RepositoryAccess.getSolutionPath(componentsDir));
        }

        resourceLocations = locations.toArray(new String[locations.size()]);
    }

    /**
     * Get a list of locations from which resource loading is allowed. This will
     * include the solution repository, CDE's location and any folders declared as
     * containing CDE components
     *
     * @return Full paths to allowed locations
     */
    public String[] getAllowedLocations() {
        if (resourceLocations == null) {
            indexCustomComponents();
        }
        return resourceLocations;
    }

    private String[] getExternalComponentLocations() {

        PluginsAnalyzer pluginsAnalyzer = new PluginsAnalyzer();
        pluginsAnalyzer.refresh();

        List<PluginsAnalyzer.PluginWithEntity> pluginsWithEntity = null;

        pluginsWithEntity = pluginsAnalyzer.getRegisteredEntities("/cde-components");

        ArrayList<String> componentLocations = new ArrayList<String>();
        for (PluginsAnalyzer.PluginWithEntity entity : pluginsWithEntity) {
            String location = entity.getRegisteredEntity().valueOf("path");
            componentLocations.add(location);
            logger.debug("found CDE components location declared in " + entity.getPlugin().getId() + " [" + location
                    + "]");
        }

        return componentLocations.toArray(new String[componentLocations.size()]);
    }

    private void indexCustomComponents(String dirPath) {
        String dirAbsPath = Utils.joinPath(basePath, dirPath);
        File dir = new File(dirAbsPath);

        logger.info("Loading custom components from: " + dir.toString());

        FilenameFilter subFolders = new FilenameFilter() {
            public boolean accept(File systemFolder, String name) {
                File plugin = new File(Utils.joinPath(systemFolder.getPath(), name, COMPONENT_FILE));
                return plugin.exists() && plugin.canRead();

            }
        };
        String[] files = dir.list(subFolders);
        if (files == null) {
            return;
        }
        logger.debug(files.length + " sub-folders found");
        processFiles(dirPath, dir, files);

    }

    private void indexWidgetComponents() {
        String dirPath = "/cde/widgets/";
        String dirAbsPath = Utils.joinPath(basePath, dirPath);
        File dir = new File(dirAbsPath);

        logger.info("Loading widget components from: " + dir.toString());

        FilenameFilter widgetComponents = new FilenameFilter() {
            public boolean accept(File systemFolder, String name) {
                return !name.startsWith(".") && name.endsWith(".component.xml");
            }
        };
        String[] files = dir.list(widgetComponents);
        if (files == null) {
            return;
        }
        logger.debug(files.length + " widget components found");
        processFiles(dirPath, dir, files);
    }

    private void processFiles(String dirPath, File dir, String[] files) {
        if (files != null) {

            Arrays.sort(files, String.CASE_INSENSITIVE_ORDER);
            for (String file : files) {
                try {
                    String basePath = Utils.joinPath(dir.getPath(), file);
                    String xmlPath = Utils.joinPath(basePath, COMPONENT_FILE);

                    Document doc;
                    try {
                        doc = XmlDom4JHelper.getDocFromFile(basePath, null);
                    } catch (Exception e) {
                        doc = XmlDom4JHelper.getDocFromFile(xmlPath, null);
                    }
                    // To support multiple definitions on the same file, we'll iterate
                    // through all the DesignerComponent nodes
                    List<Node> components = doc.selectNodes("//DesignerComponent");

                    if (logger.isDebugEnabled() && components.size() > 0) {
                        logger.debug("\t" + file + " [" + components.size() + "]");
                    }

                    for (Node component : components) {

                        // To figure out whether the component is generic or has a special
                        // implementation, we directly look for the class override in the definition
                        String className = XmlDom4JHelper.getNodeText("Override", component);
                        if (className != null) {
                            BaseComponent renderer = rendererFromClass(className);
                            if (renderer != null) {
                                componentPool.put(renderer.getName(), renderer);
                            }
                        } else {
                            CustomComponent renderer = new CustomComponent(Utils.joinPath(dirPath, file));
                            if (renderer != null) {
                                renderer.setDefinition(component);
                                componentPool.put(renderer.getName(), renderer);
                            }
                        }

                    }

                } catch (Exception e) {
                    Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, e);
                }
            }
        }
    }

    private void init() {
        this.componentPool = new Hashtable<String, BaseComponent>();
        // we need the properties to be initialized. Calling getInstance() is enough.
        PropertyManager.getInstance();
        indexBaseComponents();
        indexCustomComponents();
        indexWidgetComponents();
    }

    private BaseComponent rendererFromClass(String className) {
        BaseComponent renderer = null;
        try {
            renderer = (BaseComponent) Class.forName(PACKAGEHEADER + className).newInstance();
        } catch (Exception ex) {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        return renderer;
    }

    public String getEntry() {
        StringBuilder entry = new StringBuilder();
        Collection<BaseComponent> components = componentPool.values();
        for (IComponent render : components) {
            entry.append(render.getEntry());
        }
        return entry.toString();
    }

    public String getModel() {
        StringBuilder model = new StringBuilder();
        Collection<BaseComponent> components = componentPool.values();
        for (IComponent render : components) {
            model.append(render.getModel());
        }
        return model.toString();
    }

    public String getDefinitions() {
        StringBuilder defs = new StringBuilder();
        defs.append(PropertyManager.getInstance().getDefinitions());
        defs.append(getEntry());
        defs.append(getModel());

        return defs.toString().replaceAll(",([\\r\\n]+\\s*})", "$1"); // pattern: |,([\r\n]+\s*})| // replaceBy: |$1| 
    }

    public String getImplementations() {
        return "";
    }

    public BaseComponent getRenderer(JXPathContext context) {
        String renderType = ((String) context.getValue("type")).replace("Components", "");
        return componentPool.get(renderType);
    }

    public void parseCdaDefinitions(JSON json) throws Exception {
        cdaSettings = json;
        final JXPathContext doc = JXPathContext.newContext(json);
        Iterator<Pointer> pointers = doc.iteratePointers("*");
        while (pointers.hasNext()) {
            Pointer pointer = pointers.next();
            CdaDatasource ds = new CdaDatasource(pointer);
            componentPool.put(ds.getName(), ds);
        }
    }

    public JSON getCdaDefinitions() {
        return cdaSettings;
    }
}