org.geworkbench.engine.ccm.ComponentConfigurationManager.java Source code

Java tutorial

Introduction

Here is the source code for org.geworkbench.engine.ccm.ComponentConfigurationManager.java

Source

package org.geworkbench.engine.ccm;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Vector;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.digester.Digester;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geworkbench.engine.config.PluginDescriptor;
import org.geworkbench.engine.config.PluginRegistry;
import org.geworkbench.engine.config.UILauncher;
import org.geworkbench.engine.config.rules.PluginRule;
import org.geworkbench.engine.management.ComponentRegistry;
import org.geworkbench.engine.management.ComponentResource;
import org.geworkbench.util.FilePathnameUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.SAXException;

/**
 * Manages the dynamic loading and removal of components.
 * 
 * @author keshav
 * @author tg2321
 * @version $Id: ComponentConfigurationManager.java,v 1.1 2009/02/09 19:54:43
 *          keshav Exp $
 */
public class ComponentConfigurationManager {

    private static Log log = LogFactory.getLog(ComponentConfigurationManager.class);
    String[] files = null;

    private static final String FILE_DEL = System.getProperty("file.separator");
    private static final String COMPONENT_DESCRIPTOR_EXTENSION = ".cwb.xml";

    private static String propertiesDirectory = FilePathnameUtils.getUserSettingDirectoryPath();

    private String componentsDirectory = UILauncher.getComponentsDirectory();

    private static ComponentConfigurationManager instance = null;

    public static ComponentConfigurationManager getInstance() {
        if (instance == null) {
            instance = new ComponentConfigurationManager();
        }
        return instance;
    }

    /**
     * Constructor
     * 
     * @param
     */
    private ComponentConfigurationManager() {
        File dir = new File(componentsDirectory);
        if (!dir.isDirectory()) {
            log.warn("Supplied components directory is not a directory: " + componentsDirectory);
            return;
        }
        files = dir.list();
    }

    /**
     * Creates a {@link ComponentResource}.
     * 
     * @return {@link ComponentResource}
     */
    private ComponentResource createComponentResource(String resource) {
        log.debug("Create component resource " + resource);

        if (StringUtils.isEmpty(resource)) {
            log.error("Input resource is null.  Returning ...");
        }
        List<String> list = Arrays.asList(files);

        ComponentResource componentResource = null;
        if (list.contains(resource)) {
            int index = list.indexOf(resource);
            File file = new File(list.get(index));
            try {
                String path = componentsDirectory + FILE_DEL + file.getPath();
                componentResource = new ComponentResource(path, false);
                log.debug("Created component resource " + file.getName());
            } catch (IOException e) {
                log.error("Could not initialize component resource '" + file.getName() + "'.", e);
            }
            return componentResource;
        }
        log.error("Resource does not exist for " + resource + ".  Returning null.");
        return null;
    }

    /**
     * .cwb.xml files decides which rows
     * should be displayed in the CCM window.
     * 
     * @return {@link ArrayList}
     */
    public void loadAllComponentFolders(File componentDirectory) {
        cwbFile = new ArrayList<File>();
        if (!componentDirectory.isDirectory()) {
            log.error("component directory is not a directory");
        }

        File[] componentDirectories = componentDirectory.listFiles();
        if (componentDirectories == null) {
            log.warn("no component found");
            return;
        }
        for (File componentDir : componentDirectories) {
            log.info("searching resource " + componentDir);

            File resourceDir = new File(componentDir + "/classes");
            try {
                searchCwb(resourceDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Collections.sort(cwbFile);
        log.info(cwbFile.size() + " cwb files found under all resource directories");
    }

    public void removeOutVersionedFoldersFromCwbFileList() {
        List<File> tmpCwbFiles = new ArrayList<File>();
        boolean foundNewerVersion = false;
        for (int i = 0; i < cwbFile.size(); i++) {
            foundNewerVersion = false;
            File file1 = cwbFile.get(i);
            String cwbFileName1 = file1.getName();
            for (int j = 0; j < cwbFile.size(); j++) {
                if (i == j) {
                    continue;
                }
                File file2 = cwbFile.get(j);
                String cwbFileName2 = file2.getName();
                if (cwbFileName1.equals(cwbFileName2)) {
                    String folder1 = resourceFolder(file1);
                    int versionIndex1 = folder1.indexOf(".");
                    Double version1 = new Double(0.0);
                    int folder1length = folder1.length();
                    if (versionIndex1 > -1 && folder1length >= versionIndex1 + 1) {
                        try {
                            version1 = new Double(folder1.substring(versionIndex1 + 1));
                        } catch (Exception e) {
                            version1 = new Double(0.0);
                        }
                    }

                    String folder2 = resourceFolder(file2);
                    int versionIndex2 = folder2.indexOf(".");
                    Double version2 = new Double(0.0);
                    int folder2length = folder2.length();
                    if (versionIndex2 > -1 && folder2length >= versionIndex2 + 1) {
                        try {
                            String ver = folder2.substring(versionIndex2 + 1);
                            version2 = new Double(ver);
                        } catch (Exception e) {
                            version2 = new Double(0.0);
                        }
                    }

                    if (version2.compareTo(version1) > 0) {
                        foundNewerVersion = true;
                        break;
                    }
                }
            }

            if (foundNewerVersion) {
                continue;
            }
            tmpCwbFiles.add(file1);
        }
        cwbFile = tmpCwbFiles;
    }

    private void searchCwb(File dir) throws IOException {
        File[] files = dir.listFiles();
        if (files == null || files.length == 0)
            return;
        for (File file : files) {
            if (file.isDirectory()) {
                searchCwb(file);
            } else {
                if (file.getName().endsWith(COMPONENT_DESCRIPTOR_EXTENSION)) {
                    cwbFile.add(file);
                }
            }
        }
    }

    List<File> cwbFile = null;

    public void loadSelectedComponents() {
        for (File file : cwbFile) {
            // this is not really the right way to do it. just to support existing code. TODO
            String folder = resourceFolder(file);
            String ccmFileName = file.getName();

            String propFileName = ccmFileName.replace(COMPONENT_DESCRIPTOR_EXTENSION, ".ccmproperties");

            String onOff = readProperty(folder, propFileName, "on-off");
            PluginComponent ccmComponent = getPluginsFromFile(file);
            if (ccmComponent == null) {
                log.error(".cwb.xml file " + file + " failed to be loaded");
                continue;
            }
            String name = ccmComponent.getName();
            UILauncher.setProgressBarString(name);
            boolean loadByDefault = ccmComponent.getLoadByDefault();

            if (onOff == null && loadByDefault) {
                writeProperty(folder, propFileName, "on-off", "true");
                onOff = readProperty(folder, propFileName, "on-off");
            }
            if (onOff != null && onOff.equals("true")) {
                log.info("loading " + file);
                loadComponent(file);
            } else {
                log.info(file + "turned off");
            }
        }
    }

    // this eventually should not be necessary if the cwb/resource is managed properly
    private String resourceFolder(File file) {
        String path = file.getAbsolutePath();
        int index = path.indexOf(componentsDirectory) + componentsDirectory.length() + 1;
        return path.substring(index, path.indexOf(FILE_DEL, index));
    }

    /**
     * Load a plugin component described in a .cwb.xml file. resoruceMap should have been initialized already.
     */
    void loadComponent(File file) {
        String folder = resourceFolder(file);
        /* create component resource */
        ComponentResource componentResource = createComponentResource(folder);

        /* add resource to registry */
        ComponentRegistry.getRegistry().addComponentResource(folder, componentResource);

        InputStream is = null;

        try {
            is = new FileInputStream(file);
            cwbDigester.parse(is);
            log.debug(file + " loaded");
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (SAXException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Removes the component with resourceName.
     * 
     * @param folderName
     * @param ccmFileName
     * @return Returns false if component was not successfully removed, else
     *         true.
     */
    @SuppressWarnings("unchecked")
    public boolean removeComponent(String folderName, String filename) {

        /*
         * Container Summary:
         * 
         * ComponentRegistry Section listeners = new TypeMap<List>(); 
         * acceptors = new HashMap<Class, List<Class>>(); 
         * synchModels = new HashMap<Class, SynchModel>(); 
         * components = new ArrayList(); 
         * idToDescriptor = new HashMap<String, PluginDescriptor>(); 
         * nameToComponentResource = new HashMap<String, ComponentResource>();
         */

        ComponentRegistry componentRegistry = ComponentRegistry.getRegistry();

        /* validation */
        if (StringUtils.isEmpty(folderName)) {
            log.error("Input resource is null.  Returning ...");
            return false;
        }

        List<String> list = Arrays.asList(files);
        if (!list.contains(folderName)) {
            return false;
        }

        // FIXME why parse again? can't we get this info another way?
        /* parse the ccm.xml file */
        PluginComponent ccmComponent = null;
        if (filename.endsWith(COMPONENT_DESCRIPTOR_EXTENSION)) {
            ccmComponent = getPluginsFromFile(new File(filename));
        } else {
            return false;
        }

        if (ccmComponent == null)
            return false;

        /* GET THE VARIOUS MAPS/VECTORS FROM THE PLUGIN REGISTRY */

        /* plugin registry component vector */
        Vector<PluginDescriptor> componentVector = PluginRegistry.getComponentVector();

        /* plugin registry visual area map */
        HashMap<PluginDescriptor, String> visualAreaMap = PluginRegistry.getVisualAreaMap();

        /* plugin registry used ids */
        Vector<String> usedIds = PluginRegistry.getUsedIds();

        // FIXME Can't we get the PluginDesriptor we want other than from the
        // ccm.xml file?
        // beginning of processing the plugin
        final String pluginClazzName = ccmComponent.getClazz();
        PluginDescriptor pluginDescriptor = PluginRegistry.getPluginDescriptor(ccmComponent.getPluginId());

        if (pluginDescriptor != null) {

            /* START THE REMOVAL PROCESS IN THE PLUGIN REGISTRY */
            /* PluginRegistry.visualAreaMap */
            for (Entry<PluginDescriptor, String> entry : visualAreaMap.entrySet()) {
                Object pluginDescriptor1 = entry.getKey();
                Class<?> clazz = pluginDescriptor1.getClass();
                String proxiedClazzName = clazz.getName();

                // TODO Replace $$ parse methods with clazzName = clazz.getSuperclass() 
                String[] temp = StringUtils.split(proxiedClazzName, "$$");
                String clazzName = temp[0];

                if (StringUtils.equals(pluginClazzName, clazzName)) {
                    visualAreaMap.remove(entry.getKey());
                    break;
                }
            }

            /* PluginRegistry.visualAreaMap */
            String id = ccmComponent.getPluginId();
            if (PluginDescriptor.idExists(id)) {
                usedIds.remove(id);
            }

            /* PluginRegistry.compontentVector */
            if (componentVector.contains(pluginDescriptor)) {
                componentVector.remove(pluginDescriptor);
            }

            /* START THE REMOVAL PROCESS IN THE COMPONENT REGISTRY */

            componentRegistry.removeComponent(pluginClazzName);
            componentRegistry.removePlugin(ccmComponent.getPluginId());

        } // end of processing the plugin

        /* ComponentRegistry.idToDescriptor */
        /* If other Plugins are using the same Component Resource, don't remove the Resource */
        int foldersInUse = 0;
        for (int i = 0; i < componentVector.size(); i++) {
            PluginDescriptor pd = componentVector.get(i);
            if (pd == null) {
                continue;
            }

            ComponentResource componentResource = pd.getResource();
            if (componentResource == null) {
                continue;
            }

            String name = componentResource.getName();
            if (name == null) {
                continue;
            }

            if (name.equalsIgnoreCase(folderName)) {
                foldersInUse++;
            }
        }

        if (foldersInUse < 1) {
            componentRegistry.removeComponentResource(folderName);
        }

        return true;
    }

    PluginComponent getPluginsFromFile(File file) {
        if (!file.exists()) {
            return null;
        }

        PluginComponent ccmComponent = null;

        SAXBuilder builder = new SAXBuilder();
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);

            if (inputStream != null) {
                Document doc = null;
                try {
                    doc = builder.build(inputStream);
                } catch (JDOMException e) {
                    log.error(e, e);
                } catch (IOException e) {
                    log.error(e, e);
                }
                Element root = doc.getRootElement();
                if (root.getName().equals("component-descriptor")) {
                    String name = null;
                    String clazz = null;
                    String version = null;
                    String author = null;
                    String authorUrl = null;
                    String tutorialUrl = null;
                    String toolUrl = null;
                    String description = null;
                    String license = null;
                    boolean mustAccept = false;
                    String documentation = null;
                    boolean loadByDefault = false;
                    boolean hidden = false;
                    String pluginName = null;
                    String pluginId = null;
                    String resource = null;
                    String[] category = new String[0];
                    List<String> required = new ArrayList<String>();
                    List<String> related = new ArrayList<String>();

                    for (Object objElement : root.getChildren()) {
                        Element element = (Element) objElement;
                        if (element.getName().equals("component")) {
                            clazz = element.getAttributeValue("class");
                            name = element.getAttributeValue("name");
                            version = element.getAttributeValue("version");
                            author = element.getAttributeValue("author");
                            authorUrl = element.getAttributeValue("authorURL");
                            tutorialUrl = element.getAttributeValue("tutorialURL");
                            toolUrl = element.getAttributeValue("toolURL");
                            description = element.getAttributeValue("description");
                            String str = element.getAttributeValue("mustAccept");
                            if (str != null && str.equalsIgnoreCase("true"))
                                mustAccept = true;
                            documentation = element.getAttributeValue("documentation");
                            str = element.getAttributeValue("loadByDefault");
                            if (str != null && str.equalsIgnoreCase("true"))
                                loadByDefault = true;
                            str = element.getAttributeValue("hidden");
                            if (str != null && str.equalsIgnoreCase("true"))
                                hidden = true;

                            for (Object obj : element.getChildren()) {
                                Element subElement = (Element) obj;
                                String type = subElement.getName();
                                String dependencyClass = subElement.getAttributeValue("class");
                                if (type.equals("required-component")) {
                                    required.add(dependencyClass);
                                } else if (type.equals("related-component")) {
                                    related.add(dependencyClass);
                                } else if (type.equals("license")) {
                                    license = subElement.getTextTrim();
                                }
                            }

                            str = element.getAttributeValue("category");
                            if (str != null) {
                                category = str.trim().split(",");
                                for (int i = 0; i < category.length; i++) {
                                    category[i] = category[i].trim().toLowerCase();
                                }
                            }

                        }

                        if (element.getName().equals("plugin")) {
                            pluginId = element.getAttributeValue("id");
                            pluginName = element.getAttributeValue("name");
                            String pluginClazz = element.getAttributeValue("class");
                            if (!pluginClazz.equals(clazz)) {
                                log.error("plugin element and component have different class names in "
                                        + file.getName());
                            }
                            resource = element.getAttributeValue("source");
                        }
                    }

                    ccmComponent = new PluginComponent(name, clazz, version, author, authorUrl, tutorialUrl,
                            toolUrl, description, license, mustAccept, documentation, loadByDefault, hidden,
                            pluginName, pluginId, resource, category, required, related);
                } // end of if open element is correct
            }
        } catch (Exception e) {
            log.error("ERROR LOADING:" + file, e);
            return null;
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                log.error("ERROR LOADING:" + file, e);
                return null;
            }
        }

        return ccmComponent;
    }

    /**
     * Save component selections to properties file
     * 
     * @param folder
     * @param propertyFileName
     * @param key
     * @param value
     */
    public static void writeProperty(String folder, String propertyFileName, String key, String value) {

        String fullPropertiesPath = propertiesDirectory + FILE_DEL + folder + FILE_DEL + propertyFileName;
        FileInputStream in = null;
        try {
            Properties pro = new Properties();
            File f = new File(fullPropertiesPath);

            if (f.exists()) {
                in = new FileInputStream(f);
                pro.load(in);
            } else {
                f.getParentFile().mkdirs();
            }

            pro.setProperty(key, value);
            pro.store(new FileOutputStream(fullPropertiesPath), null);
            log.debug(fullPropertiesPath + " has been updated.");

        } catch (IOException e) {
            log.error(e, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                log.error("Problems closing the stream.");
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * Read component selections to properties file.
     * 
     * @param folder
     * @param propertyFileName
     * @param key
     * @return
     */
    public static String readProperty(String folder, String propertyFileName, String key) {
        String returnValue = null;

        String fullPropertiesPath = propertiesDirectory + FILE_DEL + folder + FILE_DEL + propertyFileName;

        FileInputStream in = null;
        try {
            Properties properties = new Properties();
            File f = new File(fullPropertiesPath);

            if (!f.exists()) {
                return null;
            }

            in = new FileInputStream(f);
            properties.load(in);

            returnValue = properties.getProperty(key);

            properties.store(new FileOutputStream(fullPropertiesPath), null);

        } catch (IOException e) {
            log.error(e, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                log.error("Problems closing the stream.");
                throw new RuntimeException(e);
            }
        }

        return returnValue;
    }

    private static Digester cwbDigester = null;
    static {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser saxParser = factory.newSAXParser();
            cwbDigester = new Digester(saxParser);

            cwbDigester.setUseContextClassLoader(true);

            // Instantiates a plugin and adds it in the PluginResgistry
            cwbDigester.addRule("component-descriptor/plugin",
                    new PluginRule("org.geworkbench.engine.config.rules.PluginObject"));

            // Registers a visual plugin with the top-level application GUI.
            cwbDigester.addCallMethod("component-descriptor/plugin/gui-area", "addGUIComponent", 1);
            cwbDigester.addCallParam("component-descriptor/plugin/gui-area", 0, "name");
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}