org.pentaho.platform.plugin.services.pluginmgr.PluginResourceLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.plugin.services.pluginmgr.PluginResourceLoader.java

Source

/*!
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright (c) 2002-2013 Pentaho Corporation..  All rights reserved.
 */

package org.pentaho.platform.plugin.services.pluginmgr;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.pentaho.platform.api.engine.IPluginResourceLoader;
import org.pentaho.platform.api.repository2.unified.RepositoryFile;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.plugin.services.messages.Messages;
import org.pentaho.platform.util.logging.Logger;
import org.pentaho.platform.util.messages.LocaleHelper;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;

/**
 * The default implementation of the {@link IPluginResourceLoader}. Obtains resources by searching the root directory of
 * a {@link PluginClassLoader}.
 * 
 * <h3>Resource discovery</h3> {@link PluginResourceLoader} will search the following places for plugin classes:
 * <ul>
 * <li>the /lib folder under the plugin's root directory, e.g. "myplugin/lib"
 * </ul>
 * {@link PluginResourceLoader} will search for non-class resources in several locations:
 * <ul>
 * <li>inside jar files located in the lib directory
 * <li>from the filesystem relative to the root directory of the plugin
 * </ul>
 * 
 * <h3>resourcePath</h3> This class requires resource paths to be the relative paths to plugin resources, relative the
 * root directory of the plugin. A resource path can be specified either using '/' or '.' (or both) in the path,
 * depending on the particular method you are using. It is usually best to specify the path using '/' since both the
 * filesystem and the classloader can handle this delimiter, whereas '.' will not be handled correctly if you are trying
 * to load a resource from the filesystem.
 * 
 * <h3>Plugin Settings</h3>This class backs the plugin settings APIs with the PentahoSystem settings service. See
 * {@link PentahoSystem#getSystemSetting(String, String)} and {@link ISystemSettings}. System settings are expected in a
 * file named settings.xml in the root of the plugin directory.
 * 
 * @author aphillips
 * 
 */
public class PluginResourceLoader implements IPluginResourceLoader {

    private File rootDir = null;

    private PluginClassLoader overrideClassloader;

    private String settingsPath = RepositoryFile.SEPARATOR + "settings.xml"; //$NON-NLS-1$

    public void setSettingsPath(String settingsPath) {
        this.settingsPath = settingsPath;
    }

    @Deprecated
    public void setOverrideClassloader(PluginClassLoader pluginClassloader) {
        this.overrideClassloader = pluginClassloader;
    }

    protected PluginClassLoader getOverrideClassloader() {
        return overrideClassloader;
    }

    /**
     * Force the resource loader to look for resources in this root directory. If null, the resource loader will consult
     * the {@link PluginClassLoader} for the root directory.
     * 
     * @param rootDir
     *          the root directory in which to search for resources
     * @deprecated instead of setting the root dir, have your application use a subclass of PluginResourceLoader that
     *             returns an appropriately pathed PluginClassLoader from an overridden {@link #getClassLoader(Class)}.
     */
    public void setRootDir(File rootDir) {
        this.rootDir = rootDir;
    }

    public byte[] getResourceAsBytes(Class<? extends Object> clazz, String resourcePath) {
        InputStream in = getResourceAsStream(clazz, resourcePath);
        if (in == null) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            out.write(in);
        } catch (IOException e) {
            Logger.debug(this, "Cannot open stream to resource", e); //$NON-NLS-1$
            return null;
        } finally {
            IOUtils.closeQuietly(in);
        }
        return out.toByteArray();
    }

    public String getResourceAsString(Class<? extends Object> clazz, String resourcePath)
            throws UnsupportedEncodingException {
        return getResourceAsString(clazz, resourcePath, LocaleHelper.getSystemEncoding());
    }

    public String getResourceAsString(Class<? extends Object> clazz, String resourcePath, String charsetName)
            throws UnsupportedEncodingException {
        byte[] bytes = getResourceAsBytes(clazz, resourcePath);
        if (bytes == null) {
            return null;
        }
        return new String(bytes, charsetName);
    }

    public String getSystemRelativePluginPath(ClassLoader classLoader) {
        File dir = getPluginDir(classLoader);
        if (dir == null) {
            return null;
        }
        // get the full path with \ converted to /
        String path = dir.getAbsolutePath().replace("\\", RepositoryFile.SEPARATOR);
        int pos = path.lastIndexOf(RepositoryFile.SEPARATOR + "system" + RepositoryFile.SEPARATOR); //$NON-NLS-1$
        if (pos != -1) {
            path = path.substring(pos + 8);
        }
        return path;
    }

    protected File getPluginDir(ClassLoader classLoader) {
        if (rootDir != null) {
            return rootDir;
        }
        if (classLoader instanceof PluginClassLoader) {
            return ((PluginClassLoader) classLoader).getPluginDir();
        }
        return null;
    }

    /*
     * It is important for this method to exist since it provides a way to override the classloader which is particularly
     * useful in test cases
     */
    protected ClassLoader getClassLoader(Class<?> clazz) {
        PluginClassLoader _overrideClassloader = getOverrideClassloader();
        ClassLoader classLoader = (_overrideClassloader != null) ? _overrideClassloader : clazz.getClassLoader();

        if (!PluginClassLoader.class.isAssignableFrom(classLoader.getClass())) {
            Logger.warn(this,
                    Messages.getInstance().getString("PluginResourceLoader.WARN_CLASS_LOADED_OUTSIDE_OF_PLUGIN_ENV",
                            clazz.getName(), PluginClassLoader.class.getSimpleName(),
                            this.getClass().getSimpleName())); //$NON-NLS-1$
        }
        return classLoader;
    }

    public InputStream getResourceAsStream(Class<?> clazz, String resourcePath) {
        ClassLoader classLoader = getClassLoader(clazz);
        return getResourceAsStream(classLoader, resourcePath);
    }

    public InputStream getResourceAsStream(ClassLoader classLoader, String resourcePath) {
        if (getOverrideClassloader() != null) {
            classLoader = getOverrideClassloader();
        }

        InputStream in = null;

        File root = getPluginDir(classLoader);
        if (root != null) {

            // can we find it on the filesystem?
            File f = new File(root, resourcePath);
            if (f.canRead()) {
                try {
                    in = new BufferedInputStream(new FileInputStream(f));
                } catch (FileNotFoundException e) {
                    Logger.debug(this, "Cannot open stream to resource", e); //$NON-NLS-1$
                }
            } else { //if not in filesystem ask the classloader
                in = classLoader.getResourceAsStream(resourcePath);
                if (in == null) {
                    Logger.debug(this, "Cannot find resource defined by path [" + resourcePath + "]"); //$NON-NLS-1$ //$NON-NLS-2$
                }
            }
        }
        return in;
    }

    public List<URL> findResources(Class<?> clazz, String namePattern) {
        ClassLoader classLoader = getClassLoader(clazz);
        return findResources(classLoader, namePattern);
    }

    public List<URL> findResources(ClassLoader classLoader, String namePattern) {

        String dirPattern = "", filePattern = "*"; //$NON-NLS-1$ //$NON-NLS-2$

        if (namePattern.contains("/")) { //$NON-NLS-1$
            String pattern = namePattern.substring(0, namePattern.lastIndexOf('/'));
            if (pattern.length() > 0) {
                dirPattern = pattern;
            }
            pattern = namePattern.substring(namePattern.lastIndexOf('/') + 1, namePattern.length());
            if (pattern.length() > 0) {
                filePattern = pattern;
            }
        } else {
            filePattern = namePattern;
        }

        IOFileFilter fileFilter = new WildcardFileFilter(filePattern);
        IOFileFilter dirFilter = TrueFileFilter.INSTANCE;

        Collection<?> files = FileUtils.listFiles(new File(getPluginDir(classLoader), dirPattern), fileFilter,
                dirFilter);
        Iterator<?> fileIter = files.iterator();
        List<URL> urls = new ArrayList<URL>(files.size());
        while (fileIter.hasNext()) {
            try {
                urls.add(((File) fileIter.next()).toURI().toURL());
            } catch (MalformedURLException e) {
                Logger.warn(this, "Could not create url", e); //$NON-NLS-1$
            }
        }
        return urls;
    }

    public ResourceBundle getResourceBundle(Class<?> clazz, String resourcePath) {
        ResourceBundle bundle = ResourceBundle.getBundle(resourcePath, LocaleHelper.getLocale(),
                getClassLoader(clazz));
        return bundle;
    }

    public String getPluginSetting(Class<?> pluginClass, String key) {
        return getPluginSetting(pluginClass, key, null);
    }

    public String getPluginSetting(Class<?> pluginClass, String key, String defaultVal) {
        ClassLoader classLoader = getClassLoader(pluginClass);
        String pluginPath = getSystemRelativePluginPath(classLoader);
        File absPluginPath = getPluginDir(classLoader);
        if (pluginPath == null) {
            Logger.debug(this, Messages.getInstance().getString("PluginResourceLoader.WARN_PLUGIN_PATH_BAD", //$NON-NLS-1$
                    "" + pluginClass, settingsPath, key));
            return defaultVal;
        }
        File settingsFile = new File(absPluginPath, settingsPath);
        if (!settingsFile.exists()) {
            Logger.debug(this, Messages.getInstance().getErrorString(
                    "SYSTEMSETTINGS.ERROR_0002_FILE_NOT_IN_SOLUTION", settingsFile.getAbsolutePath())); //$NON-NLS-1$
            return defaultVal;
        }
        return PentahoSystem.getSystemSetting(pluginPath + settingsPath, key, defaultVal);
    }

    public String getPluginSetting(ClassLoader classLoader, String key, String defaultVal) {
        if (getOverrideClassloader() != null) {
            classLoader = getOverrideClassloader();
        }
        String pluginPath = getSystemRelativePluginPath(classLoader);
        if (pluginPath == null) {
            Logger.debug(this, Messages.getInstance().getString("PluginResourceLoader.WARN_PLUGIN_PATH_BAD", //$NON-NLS-1$
                    "" + classLoader, settingsPath, key));
            return defaultVal;
        }

        File absPluginPath = getPluginDir(classLoader);
        File settingsFile = new File(absPluginPath, settingsPath);
        if (!settingsFile.exists()) {
            Logger.debug(this, Messages.getInstance().getErrorString(
                    "SYSTEMSETTINGS.ERROR_0002_FILE_NOT_IN_SOLUTION", settingsFile.getAbsolutePath())); //$NON-NLS-1$
            return defaultVal;
        }

        return PentahoSystem.getSystemSetting(pluginPath + settingsPath, key, defaultVal);
    }

}