/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.bus.extension; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; 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.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import org.apache.cxf.Bus; import org.apache.cxf.common.injection.ResourceInjector; import org.apache.cxf.configuration.ConfiguredBeanLocator; import org.apache.cxf.configuration.Configurer; import org.apache.cxf.resource.ObjectTypeResolver; import org.apache.cxf.resource.ResourceManager; import org.apache.cxf.resource.ResourceResolver; import org.apache.cxf.resource.SinglePropertyResolver; public class ExtensionManagerImpl implements ExtensionManager, ConfiguredBeanLocator { public static final String EXTENSIONMANAGER_PROPERTY_NAME = "extensionManager"; public static final String ACTIVATION_NAMESPACES_PROPERTY_NAME = "activationNamespaces"; public static final String ACTIVATION_NAMESPACES_SETTER_METHOD_NAME = "setActivationNamespaces"; public static final String BUS_EXTENSION_RESOURCE = "META-INF/cxf/bus-extensions.txt"; private final ClassLoader loader; private ResourceManager resourceManager; private Map<String, Extension> all = new ConcurrentHashMap<String, Extension>(); private List<Extension> ordered = new CopyOnWriteArrayList<Extension>(); private final Map<Class<?>, Object> activated; private final Bus bus; public ExtensionManagerImpl(ClassLoader cl, Map<Class<?>, Object> initialExtensions, ResourceManager rm, Bus b) { this(new String[] {BUS_EXTENSION_RESOURCE}, cl, initialExtensions, rm, b); } public ExtensionManagerImpl(String resource, ClassLoader cl, Map<Class<?>, Object> initialExtensions, ResourceManager rm, Bus b) { this(new String[] {resource}, cl, initialExtensions, rm, b); } public ExtensionManagerImpl(String resources[], ClassLoader cl, Map<Class<?>, Object> initialExtensions, ResourceManager rm, Bus b) { loader = cl; bus = b; activated = initialExtensions; resourceManager = rm; ResourceResolver extensionManagerResolver = new SinglePropertyResolver(EXTENSIONMANAGER_PROPERTY_NAME, this); resourceManager.addResourceResolver(extensionManagerResolver); resourceManager.addResourceResolver(new ObjectTypeResolver(this)); load(resources); for (Map.Entry<String, Extension> ext : ExtensionRegistry.getRegisteredExtensions().entrySet()) { if (!all.containsKey(ext.getKey())) { all.put(ext.getKey(), ext.getValue()); ordered.add(ext.getValue()); } } } final void load(String resources[]) { if (resources == null) { return; } try { for (String resource : resources) { load(resource); } } catch (IOException ex) { throw new ExtensionException(ex); } } public void add(Extension ex) { all.put(ex.getName(), ex); ordered.add(ex); } public void initialize() { for (Extension e : ordered) { if (!e.isDeferred() && e.getLoadedObject() == null) { loadAndRegister(e); } } } public void removeBeansOfNames(List<String> names) { for (String s : names) { Extension ex = all.remove(s); if (ex != null) { ordered.remove(ex); } } } public void activateAll() { for (Extension e : ordered) { if (e.getLoadedObject() == null) { loadAndRegister(e); } } } public <T> void activateAllByType(Class<T> type) { for (Extension e : ordered) { if (e.getLoadedObject() == null) { Class<?> cls = e.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { synchronized (e) { loadAndRegister(e); } } } } } public boolean hasBeanOfName(String name) { return all.containsKey(name); } 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(); InputStream is; try { is = AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() { public InputStream run() throws Exception { return url.openStream(); } }); } catch (PrivilegedActionException pae) { throw (IOException)pae.getException(); } try { List<Extension> exts = new TextExtensionFragmentParser(loader).getExtensions(is); for (Extension e : exts) { if (loader != l) { e.classloader = l; } if (!all.containsKey(e.getName())) { all.put(e.getName(), e); ordered.add(e); } } } finally { try { is.close(); } catch (IOException ex) { //ignore } } } } final void loadAndRegister(Extension e) { Class<?> cls = null; if (null != e.getInterfaceName() && !"".equals(e.getInterfaceName())) { cls = e.loadInterface(loader); } else { cls = e.getClassObject(loader); } if (null != activated && null != cls && null != activated.get(cls)) { return; } synchronized (e) { Object obj = e.load(loader, bus); if (obj == null) { return; } if (null != activated) { Configurer configurer = (Configurer)(activated.get(Configurer.class)); if (null != configurer) { configurer.configureBean(obj); } } // let the object know for which namespaces it has been activated ResourceResolver namespacesResolver = null; if (null != e.getNamespaces()) { namespacesResolver = new SinglePropertyResolver(ACTIVATION_NAMESPACES_PROPERTY_NAME, e.getNamespaces()); resourceManager.addResourceResolver(namespacesResolver); } // Since we need to support spring2.5 by removing @Resource("activationNamespaces") // Now we call the setActivationNamespaces method directly here if (e.getNamespaces() != null && !e.getNamespaces().isEmpty()) { invokeSetterActivationNSMethod(obj, e.getNamespaces()); } ResourceInjector injector = new ResourceInjector(resourceManager); try { injector.inject(obj); injector.construct(obj); } finally { if (null != namespacesResolver) { resourceManager.removeResourceResolver(namespacesResolver); } } if (null != activated) { if (cls == null) { cls = obj.getClass(); } activated.put(cls, obj); } } } public <T> T getExtension(String name, Class<T> type) { if (name == null) { return null; } Extension e = all.get(name); if (e != null) { Class<?> cls = e.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { synchronized (e) { if (e.getLoadedObject() == null) { loadAndRegister(e); } return type.cast(e.getLoadedObject()); } } } return null; } private void invokeSetterActivationNSMethod(Object target, Object value) { Class<?> clazz = target.getClass(); String methodName = ACTIVATION_NAMESPACES_SETTER_METHOD_NAME; while (clazz != Object.class) { Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; Class<?> params[] = method.getParameterTypes(); if (method.getName().equals(methodName) && params.length == 1) { Class<?> paramType = params[0]; if (paramType.isInstance(value)) { try { method.invoke(target, new Object[] {value}); } catch (Exception e) { // do nothing here } return; } } } clazz = clazz.getSuperclass(); } } public List<String> getBeanNamesOfType(Class<?> type) { List<String> ret = new LinkedList<String>(); for (Extension ex : ordered) { Class<?> cls = ex.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { synchronized (ex) { ret.add(ex.getName()); } } } return ret; } public <T> T getBeanOfType(String name, Class<T> type) { if (name == null) { return null; } Extension ex = all.get(name); if (ex != null) { if (ex.getLoadedObject() == null) { loadAndRegister(ex); } return type.cast(ex.getLoadedObject()); } return null; } public <T> Collection<? extends T> getBeansOfType(Class<T> type) { List<T> ret = new LinkedList<T>(); Extension ext = all.get(type.getName()); if (ext != null) { Class<?> cls = ext.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { synchronized (ext) { if (ext.getLoadedObject() == null) { loadAndRegister(ext); } if (ext.getLoadedObject() != null) { ret.add(type.cast(ext.getLoadedObject())); } } } } for (Extension ex : ordered) { if (ex != ext) { Class<?> cls = ex.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { synchronized (ex) { if (ex.getLoadedObject() == null) { loadAndRegister(ex); } if (ex.getLoadedObject() != null) { ret.add(type.cast(ex.getLoadedObject())); } } } } } return ret; } public <T> boolean loadBeansOfType(Class<T> type, BeanLoaderListener<T> listener) { boolean loaded = false; for (Extension ex : ordered) { Class<?> cls = ex.getClassObject(loader); if (cls != null && type.isAssignableFrom(cls)) { synchronized (ex) { if (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; } public boolean hasConfiguredPropertyValue(String beanName, String propertyName, String value) { if (beanName == null) { return false; } Extension ex = all.get(beanName); return ex != null && ex.getNamespaces() != null && ex.getNamespaces().contains(value); } public void destroyBeans() { for (Extension ex : ordered) { if (ex.getLoadedObject() != null) { ResourceInjector injector = new ResourceInjector(resourceManager); injector.destroy(ex.getLoadedObject()); } } } }