/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright 2008-2009 Pentaho Corporation. All rights reserved.
*
*/
package org.pentaho.platform.plugin.services.pluginmgr;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.pentaho.platform.api.engine.IContentGenerator;
import org.pentaho.platform.api.engine.IContentGeneratorInfo;
import org.pentaho.platform.api.engine.IContentInfo;
import org.pentaho.platform.api.engine.IFileInfo;
import org.pentaho.platform.api.engine.IFileInfoGenerator;
import org.pentaho.platform.api.engine.IPentahoObjectFactory;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.IPlatformPlugin;
import org.pentaho.platform.api.engine.IPluginLifecycleListener;
import org.pentaho.platform.api.engine.IPluginProvider;
import org.pentaho.platform.api.engine.IPluginResourceLoader;
import org.pentaho.platform.api.engine.IServiceManager;
import org.pentaho.platform.api.engine.ISolutionFile;
import org.pentaho.platform.api.engine.ISolutionFileMetaProvider;
import org.pentaho.platform.api.engine.ObjectFactoryException;
import org.pentaho.platform.api.engine.PlatformPluginRegistrationException;
import org.pentaho.platform.api.engine.PluginBeanDefinition;
import org.pentaho.platform.api.engine.PluginBeanException;
import org.pentaho.platform.api.engine.PluginLifecycleException;
import org.pentaho.platform.api.engine.PluginServiceDefinition;
import org.pentaho.platform.api.engine.ServiceException;
import org.pentaho.platform.api.engine.ServiceInitializationException;
import org.pentaho.platform.api.engine.IPentahoDefinableObjectFactory.Scope;
import org.pentaho.platform.api.repository.ISolutionRepository;
import org.pentaho.platform.engine.core.solution.FileInfo;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.plugin.services.messages.Messages;
import org.pentaho.platform.plugin.services.pluginmgr.servicemgr.ServiceConfig;
import org.pentaho.platform.util.logging.Logger;
@SuppressWarnings("deprecation")
public class DefaultPluginManager extends AbstractPluginManager {
private Map<String, ClassLoader> classLoaderMap = Collections.synchronizedMap(new HashMap<String, ClassLoader>());
public DefaultPluginManager() {
}
/**
* Clears all the lists and maps in preparation for
* reloading the state from the plugin provider.
* Fires the plugin unloaded event for each known plugin.
*/
private void unloadPlugins() {
overlaysCache.clear();
menuCustomizationsCache.clear();
classLoaderMap.clear();
contentGeneratorInfoByIdMap.clear();
contentGeneratorInfoByTypeMap.clear();
contentTypeByExtension.clear();
objectFactory.init(null, null);
//we do not need to synchronize here since unloadPlugins
//is called within the synchronized block in reload
for (IPlatformPlugin plugin : registeredPlugins.values()) {
try {
plugin.unLoaded();
} catch (Throwable t) {
//we do not want any type of exception to leak out and cause a problem here
//A plugin unload should not adversely affect anything downstream, it should
//log an error and otherwise fail silently
String msg = Messages.getInstance().getErrorString(
"PluginManager.ERROR_0014_PLUGIN_FAILED_TO_PROPERLY_UNLOAD", plugin.getId()); //$NON-NLS-1$
Logger.error(getClass().toString(), msg, t);
PluginMessageLogger.add(msg);
}
}
registeredPlugins.clear();
}
public final boolean reload(IPentahoSession session) {
boolean anyErrors = false;
IPluginProvider pluginProvider = PentahoSystem.get(IPluginProvider.class, session);
List<IPlatformPlugin> providedPlugins = null;
try {
synchronized (registeredPlugins) {
this.unloadPlugins();
}
//the plugin may fail to load during getPlugins without an exception thrown if the provider
//is capable of discovering the plugin fine but there are structural problems with the plugin
//itself. In this case a warning should be logged by the provider, but, again, no exception
//is expected.
providedPlugins = pluginProvider.getPlugins(session);
} catch (PlatformPluginRegistrationException e1) {
String msg = Messages.getInstance().getErrorString("PluginManager.ERROR_0012_PLUGIN_DISCOVERY_FAILED"); //$NON-NLS-1$
Logger.error(getClass().toString(), msg, e1);
PluginMessageLogger.add(msg);
anyErrors = true;
}
objectFactory.init(null, null);
synchronized (providedPlugins) {
for (IPlatformPlugin plugin : providedPlugins) {
try {
registerPlugin(plugin, session);
registeredPlugins.put(plugin.getId(), plugin);
} catch (Throwable t) {
// this has been logged already
anyErrors = true;
String msg = Messages.getInstance().getErrorString("PluginManager.ERROR_0011_FAILED_TO_REGISTER_PLUGIN", plugin.getId()); //$NON-NLS-1$
Logger.error(getClass().toString(), msg, t);
PluginMessageLogger.add(msg);
}
}
}
IServiceManager svcManager = PentahoSystem.get(IServiceManager.class, null);
try {
svcManager.initServices();
} catch (ServiceInitializationException e) {
String msg = Messages.getInstance().getErrorString("PluginManager.ERROR_0022_SERVICE_INITIALIZATION_FAILED"); //$NON-NLS-1$
Logger.error(getClass().toString(), msg, e);
PluginMessageLogger.add(msg);
}
return !anyErrors;
}
/**
* Gets the plugin ready to handle lifecycle events.
*/
private static void bootStrapPlugin(IPlatformPlugin plugin, ClassLoader loader)
throws PlatformPluginRegistrationException {
Object listener = null;
try {
if (!StringUtils.isEmpty(plugin.getLifecycleListenerClassname())) {
listener = loader.loadClass(plugin.getLifecycleListenerClassname()).newInstance();
}
} catch (Throwable t) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0017_COULD_NOT_LOAD_PLUGIN_LIFECYCLE_LISTENER", plugin.getId(), plugin //$NON-NLS-1$
.getLifecycleListenerClassname()), t);
}
if (listener != null) {
if (!IPluginLifecycleListener.class.isAssignableFrom(listener.getClass())) {
throw new PlatformPluginRegistrationException(
Messages.getInstance()
.getErrorString(
"PluginManager.ERROR_0016_PLUGIN_LIFECYCLE_LISTENER_WRONG_TYPE", plugin.getId(), plugin.getLifecycleListenerClassname())); //$NON-NLS-1$
}
plugin.addLifecycleListener((IPluginLifecycleListener) listener);
}
}
@SuppressWarnings("unchecked")
private void registerPlugin(final IPlatformPlugin plugin, IPentahoSession session)
throws PlatformPluginRegistrationException, PluginLifecycleException {
//TODO: we should treat the registration of a plugin as an atomic operation
//with rollback if something is broken
if(StringUtils.isEmpty(plugin.getId())) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0026_PLUGIN_INVALID", plugin.getSourceDescription())); //$NON-NLS-1$
}
if (registeredPlugins.containsKey(plugin.getId())) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0024_PLUGIN_ALREADY_LOADED_BY_SAME_NAME", plugin.getId())); //$NON-NLS-1$
}
ClassLoader loader = setPluginClassLoader(plugin);
bootStrapPlugin(plugin, loader);
plugin.init();
registerContentTypes(plugin, loader);
registerContentGenerators(plugin, loader);
//cache overlays
overlaysCache.addAll(plugin.getOverlays());
//cache menu customizations
menuCustomizationsCache.addAll(plugin.getMenuCustomizations());
registerBeans(plugin, loader, session);
//service registry must take place after bean registry since
//a service class may be configured as a plugin bean
registerServices(plugin, loader);
PluginMessageLogger.add(Messages.getInstance().getString("PluginManager.PLUGIN_REGISTERED", plugin.getId())); //$NON-NLS-1$
try {
plugin.loaded();
} catch (Throwable t) {
//The plugin has already been loaded, so there is really no logical response to any type
//of failure here except to log an error and otherwise fail silently
String msg = Messages.getInstance().getErrorString("PluginManager.ERROR_0015_PLUGIN_LOADED_HANDLING_FAILED", plugin.getId()); //$NON-NLS-1$
Logger.error(getClass().toString(), msg, t);
PluginMessageLogger.add(msg);
}
}
private void registerContentTypes(IPlatformPlugin plugin, ClassLoader loader)
throws PlatformPluginRegistrationException {
//index content types and define any file meta providers
for (IContentInfo info : plugin.getContentInfos()) {
contentTypeByExtension.put(info.getExtension(), info);
String metaProviderClass = plugin.getMetaProviderMap().get(info.getExtension());
//if a meta-provider is defined for this content type, then register it...
if (!StringUtils.isEmpty(metaProviderClass)) {
Class<?> clazz = null;
String defaultErrMsg = Messages.getInstance()
.getErrorString(
"PluginManager.ERROR_0013_FAILED_TO_SET_CONTENT_TYPE_META_PROVIDER", metaProviderClass, info.getExtension()); //$NON-NLS-1$
try {
//do a test load to fail early if class not found
clazz = loader.loadClass(metaProviderClass);
} catch (Exception e) {
throw new PlatformPluginRegistrationException(defaultErrMsg, e);
}
//check that the class is an accepted type
if (!(ISolutionFileMetaProvider.class.isAssignableFrom(clazz) || IFileInfoGenerator.class
.isAssignableFrom(clazz))) {
throw new PlatformPluginRegistrationException(
Messages.getInstance()
.getErrorString(
"PluginManager.ERROR_0019_WRONG_TYPE_FOR_CONTENT_TYPE_META_PROVIDER", metaProviderClass, info.getExtension())); //$NON-NLS-1$
}
//the class is ok, so register it with the factory
objectFactory.defineObject(info.getExtension(), metaProviderClass, Scope.LOCAL, loader);
try {
//check that the class can be instantiated
//we have to tell the factory to return us an Object since the instance could be one of 2 permissible types
objectFactory.get(Object.class, info.getExtension(), null); //solution file meta providers cannot be session scoped, so null is ok here
} catch (Exception e) {
throw new PlatformPluginRegistrationException(defaultErrMsg, e);
}
}
}
}
private void registerBeans(IPlatformPlugin plugin, ClassLoader loader, IPentahoSession session)
throws PlatformPluginRegistrationException {
//we do not have to synchronize on the bean set here because the
//map that backs the set is never modified after the plugin has
//been made available to the plugin manager
for (PluginBeanDefinition def : plugin.getBeans()) {
//register by classname if id is null
def.setBeanId((def.getBeanId() == null) ? def.getClassname() : def.getBeanId());
registerClass(plugin, def.getBeanId(), def.getClassname(), loader);
}
}
/*
* A utility method that wraps plugin class registration with proper error handling and messaging
*/
private void registerClass(IPlatformPlugin plugin, String id, String classname, ClassLoader loader)
throws PlatformPluginRegistrationException {
if (objectFactory.objectDefined(id)) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0018_BEAN_ALREADY_REGISTERED", id, plugin.getId())); //$NON-NLS-1$
}
//right now we support only prototype scope for beans
objectFactory.defineObject(id, classname, Scope.LOCAL, loader);
}
private void registerServices(IPlatformPlugin plugin, ClassLoader loader) throws PlatformPluginRegistrationException {
IServiceManager svcManager = PentahoSystem.get(IServiceManager.class, null);
for (PluginServiceDefinition pws : plugin.getServices()) {
for (ServiceConfig ws : createServiceConfigs(pws, plugin, loader)) {
try {
svcManager.registerService(ws);
} catch (ServiceException e) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0025_SERVICE_REGISTRATION_FAILED", ws.getId(), plugin.getId()), e); //$NON-NLS-1$
}
}
}
}
/*
* A utility method to convert plugin version of webservice definition to the official engine version
* consumable by an IServiceManager
*/
private Collection<ServiceConfig> createServiceConfigs(PluginServiceDefinition pws,
IPlatformPlugin plugin, ClassLoader loader) throws PlatformPluginRegistrationException {
Collection<ServiceConfig> services = new ArrayList<ServiceConfig>();
//Set the service type (one service config instance created per service type)
//
if (pws.getTypes() == null || pws.getTypes().length < 1) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0023_SERVICE_TYPE_UNSPECIFIED", pws.getId())); //$NON-NLS-1$
}
for (String type : pws.getTypes()) {
ServiceConfig ws = new ServiceConfig();
ws.setServiceType(type);
ws.setTitle(pws.getTitle());
ws.setDescription(pws.getDescription());
String serviceClassName = (StringUtils.isEmpty(pws.getServiceClass())) ? pws.getServiceBeanId() : pws.getServiceClass();
String serviceId;
if (!StringUtils.isEmpty(pws.getId())) {
serviceId = pws.getId();
} else {
serviceId = serviceClassName;
if (serviceClassName.indexOf('.') > 0) {
serviceId = serviceClassName.substring(serviceClassName.lastIndexOf('.') + 1);
}
}
ws.setId(serviceId);
//Register the service class
//
final String serviceClassKey = ws.getServiceType() + "-" + ws.getId() + "/" + serviceClassName; //$NON-NLS-1$ //$NON-NLS-2$
registerClass(plugin, serviceClassKey, serviceClassName, loader);
if (!this.isBeanRegistered(serviceClassKey)) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0020_NO_SERVICE_CLASS_REGISTERED", serviceClassKey)); //$NON-NLS-1$
}
//Load/set the service class and supporting types
//
try {
ws.setServiceClass(loadClass(serviceClassKey));
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
if (pws.getExtraClasses() != null) {
for (String extraClass : pws.getExtraClasses()) {
classes.add(loadClass(extraClass));
}
}
ws.setExtraClasses(classes);
} catch (PluginBeanException e) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString(
"PluginManager.ERROR_0021_SERVICE_CLASS_LOAD_FAILED", serviceClassKey), e); //$NON-NLS-1$
}
services.add(ws);
}
return services;
}
private ClassLoader setPluginClassLoader(IPlatformPlugin plugin) throws PlatformPluginRegistrationException {
ClassLoader loader = classLoaderMap.get(plugin.getId());
if (loader == null) {
String pluginDirPath = PentahoSystem.getApplicationContext().getSolutionPath(
"system/" + plugin.getSourceDescription()); //$NON-NLS-1$
//need to scrub out duplicate file delimeters otherwise we will
//not be able to locate resources in jars. This classloader ultimately
//needs to be made less fragile
pluginDirPath = pluginDirPath.replace("//", "/"); //$NON-NLS-1$ //$NON-NLS-2$
Logger.debug(this, "plugin dir for " + plugin.getId() + " is [" + pluginDirPath + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
File pluginDir = new File(pluginDirPath);
if(!pluginDir.exists() || !pluginDir.isDirectory() || !pluginDir.canRead()) {
throw new PlatformPluginRegistrationException(Messages.getInstance().getErrorString("PluginManager.ERROR_0027_PLUGIN_DIR_UNAVAILABLE", pluginDir.getAbsolutePath())); //$NON-NLS-1$
}
loader = new PluginClassLoader(pluginDir, this.getClass().getClassLoader());
if(plugin.getLoaderType() == IPlatformPlugin.ClassLoaderType.OVERRIDING) {
((PluginClassLoader)loader).setOverrideLoad(true);
}
classLoaderMap.put(plugin.getId(), loader);
}
return loader;
}
public ClassLoader getClassLoader(IPlatformPlugin plugin) {
return getClassLoader(plugin.getId());
}
public ClassLoader getClassLoader(String pluginId) {
return classLoaderMap.get(pluginId);
}
private void registerContentGenerators(IPlatformPlugin plugin, ClassLoader loader)
throws PlatformPluginRegistrationException {
//register the content generators
for (IContentGeneratorInfo cgInfo : plugin.getContentGenerators()) {
String errorMsg = Messages.getInstance().getString(
"PluginManager.USER_CONTENT_GENERATOR_NOT_REGISTERED", cgInfo.getId(), plugin.getId()); //$NON-NLS-1$
//test load the content generator
try {
Class<?> clazz = Class.forName(cgInfo.getClassname(), false, loader);
objectFactory.defineObject(clazz.getSimpleName(), cgInfo.getClassname(), Scope.LOCAL, loader);
objectFactory.defineObject(cgInfo.getId(), cgInfo.getClassname(), Scope.LOCAL, loader);
} catch (Exception e) {
throw new PlatformPluginRegistrationException(errorMsg, e);
}
// do a test load of the content generator so we can fail now if the class cannot be found
// this tests class loading and cast class issues
Object tmpObject;
try {
tmpObject = objectFactory.get(Object.class, cgInfo.getId(), null); //content generators cannot be session scoped, so null is ok here
} catch (ObjectFactoryException e) {
throw new PlatformPluginRegistrationException(errorMsg, e);
}
//try to cast it to make sure it's the correct type, we want an exception to be thrown if not
@SuppressWarnings("unused")
IContentGenerator cg = (IContentGenerator) tmpObject;
//create the file info generator
if (cgInfo.getFileInfoGeneratorClassname() != null) {
// try to create the fileinfo generator class
try {
objectFactory.defineObject(cgInfo.getType(), cgInfo.getFileInfoGeneratorClassname(), Scope.LOCAL, loader);
} catch (Exception e) {
throw new PlatformPluginRegistrationException(
Messages.getInstance()
.getErrorString(
"PluginManager.ERROR_0013_FAILED_TO_CREATE_FILE_INFO_GENERATOR", cgInfo.getFileInfoGeneratorClassname(), cgInfo.getType()), e); //$NON-NLS-1$
}
}
contentGeneratorInfoByIdMap.put(cgInfo.getId(), cgInfo);
List<IContentGeneratorInfo> generatorList = contentGeneratorInfoByTypeMap.get(cgInfo.getType());
if (generatorList == null) {
generatorList = new ArrayList<IContentGeneratorInfo>();
contentGeneratorInfoByTypeMap.put(cgInfo.getType(), generatorList);
}
generatorList.add(cgInfo);
PluginMessageLogger.add(Messages.getInstance().getString(
"PluginManager.USER_CONTENT_GENERATOR_REGISTERED", cgInfo.getId(), plugin.getId())); //$NON-NLS-1$
}
}
public IPentahoObjectFactory getBeanFactory() {
return objectFactory;
}
public Object getBean(String beanId) throws PluginBeanException {
if (beanId == null) {
throw new IllegalArgumentException("beanId cannot be null"); //$NON-NLS-1$
}
if (objectFactory.objectDefined(beanId)) {
Object bean = null;
try {
//TODO: should we allow session scoped beans?, if so we need to pass in the session
//It looks ugly to pass Object.class to the object factory. This is the way it must
//be unless we want to support null interfaceClass in which case the factory will not
//cast the resultant object.
bean = objectFactory.get(Object.class, beanId, null);
return bean;
} catch (Throwable ex) { // Catching throwable on purpose
throw new PluginBeanException(ex);
}
} else {
throw new PluginBeanException(Messages.getInstance().getString("PluginManager.WARN_CLASS_NOT_REGISTERED")); //$NON-NLS-1$
}
}
public Class<?> loadClass(String beanId) throws PluginBeanException {
if (beanId == null) {
throw new IllegalArgumentException("beanId cannot be null"); //$NON-NLS-1$
}
if (objectFactory.objectDefined(beanId)) {
try {
return objectFactory.getImplementingClass(beanId);
} catch (Throwable ex) { // Catching throwable on purpose
throw new PluginBeanException(ex);
}
} else {
throw new PluginBeanException(Messages.getInstance().getString("PluginManager.WARN_CLASS_NOT_REGISTERED", beanId)); //$NON-NLS-1$
}
}
public boolean isBeanRegistered(String beanId) {
if (beanId == null) {
throw new IllegalArgumentException("beanId cannot be null"); //$NON-NLS-1$
}
return objectFactory.objectDefined(beanId);
}
public void unloadAllPlugins() {
synchronized (registeredPlugins) {
this.unloadPlugins();
}
}
public IFileInfo getFileInfo(String extension, IPentahoSession session, ISolutionFile solutionFile, InputStream in) {
IFileInfo fileInfo = null;
try {
IFileInfoGenerator fileInfoGenerator = null;
if (objectFactory.objectDefined(extension)) {
fileInfoGenerator = objectFactory.get(IFileInfoGenerator.class, extension, null); //session scope not supported for meta providers
}
if (fileInfoGenerator instanceof ISolutionFileMetaProvider) {
// new good stuff
ISolutionFileMetaProvider provider = (ISolutionFileMetaProvider) fileInfoGenerator;
fileInfo = provider.getFileInfo(solutionFile, in);
} else {
// old nasty stuff
fileInfo = getLegacyFileInfo(fileInfoGenerator, session, solutionFile);
}
} catch (Throwable t) {
// we cannot allow a plugin to break our application, so we *MUST* catch
// throwable here (think about AbstractMethodError for example)
// fileInfo will remain null if we hit an exception here, but just to make
// sure, we'll make sure to set it
t.printStackTrace();
fileInfo = null;
}
if (fileInfo == null) {
/* create a fallback file info based on the information from the solution file */
fileInfo = new FileInfo();
fileInfo.setTitle(solutionFile.getFileName());
fileInfo.setDescription("failsafe: " + solutionFile.getFullPath()); //$NON-NLS-1$
fileInfo.setDisplayType(solutionFile.getExtension());
}
return fileInfo;
}
private static IFileInfo getLegacyFileInfo(IFileInfoGenerator fileInfoGenerator, IPentahoSession session,
ISolutionFile solutionFile) {
IFileInfo fileInfo = null;
try {
String fullPath = solutionFile.getFullPath();
String solution = solutionFile.getSolution();
String fileName = solutionFile.getFileName();
String path = solutionFile.getSolutionPath();
IFileInfoGenerator.ContentType contentType = fileInfoGenerator.getContentType();
ISolutionRepository repository = PentahoSystem.get(ISolutionRepository.class, session);
if (contentType == IFileInfoGenerator.ContentType.INPUTSTREAM) {
InputStream in = repository.getResourceInputStream(fullPath, true, ISolutionRepository.ACTION_EXECUTE);
fileInfo = fileInfoGenerator.getFileInfo(solution, path, fileName, in);
} else if (contentType == IFileInfoGenerator.ContentType.DOM4JDOC) {
Document doc = repository.getResourceAsDocument(fullPath, ISolutionRepository.ACTION_EXECUTE);
fileInfo = fileInfoGenerator.getFileInfo(solution, path, fileName, doc);
} else if (contentType == IFileInfoGenerator.ContentType.BYTES) {
byte bytes[] = repository.getResourceAsBytes(fullPath, true, ISolutionRepository.ACTION_EXECUTE);
fileInfo = fileInfoGenerator.getFileInfo(solution, path, fileName, bytes);
} else if (contentType == IFileInfoGenerator.ContentType.STRING) {
String str = repository.getResourceAsString(fullPath, ISolutionRepository.ACTION_EXECUTE);
fileInfo = fileInfoGenerator.getFileInfo(solution, path, fileName, str);
}
} catch (Exception e) {
//we don't care if an error occurred, we'll just return null and the caller will handle it
}
return fileInfo;
}
public Object getPluginSetting(IPlatformPlugin plugin, String key, String defaultValue) {
return getPluginSetting(plugin.getId(), key, defaultValue);
}
public Object getPluginSetting(String pluginId, String key, String defaultValue) {
IPluginResourceLoader resLoader = PentahoSystem.get(IPluginResourceLoader.class, null);
ClassLoader classLoader = classLoaderMap.get(pluginId);
return resLoader.getPluginSetting(classLoader, key, defaultValue);
}
public IPlatformPlugin isResourceLoadable(String path) {
PlatformPlugin p = new PlatformPlugin();
p.setId(getServicePlugin(path));
return p;
}
public String getServicePlugin(String path) {
//normalize path for comparison
path = (path.startsWith("/")) ? path.substring(1) : path; //$NON-NLS-1$
for (IPlatformPlugin plugin : registeredPlugins.values()) {
String pluginId = getStaticResourcePluginId(plugin, path);
if (pluginId != null) {
return pluginId;
}
for (IContentGeneratorInfo contentGenerator : plugin.getContentGenerators()) {
String cgId = contentGenerator.getId();
//content generator ids cannot start with '/', so no need to normalize cg ids
if (path.startsWith(cgId)) {
return plugin.getId();
}
}
}
return null;
}
private String getStaticResourcePluginId(IPlatformPlugin plugin, String path) {
Map<String, String> resourceMap = plugin.getStaticResourceMap();
for (String url : resourceMap.keySet()) {
//normalize static url for comparison
url = (url.startsWith("/")) ? url.substring(1) : url; //$NON-NLS-1$
if (path.startsWith(url)) {
return plugin.getId();
}
}
return null;
}
public boolean isStaticResource(String path) {
// normalize path for comparison
path = (path.startsWith("/")) ? path.substring(1) : path; //$NON-NLS-1$
for (IPlatformPlugin plugin : registeredPlugins.values()) {
String pluginId = getStaticResourcePluginId(plugin, path);
if (pluginId != null) {
return true;
}
}
return false;
}
public InputStream getStaticResource(String path) {
for (IPlatformPlugin plugin : registeredPlugins.values()) {
Map<String, String> resourceMap = plugin.getStaticResourceMap();
for (String url : resourceMap.keySet()) {
if (path.startsWith(url, 1) || path.startsWith(url)) {
IPluginResourceLoader resLoader = PentahoSystem.get(IPluginResourceLoader.class, null);
ClassLoader classLoader = classLoaderMap.get(plugin.getId());
String resourcePath = path.replace(url, resourceMap.get(url));
return resLoader.getResourceAsStream(classLoader, resourcePath);
}
}
}
return null;
}
}