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