001    /**
002     * Copyright 2005-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.kew.plugin;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.apache.log4j.Logger;
020    import org.kuali.rice.core.api.config.CoreConfigHelper;
021    import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
022    import org.kuali.rice.core.api.resourceloader.ResourceLoader;
023    import org.kuali.rice.core.framework.resourceloader.BaseResourceLoader;
024    import org.kuali.rice.core.impl.resourceloader.ResourceLoaderUtil;
025    
026    import javax.xml.namespace.QName;
027    import java.io.File;
028    import java.io.FileFilter;
029    import java.io.FilenameFilter;
030    import java.util.Iterator;
031    import java.util.List;
032    
033    
034    /**
035     * Various plugin utilities.
036     *
037     * @author Kuali Rice Team (rice.collab@kuali.org)
038     */
039    public final class PluginUtils {
040    
041        private static final Logger LOG = Logger.getLogger(PluginUtils.class);
042        private static final String SHARED_DIR = "shared";
043    
044        // maximum time we should wait for a new plugin directory to stop being
045        // modified before we give up on loading it this time around
046        public static final long INFINITE_MAX_WAIT = -1;
047        // NOTE: must be greater than the SAFE TIME
048        public static final long DEFAULT_MAX_WAIT = 90000;
049    
050        // amount of time since the last time the plugin dir was updated that we
051        // consider "safe" to proceed with registering the plugin
052        // basically, with the current implementation, an amount of time that we
053        // expect any files in process of modification to complete (e.g. copy)
054        // NOTE: MUST be LESS than the MAX WAIT otherwise, we will ALWAYS fail to wait
055        public static final long DEFAULT_SAFE_TIME = 60000;
056    
057        private static final FilenameFilter JAR_FILES_FILTER = new FilenameFilter() {
058            public boolean accept(File dir, String name) {
059                return name.matches(".+\\.jar");
060            }
061        };
062    
063        private static final FileFilter SHARED_DIR_FILTER = new FileFilter() {
064            public boolean accept(File file) {
065                return file.isDirectory() && file.getName().equals(SHARED_DIR);
066            }
067        };
068        
069            private PluginUtils() {
070                    throw new UnsupportedOperationException("do not call");
071            }
072    
073        public static class PluginZipFileFilter implements FileFilter {
074            public boolean accept(File file) {
075                return file.isFile() && file.getName().endsWith(".zip");
076            }
077        }
078    
079        public static String getLogPrefix(Plugin plugin) {
080            return getLogPrefix(plugin.getName());
081        }
082    
083        public static String getLogPrefix(QName pluginName) {
084            return "[Plugin: " + pluginName + "]";
085        }
086    
087        static File[] findJars(File libDir) {
088            File[] jarFiles = new File[0];
089            if (libDir.isDirectory()) {
090                jarFiles = libDir.listFiles(JAR_FILES_FILTER);
091            }
092            return jarFiles;
093        }
094    
095        public static File findSharedDirectory(List pluginDirectories) {
096            for (Iterator iterator = pluginDirectories.iterator(); iterator.hasNext();) {
097                File dir = new File((String) iterator.next());
098                if (dir.isDirectory()) {
099                    File[] subDirs = dir.listFiles(SHARED_DIR_FILTER);
100                    if (subDirs.length > 0) {
101                        return subDirs[0];
102                    }
103                }
104            }
105            return null;
106        }
107    
108        public static void validatePluginZipFile(File file) {
109            if (file == null) {
110                            throw new IllegalArgumentException("Given plugin file was 'null'");
111                    } else if (!file.exists()) {
112                            throw new IllegalArgumentException("Given plugin file does not exist: " + file.getAbsolutePath());
113                    } else if (!file.isFile()) {
114                            throw new IllegalArgumentException("Given plugin file is not a valid file: " + file.getAbsolutePath());
115                    } else if (!file.canRead()) {
116                            throw new IllegalArgumentException("Permission denied to read given plugin file: " + file.getAbsolutePath());
117                    } else if (!file.getName().endsWith(".zip")) {
118                            throw new IllegalArgumentException("Given plugin file does not end in .zip extension: " + file.getAbsolutePath());
119                    }
120            // now look at the directory the plugin file is in because we need to be able to extract it there
121            File pluginDirectory = file.getParentFile();
122            validatePluginDirectory(pluginDirectory);
123            // also verify that we can write to this directory
124            if (pluginDirectory == null) {
125                    throw new IllegalArgumentException("Given plugin directory was 'null'");
126            } else if (!pluginDirectory.canWrite()) {
127                    throw new IllegalArgumentException("Impossible to write to plugin directory so plugin cannot be expanded: " + pluginDirectory.getAbsolutePath());
128            }
129        }
130    
131        public static void validatePluginDirectory(File directory) {
132            if (directory == null) {
133                            throw new IllegalArgumentException("Given directory was 'null'");
134                    } else if (!directory.exists()) {
135                            throw new IllegalArgumentException("Given directory does not exist: " + directory.getAbsolutePath());
136                    } else if (!directory.isDirectory()) {
137                            throw new IllegalArgumentException("Given plugin directory is not a valid directory: " + directory.getAbsolutePath());
138                    } else if (!directory.canRead()) {
139                            throw new IllegalArgumentException("Permission denied to read given plugin directory: " + directory.getAbsolutePath());
140                    }
141        }
142    
143        public static PluginRegistry getPluginRegistry() {
144            return (PluginRegistry)GlobalResourceLoader.getResourceLoader(new QName(CoreConfigHelper.getApplicationId(), ResourceLoader.PLUGIN_REGISTRY_LOADER_NAME));
145        }
146    
147        public static void installResourceLoader(Plugin plugin) {
148            if (plugin.getConfig() instanceof PluginConfig) {
149                            PluginConfig pluginConfig = (PluginConfig)plugin.getConfig();
150                            if (!StringUtils.isEmpty(pluginConfig.getResourceLoaderClassname())) {
151                    ResourceLoader resourceLoader = (ResourceLoader) ResourceLoaderUtil.createObject(pluginConfig.getResourceLoaderClassname(), plugin.getClassLoader());
152                    if (resourceLoader == null) {
153                        LOG.warn("Could not create resource loader from plugin resource loader class: " + pluginConfig.getResourceLoaderClassname());
154                        // if null, use a default resource loader
155                                            resourceLoader = new BaseResourceLoader(plugin.getName());
156                    }
157                                    plugin.addResourceLoader(resourceLoader);
158                            }
159                    }
160        }
161    
162        public static void installPluginListeners(Plugin plugin) {
163            if (plugin.getConfig() instanceof PluginConfig) {
164                            PluginConfig pluginConfig = (PluginConfig)plugin.getConfig();
165                            for (Iterator iterator = pluginConfig.getListeners().iterator(); iterator.hasNext();) {
166                        String pluginListenerClassName = (String) iterator.next();
167                        try {
168                            Class listenerClass = Class.forName(pluginListenerClassName, true, plugin.getClassLoader());
169                            plugin.addPluginListener((PluginListener)listenerClass.newInstance());
170                        } catch (ClassNotFoundException e) {
171                            throw new PluginException(getLogPrefix(plugin)+" Error finding listener class '"+pluginListenerClassName+"'.", e);
172                        } catch (InstantiationException e) {
173                            throw new PluginException(getLogPrefix(plugin)+" Error creating an instance of listener class '"+pluginListenerClassName+"'.", e);
174                        } catch (IllegalAccessException e) {
175                            throw new PluginException(getLogPrefix(plugin)+" Error creating an instance of listener class '"+pluginListenerClassName+"'.", e);
176                        } catch (ClassCastException e) {
177                            throw new PluginException(getLogPrefix(plugin)+" Listener class '"+pluginListenerClassName+"' does not implement PluginListener.", e);
178                        }
179                    }
180                    }
181        }
182    }