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 }