de.juwimm.cms.content.modules.ModuleFactoryStandardImpl.java Source code

Java tutorial

Introduction

Here is the source code for de.juwimm.cms.content.modules.ModuleFactoryStandardImpl.java

Source

/**
 * Copyright (c) 2009 Juwi MacMillan Group GmbH
 *
 * 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 de.juwimm.cms.content.modules;

import static de.juwimm.cms.client.beans.Application.getBean;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.log4j.Logger;
import org.tizzit.util.XercesHelper;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import de.juwimm.cms.Messages;
import de.juwimm.cms.client.beans.Beans;
import de.juwimm.cms.common.Constants;
import de.juwimm.cms.gui.controls.ColapsePanel;
import de.juwimm.cms.util.Communication;
import de.juwimm.cms.vo.SiteValue;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2002</p>
 * <p>Company: </p>
 * @author <a href="mailto:s.kulawik@juwimm.com">Sascha-Matthias Kulawik</a>
 * @version $Id$
 */
public class ModuleFactoryStandardImpl implements ModuleFactory {
    private static Logger log = Logger.getLogger(ModuleFactoryStandardImpl.class);
    /** Contains all the Modules used in one Template key DcfName value Module */
    private Hashtable<String, Module> htModules = new Hashtable<String, Module>();
    /** Contains the initial content from the DCF for every dcfName */
    private final Hashtable<String, Node> htInitialContent = new Hashtable<String, Node>();

    public ModuleFactoryStandardImpl() {
        htModules = new Hashtable<String, Module>();
    }

    public Module getModuleInstanceUnconfigured(String classname, List<String> additionalJarFiles) {
        Module module = null;

        if (!additionalJarFiles.isEmpty()) {
            module = loadPlugins(classname, additionalJarFiles);
        } else {
            try {
                Class handlerClass = Class.forName(classname);
                module = (Module) handlerClass.newInstance();
            } catch (ClassNotFoundException exe) {
                log.error("ClassNotFoundException", exe);
            } catch (IllegalAccessException exe) {
                log.error("IllegalAccessException", exe);
            } catch (InstantiationException exe) {
                log.error("InstantiationException", exe);
            }
        }
        return module;
    }

    public Module loadPlugins(String classname, List<String> additionalJarFiles) {
        Module module = null;
        Communication comm = ((Communication) getBean(Beans.COMMUNICATION));
        SiteValue site = comm.getCurrentSite();
        String urlPath = site.getDcfUrl();
        final String userHome = System.getProperty("user.home");
        final String fileSeparator = System.getProperty("file.separator");

        StringBuffer pluginCachePath = new StringBuffer(userHome);
        pluginCachePath.append(fileSeparator);
        pluginCachePath.append(".tizzitCache");
        pluginCachePath.append(fileSeparator);
        pluginCachePath.append("plugins");
        pluginCachePath.append(fileSeparator);
        pluginCachePath.append(Constants.SERVER_HOST);
        pluginCachePath.append(fileSeparator);

        final String pluginPath = pluginCachePath.toString();

        final int addSize = additionalJarFiles.size();

        /* enthaelt alle Jar files die sich nicht auf dem lokalen Rechner befinden */
        ArrayList<String> httpLoad = new ArrayList<String>();

        for (int i = 0; i < addSize; i++) {
            String filePath = pluginPath + additionalJarFiles.get(i);
            File tempFile = new File(filePath);
            if (!tempFile.exists()) {
                httpLoad.add(additionalJarFiles.get(i));
            }
        }

        if (httpLoad.size() > 0) {
            File dir = new File(pluginPath);
            if (!dir.exists()) {
                if (log.isDebugEnabled())
                    log.debug("Going to create plugin directory...");
                boolean ret = dir.mkdirs();
                if (!ret) {
                    log.warn("Could not create plugin directory");
                }
            }

            /* laedt die Jarfiles auf den lokalen Rechner herunter */
            HttpClient httpclient = new HttpClient();
            for (int i = 0; i < httpLoad.size(); i++) {
                String url = urlPath + httpLoad.get(i);
                if (log.isDebugEnabled())
                    log.debug("Plugin URL " + url);
                HttpMethod method = new GetMethod(url);
                try {
                    int status = httpclient.executeMethod(method);
                    if (status == HttpStatus.SC_OK) {
                        File file = new File(pluginPath + httpLoad.get(i));
                        byte[] data = method.getResponseBody();
                        if (log.isDebugEnabled())
                            log.debug("Received " + data.length + " bytes of data");
                        FileOutputStream output = new FileOutputStream(file);
                        output.write(data);
                        output.close();
                    } else {
                        log.warn("No OK received");
                    }
                } catch (HttpException htex) {
                    log.warn("HTTP exception " + htex.getMessage());
                } catch (IOException ioe) {
                    log.warn("IO exception " + ioe.getMessage());
                }
                method.releaseConnection();
            }
        }

        try {
            if (log.isDebugEnabled())
                log.debug("Creating URL");

            URL[] url = new URL[addSize];
            for (int i = 0; i < addSize; i++) {
                String jarModule = additionalJarFiles.get(i);
                String jarPath = "file:///" + pluginPath + jarModule;
                if (log.isDebugEnabled())
                    log.debug("Jar path " + jarPath);
                url[i] = new URL(jarPath);
            }
            URLClassLoader cl = this.getURLClassLoader(url);
            //URLClassLoader cl = new URLClassLoader(url, this.getClass().getClassLoader());
            if (log.isDebugEnabled())
                log.debug("Created URL classloader");
            Class c = cl.loadClass(classname);
            if (log.isDebugEnabled())
                log.debug("Created class");
            module = (Module) c.newInstance();
            if (log.isDebugEnabled())
                log.debug("Got the module");
        } catch (Exception loadex) {
            log.warn(loadex.getClass().toString());
            log.error("Cannot load from URL " + loadex.getMessage(), loadex);
        }
        return module;
    }

    public Iterator<Module> getAllModules() {
        return htModules.values().iterator();
    }

    /**
     * Creates a {@link Module} and configures it with all information taken from the mandator's dcf.
     * 
     * @param dcfelement the randomly named element containing the {@code dcfconfig} element
     * @param contentdata XML content for the module (the way TIZZIT saves it)
     * 
     * @see de.juwimm.cms.content.modules.ModuleFactory#getModuleInstance(org.w3c.dom.Element, org.w3c.dom.Node) */
    public Module getModuleInstance(Element dcfElement, Node contentdata) {
        Module module = null;
        String classname = "";
        List<String> jarClassPath = new ArrayList<String>();
        try {
            classname = XercesHelper.getNodeValue(dcfElement, "./dcfConfig/classname");
            Iterator it = XercesHelper.findNodes(dcfElement, "./dcfConfig/classpath/jar");
            while (it.hasNext()) {
                Node node = (Node) it.next();
                jarClassPath.add(XercesHelper.getNodeValue(node));
            }
            module = getModuleInstanceUnconfigured(classname, jarClassPath);

            String label = dcfElement.getAttribute("label");
            String description = dcfElement.getAttribute("description");
            String dcfname = dcfElement.getAttribute("dcfname");
            String mandatory = XercesHelper.getNodeValue(dcfElement, "./dcfConfig/mandatory");
            module.setLabel(label);
            module.setDescription(description);
            module.setName(dcfname);
            if (mandatory.equals("true")) {
                module.setMandatory(true);
            } else {
                module.setMandatory(false);
            }

            // Fill the custom properties for this dcfmodule explicit for this DCF
            Iterator ni = XercesHelper.findNodes(dcfElement, "./dcfConfig/property");

            setCustomProperties(module, ni);

            if (module instanceof Iteration) {
                Node itEl = XercesHelper.findNode(dcfElement, "./dcfConfig/iterationElements");
                ((Iteration) module).setIterationElements(itEl);
            }

            //Load initial config if there is no current content
            Node ndeInitialContent = XercesHelper.findNode(dcfElement, "./dcfInitial");
            if (ndeInitialContent != null) {
                htInitialContent.put(module.getName(), ndeInitialContent);
            }
            if (contentdata == null) {
                contentdata = ndeInitialContent;
            }
            if (contentdata != null) {
                module.setProperties(contentdata);
            }
        } catch (Exception exe) {
            log.error("Error getting Module instance", exe);
        }
        this.htModules.put(module.getName(), module);
        return module;
    }

    /** 
     * Parses the specified {@code propertyNodes} and prepares the information, 
     * calls {@see Module#setCustomProperties(String, Properties)} 
     * 
     * @see ModuleFactory#setCustomProperties(Module, java.util.Iterator) */
    public void setCustomProperties(Module module, Iterator propertyNodes) {
        try {
            Element property;
            while (propertyNodes.hasNext()) {
                property = (Element) propertyNodes.next();
                String propertyname = property.getAttribute("name");
                Properties prop = new Properties();

                Iterator pi = XercesHelper.findNodes(property, "./*");
                Node propParameter;
                while (pi.hasNext()) {
                    propParameter = (Element) pi.next();
                    String propVal = "";
                    if (propParameter.getNodeName().equalsIgnoreCase("properties")) {
                        propVal = XercesHelper.node2string(propParameter);
                    } else {
                        propVal = XercesHelper.getNodeValue(propParameter);
                    }
                    prop.setProperty(propParameter.getNodeName(), propVal);
                }
                module.setCustomProperties(propertyname, prop);
            }
            module.setCustomProperties("CustomConfigurationReady", new Properties());

        } catch (Exception exe) {
            log.error("Error setting custom properties", exe);
        }
        if (log.isDebugEnabled())
            log.debug("SetModuleParameters end " + module.getName());
    }

    public Module getModuleByDCFName(String dcfname) {
        return this.htModules.get(dcfname);
    }

    public void reconfigureModules(Hashtable<String, Element> htModuleDcfNameDcfElement) {
        Collection coll = this.htModules.values();
        Iterator it = coll.iterator();
        while (it.hasNext()) {
            Module module = (Module) it.next();
            Thread t = new Thread(Thread.currentThread().getThreadGroup(),
                    new ReconfigureModuleRunnable(module, htModuleDcfNameDcfElement, htInitialContent));
            t.setPriority(Thread.NORM_PRIORITY);
            t.setName("ReconfigureModuleRunnable");
            t.start();
        }
    }

    /**
     * Thread calling <code>setProperties(Node)</code> on the given Module with the Node from the DCF
     */
    public class ReconfigureModuleRunnable implements Runnable {
        private Hashtable<String, Element> htModuleDcfNameDcfElement = null;
        private Hashtable<String, Node> htInitialContent = null;
        private Module module = null;

        public ReconfigureModuleRunnable(Module module, Hashtable<String, Element> htModuleDcfNameDcfElement,
                Hashtable<String, Node> htInitialContent) {
            this.module = module;
            this.htModuleDcfNameDcfElement = htModuleDcfNameDcfElement;
            this.htInitialContent = htInitialContent;
        }

        public void run() {
            Node content = htModuleDcfNameDcfElement.get(module.getName());
            if (content != null && content.hasChildNodes()) {
                module.setProperties(content);
            } else {
                module.setProperties(htInitialContent.get(module.getName()));
            }
        }
    }

    public JPanel getPanelForModule(Module module) {
        //ContentBorder cb = new ContentBorderModulePanel();
        //cb.setContentModulePanel(module.viewPanelUI());
        //cb.setLabel(module.getLabel());
        ColapsePanel cbb = new ColapsePanel();
        cbb.setText(module.getLabel());
        cbb.add(module.viewPanelUI());
        return cbb;
    }

    public String isModuleValid() {
        String retVal = "";
        Iterator it = this.htModules.values().iterator();
        while (it.hasNext()) {
            Module mod = (Module) it.next();
            log.info("VALIDATION: FOUND MOD " + mod.getName());
            if (!mod.isModuleValid()) {
                if (!retVal.equals(""))
                    retVal += "<br><hr>";
                String prepend = Messages.getString("content.moduleFactory.validationPrepend", mod.getLabel());
                String errMsg = mod.getValidationError();
                errMsg = errMsg.replaceAll("[\n]", "<br>");
                retVal += "<font face=\"Arial, Helvetica, sans-serif\"><b>" + prepend + "</b><br>" + errMsg
                        + "</font>";
            }
        }
        return retVal;
    }

    public void setEnabled(boolean enable) {
        Iterator it = this.htModules.values().iterator();
        while (it.hasNext()) {
            Module mod = (Module) it.next();
            SwingUtilities.invokeLater(new SetEnabled(mod, enable));
        }
    }

    /**
     * 
     */
    private class SetEnabled implements Runnable {
        private final Module mod;
        private final boolean enable;

        public SetEnabled(Module mod, boolean enable) {
            this.mod = mod;
            this.enable = enable;
        }

        public void run() {
            try {
                mod.setEnabled(enable);
            } catch (Exception exe) {
                log.error("Error setting enabled in setEnabled thread", exe);
            }
        }
    }

    private URLClassLoader getURLClassLoader(URL[] url) {
        ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader();
        URLClassLoader cl = new PluginURLClassLoader(url, previousClassLoader);
        Thread.currentThread().setContextClassLoader(cl);

        return cl;
    }

    /**
     * Special URLClassLoader granting all permissions
     * @author <a href="mailto:carsten.schalm@juwimm.com">Carsten Schalm</a>
     * company Juwi|MacMillan Group Gmbh, Walsrode, Germany
     * @version $Id$
     */
    public class PluginURLClassLoader extends URLClassLoader {

        public PluginURLClassLoader(URL[] url, ClassLoader parent) {
            super(url, parent);
        }

        @Override
        protected PermissionCollection getPermissions(CodeSource codesource) {
            PermissionCollection perms = super.getPermissions(codesource);
            perms.add(new AllPermission());
            return perms;
        }

    }

}