/* * JBoss, Home of Professional Open Source. * Copyright 2010, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * 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 should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.naming.context; import java.security.AccessController; import java.util.Hashtable; import java.util.StringTokenizer; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.naming.directory.Attributes; import javax.naming.spi.DirObjectFactory; import javax.naming.spi.ObjectFactory; import org.jboss.as.naming.ServiceAwareObjectFactory; import org.jboss.as.naming.logging.NamingLogger; import org.jboss.as.server.CurrentServiceContainer; import org.jboss.modules.Module; import org.jboss.msc.service.ServiceContainer; import org.wildfly.security.manager.WildFlySecurityManager; /** * ObjectFactoryBuilder implementation used to support custom object factories being loaded from modules. This class * also provides the default object factory implementation. * * @author John Bailey */ public class ObjectFactoryBuilder implements javax.naming.spi.ObjectFactoryBuilder, DirObjectFactory { public static final ObjectFactoryBuilder INSTANCE = new ObjectFactoryBuilder(); private ObjectFactoryBuilder() { } /** * Create an object factory. If the object parameter is a reference it will attempt to create an {@link javax.naming.spi.ObjectFactory} * from the reference. If the parameter is not a reference, or the reference does not create an {@link javax.naming.spi.ObjectFactory} * it will return {@code this} as the {@link javax.naming.spi.ObjectFactory} to use. * * @param obj The object bound in the naming context * @param environment The environment information * @return The object factory the object resolves to * @throws NamingException If any problems occur */ public ObjectFactory createObjectFactory(final Object obj, Hashtable<?, ?> environment) throws NamingException { try { if (obj instanceof Reference) { return factoryFromReference((Reference) obj, environment); } } catch (Throwable ignored) { } return this; } /** * Create an object instance. * * @param ref Object containing reference information * @param name The name relative to nameCtx * @param nameCtx The naming context * @param environment The environment information * @return The object * @throws Exception If any error occur */ public Object getObjectInstance(final Object ref, final Name name, final Context nameCtx, final Hashtable<?, ?> environment) throws Exception { final ClassLoader classLoader = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged(); if (classLoader == null) { return ref; } final String factoriesProp = (String) environment.get(Context.OBJECT_FACTORIES); if (factoriesProp != null) { final String[] classes = factoriesProp.split(":"); for (String className : classes) { try { final Class<?> factoryClass = classLoader.loadClass(className); final ObjectFactory objectFactory = ObjectFactory.class.cast(factoryClass.newInstance()); final Object result = objectFactory.getObjectInstance(ref, name, nameCtx, environment); if (result != null) { return result; } } catch (Throwable ignored) { } } } return ref; } /** * Create an object instance. * * @param ref Object containing reference information * @param name The name relative to nameCtx * @param nameCtx The naming context * @param environment The environment information * @param attributes The directory attributes * @return The object * @throws Exception If any error occur */ public Object getObjectInstance(final Object ref, final Name name, final Context nameCtx, final Hashtable<?, ?> environment, final Attributes attributes) throws Exception { final ClassLoader classLoader = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged(); if (classLoader == null) { return ref; } final String factoriesProp = (String) environment.get(Context.OBJECT_FACTORIES); if (factoriesProp != null) { final String[] classes = factoriesProp.split(":"); for (String className : classes) { try { final Class<?> factoryClass = classLoader.loadClass(className); final ObjectFactory objectFactory = ObjectFactory.class.cast(factoryClass.newInstance()); final Object result; if (objectFactory instanceof DirObjectFactory) { result = DirObjectFactory.class.cast(objectFactory).getObjectInstance(ref, name, nameCtx, environment, attributes); } else { result = objectFactory.getObjectInstance(ref, name, nameCtx, environment); } if (result != null) { return result; } } catch (Throwable ignored) { } } } return ref; } private ObjectFactory factoryFromReference(final Reference reference, final Hashtable<?, ?> environment) throws Exception { if (reference.getFactoryClassName() == null) { return lookForURLs(reference, environment); } if (reference instanceof ModularReference) { return factoryFromModularReference(ModularReference.class.cast(reference), environment); } return factoryFromReference(reference, WildFlySecurityManager.getCurrentContextClassLoaderPrivileged(), environment); } private ObjectFactory factoryFromModularReference(ModularReference modularReference, final Hashtable<?, ?> environment) throws Exception { final Module module = Module.getCallerModuleLoader().loadModule(modularReference.getModuleIdentifier()); final ClassLoader classLoader = module.getClassLoader(); return factoryFromReference(modularReference, classLoader, environment); } private ObjectFactory factoryFromReference(final Reference reference, final ClassLoader classLoader, final Hashtable<?, ?> environment) throws Exception { try { final Class<?> factoryClass = classLoader.loadClass(reference.getFactoryClassName()); ObjectFactory factory = ObjectFactory.class.cast(factoryClass.newInstance()); if (factory instanceof ServiceAwareObjectFactory) { ((ServiceAwareObjectFactory) factory).injectServiceRegistry(currentServiceContainer()); } return factory; } catch (Throwable t) { throw NamingLogger.ROOT_LOGGER.objectFactoryCreationFailure(t); } } static ObjectFactory lookForURLs(Reference ref, Hashtable environment) throws NamingException { for (int i = 0; i < ref.size(); i++) { RefAddr addr = ref.get(i); if (addr instanceof StringRefAddr && addr.getType().equalsIgnoreCase("URL")) { String url = (String) addr.getContent(); ObjectFactory answer = processURL(url, environment); if (answer != null) { return answer; } } } return null; } private static ObjectFactory processURL(Object refInfo, Hashtable environment) throws NamingException { if (refInfo instanceof String) { String url = (String) refInfo; String scheme = getURLScheme(url); if (scheme != null) { ObjectFactory answer = getURLObjectFactory(scheme, url, environment); if (answer != null) { return answer; } } } if (refInfo instanceof String[]) { String[] urls = (String[]) refInfo; for (int i = 0; i < urls.length; i++) { String scheme = getURLScheme(urls[i]); if (scheme != null) { ObjectFactory answer = getURLObjectFactory(scheme, urls[i], environment); if (answer != null) { return answer; } } } } return null; } private static ObjectFactory getURLObjectFactory(String scheme, String url, Hashtable environment) throws NamingException { String facProp = (String) environment.get(Context.URL_PKG_PREFIXES); if (facProp != null) { facProp += ":" + "com.sun.jndi.url"; } else { facProp = "com.sun.jndi.url"; } ClassLoader loader = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged(); String suffix = "." + scheme + "." + scheme + "URLContextFactory"; // Not cached; find first factory and cache StringTokenizer parser = new StringTokenizer(facProp, ":"); String className; ObjectFactory factory = null; while (parser.hasMoreTokens()) { className = parser.nextToken() + suffix; try { Class<?> clazz; if (loader == null) { clazz = Class.forName(className); } else { clazz = Class.forName(className, true, loader); } return new ReferenceUrlContextFactoryWrapper((ObjectFactory) clazz.newInstance(), url); } catch (InstantiationException | IllegalAccessException e) { NamingException ne = new NamingException(className); ne.setRootCause(e); throw ne; } catch (Exception e) { } } return factory; } private static String getURLScheme(String str) { int colon = str.indexOf(':'); int slash = str.indexOf('/'); if (colon > 0 && (slash == -1 || colon + 1 == slash)) return str.substring(0, colon); return null; } private static ServiceContainer currentServiceContainer() { if(System.getSecurityManager() == null) { return CurrentServiceContainer.getServiceContainer(); } return AccessController.doPrivileged(CurrentServiceContainer.GET_ACTION); } private static final class ReferenceUrlContextFactoryWrapper implements ObjectFactory { private final ObjectFactory factory; private final String url; private ReferenceUrlContextFactoryWrapper(final ObjectFactory factory, final String url) { this.factory = factory; this.url = url; } @Override public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?, ?> environment) throws Exception { return factory.getObjectInstance(url, name, nameCtx, environment); } } }