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 }