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 }