/* * Copyright 2013 The Solmix Project * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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. * * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.gnu.org/licenses/ * or see the FSF site: http://www.fsf.org. */ package org.solmix.runtime.extension; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.solmix.runtime.Container; import org.solmix.runtime.bean.BeanConfigurer; import org.solmix.runtime.bean.ConfiguredBeanProvider; import org.solmix.runtime.resource.ObjectTypeResolver; import org.solmix.runtime.resource.ResourceInjector; import org.solmix.runtime.resource.ResourceManager; import org.solmix.runtime.resource.ResourceResolver; import org.solmix.runtime.resource.SinglePropertyResolver; /** * * @author solmix.f@gmail.com * @version $Id$ 2014年7月27日 */ public class ExtensionManagerImpl implements ExtensionManager, ConfiguredBeanProvider { private static final Logger LOG = LoggerFactory.getLogger(ExtensionManagerImpl.class); public static final String PROP_EXTENSION_MANAGER = "extensionManager"; private final ClassLoader loader; private final Container container; private final ResourceManager resourceManager; private final Map<Class<?>, Object> activated; private final Map<String, ExtensionInfo> all = new ConcurrentHashMap<String, ExtensionInfo>(); public ExtensionManagerImpl(String resources[], ClassLoader cl, Map<Class<?>, Object> cache, ResourceManager resourceManager, Container container) { this.loader = cl; this.resourceManager = resourceManager; this.activated = cache; this.container = container; ResourceResolver extensionManagerResolver = new SinglePropertyResolver( PROP_EXTENSION_MANAGER, this); resourceManager.addResourceResolver(extensionManagerResolver); resourceManager.addResourceResolver(new ObjectTypeResolver(this)); load(resources); for (Map.Entry<String, ExtensionInfo> ext : ExtensionRegistry.getRegisteredExtensions().entrySet()) { if (!all.containsKey(ext.getKey())) { all.put(ext.getKey(), ext.getValue()); } } } public ExtensionManagerImpl(String resource, ClassLoader cl, Map<Class<?>, Object> initialExtensions, ResourceManager resourceManager, Container container) { this(new String[] { resource }, cl, initialExtensions, resourceManager, container); } final void load(String resources[]) { if (resources == null) { return; } try { for (String resource : resources) { load(resource); } } catch (IOException ex) { throw new ExtensionException(ex); } } final void load(String resource) throws IOException { if (loader != getClass().getClassLoader()) { load(resource, getClass().getClassLoader()); } load(resource, loader); } final synchronized void load(String resource, ClassLoader l) throws IOException { Enumeration<URL> urls = l.getResources(resource); while (urls.hasMoreElements()) { final URL url = urls.nextElement(); if(LOG.isTraceEnabled()) LOG.trace("Load ExtensionInfo from :"+url.getPath()); InputStream is; String inf=url.getFile(); try { is = AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() { @Override public InputStream run() throws Exception { return url.openStream(); } }); } catch (PrivilegedActionException pae) { throw (IOException) pae.getException(); } try { List<ExtensionInfo> exts = new InternalExtensionParser(loader).getExtensions(is,inf); for (ExtensionInfo e : exts) { if (loader != l) { e.classloader = l; } if (!all.containsKey(e.getName())) { all.put(e.getName(), e); } } } finally { try { is.close(); } catch (IOException ex) { // ignore } } } } /** * {@inheritDoc} * * @see org.solmix.runtime.bean.ConfiguredBeanProvider#getBeanNamesOfType(java.lang.Class) */ @Override public List<String> getBeanNamesOfType(Class<?> type) { List<String> ret = new LinkedList<String>(); for (ExtensionInfo ex : all.values()) { synchronized (ex) { Class<?> cls = ex.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { ret.add(ex.getName()); } } } return ret; } /** * {@inheritDoc} * * @see org.solmix.runtime.bean.ConfiguredBeanProvider#getBeanOfType(java.lang.String, * java.lang.Class) */ @Override public <T> T getBeanOfType(String name, Class<T> type) { if (name == null) { return null; } ExtensionInfo info =all.get(name); if (info != null) { if (info.getLoadedObject() == null) { loadAndRegister(info); } return type.cast(info.getLoadedObject()); } return null; } /** * @param info */ final void loadAndRegister(ExtensionInfo info) { if(LOG.isTraceEnabled()){ LOG.trace("Loading and initial Extension: "+info.getName()); } synchronized (info) { Class<?> cls = null; /*if (null != info.getInterfaceName() && !"".equals(info.getInterfaceName())) { cls = info.loadInterface(loader); } else {*/ cls = info.getClassObject(loader); // } if (null != activated && null != cls && null != activated.get(cls)) { return; } Object obj = info.load(loader, container); if (obj == null) { return; } if (null != activated) { BeanConfigurer configurer = (BeanConfigurer) (activated.get(BeanConfigurer.class)); if (null != configurer) { configurer.configureBean(obj); } } ResourceInjector injector = new ResourceInjector(resourceManager); injector.inject(obj); injector.construct(obj); if (null != activated) { if (cls == null) { cls = obj.getClass(); } activated.put(cls, obj); } } } /** * {@inheritDoc} * * @see org.solmix.runtime.bean.ConfiguredBeanProvider#getBeansOfType(java.lang.Class) */ @Override public <T> Collection<? extends T> getBeansOfType(Class<T> type) { List<T> ret = new LinkedList<T>(); for(ExtensionInfo info : all.values()){ synchronized (info) { Class<?> cls = info.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { if (info.getLoadedObject() == null) { loadAndRegister(info); } ret.add(type.cast(info.getLoadedObject())); } } } return ret; } /** * {@inheritDoc} * * @see org.solmix.runtime.bean.ConfiguredBeanProvider#loadBeansOfType(java.lang.Class, * org.solmix.runtime.bean.ConfiguredBeanProvider.BeanLoaderListener) */ @Override public <T> boolean loadBeansOfType(Class<T> type, BeanLoaderListener<T> listener) { boolean loaded = false; for (ExtensionInfo ex : all.values()) { synchronized (ex) { Class<?> cls = ex.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls) && listener.loadBean(ex.getName(), cls.asSubclass(type))) { if (ex.getLoadedObject() == null) { loadAndRegister(ex); } if (listener.beanLoaded(ex.getName(), type.cast(ex.getLoadedObject()))) { return true; } loaded = true; } } } return loaded; } /** * {@inheritDoc} * * @see org.solmix.runtime.bean.ConfiguredBeanProvider#hasBeanOfName(java.lang.String) */ @Override public boolean hasBeanOfName(String name) { if(name==null) return false; for(ExtensionInfo info:all.values()){ if(name.equals(info.getName())){ return true; } } return false; } /** * {@inheritDoc} * * @see org.solmix.runtime.extension.ExtensionManager#activateAll() */ @Override public void activateAll() { for(ExtensionInfo info :all.values()){ if(info.getLoadedObject()==null){ loadAndRegister(info); } } } /** * {@inheritDoc} * * @see org.solmix.runtime.extension.ExtensionManager#activateAllByType(java.lang.Class) */ @Override public <T> void activateAllByType(Class<T> type) { for(ExtensionInfo info :all.values()){ if(info.getLoadedObject()==null){ synchronized (info) { Class<?> cls = info.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { loadAndRegister(info); } } } } } /** * {@inheritDoc} * * @see org.solmix.runtime.extension.ExtensionManager#getExtension(java.lang.String, * java.lang.Class) */ @Override public <T> T getExtension(String name, Class<T> type) { if (name == null) { return null; } ExtensionInfo info= all.get(name); if(info!=null){ synchronized (info) { Class<?> cls = info.getClassObject(loader); if (cls != null && type.isAssignableFrom(info.getClassObject(loader))) { if (info.getLoadedObject() == null) { loadAndRegister(info); } return type.cast(info.getLoadedObject()); } } } return null; } /** * {@inheritDoc} * * @see org.solmix.runtime.extension.ExtensionManager#initialize() */ @Override public void initialize() { for(ExtensionInfo info:all.values()){ if(!info.isDeferred()&&info.getLoadedObject()==null){ loadAndRegister(info); } } } Set<ExtensionInfo> getExtensionInfos(Class<?> type){ Set<ExtensionInfo> set= new HashSet<ExtensionInfo>(); for(ExtensionInfo info:all.values()){ if(type.isAssignableFrom(info.getClassObject(loader))){ set.add(info); } } return set; } public void removeBeansOfNames(List<String> names) { for (String s : names) { for(ExtensionInfo info:all.values()){ if(s.equals(info.getName())){ all.remove(info); } } } } /** * @param info */ void createExtension(ExtensionInfo info) { if(info.getLoadedObject()==null){ loadAndRegister(info); } } }