/* * 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.aries.jndi; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Enumeration; import java.util.Hashtable; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.Referenceable; import javax.naming.StringRefAddr; import javax.naming.directory.Attributes; import javax.naming.spi.DirObjectFactory; import javax.naming.spi.ObjectFactory; import javax.naming.spi.ObjectFactoryBuilder; import org.apache.aries.util.service.registry.ServicePair; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; public class ObjectFactoryHelper implements ObjectFactory { protected BundleContext defaultContext; protected BundleContext callerContext; private static final Logger logger = Logger.getLogger(ObjectFactoryHelper.class.getName()); public ObjectFactoryHelper(BundleContext defaultContext, BundleContext callerContext) { this.defaultContext = defaultContext; this.callerContext = callerContext; } public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { // Step 1 ensure we have a reference rather than a referenceable if (obj instanceof Referenceable) { obj = ((Referenceable) obj).getReference(); } if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "obj = " + obj); Object result = obj; // Step 2 - if we have a reference process it as a reference if (obj instanceof Reference) { Reference ref = (Reference) obj; String className = ref.getFactoryClassName(); if (className != null) { // Step 3 - use the class name in the reference to get the factory class name result = getObjectInstanceUsingClassName(obj, className, obj, name, nameCtx, environment); } else { // Step 4 - look, assuming url string ref addrs, for a url context object factory. result = getObjectInstanceUsingRefAddress(ref.getAll(), obj, name, nameCtx, environment); } } if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "Step 4: result = " + result); // Step 5 - if we still don't have a resolved object goto the object factory builds in the SR. if (result == null || result == obj) { result = getObjectInstanceUsingObjectFactoryBuilders(obj, name, nameCtx, environment); } if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "Step 5: result = " + result); // Step 6 - Attempt to use all the registered ObjectFactories in the SR. if (result == null || result == obj) { if ((obj instanceof Reference && ((Reference) obj).getFactoryClassName() == null) || !(obj instanceof Reference)) { result = getObjectInstanceUsingObjectFactories(obj, name, nameCtx, environment); } } if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "Step 6: result = " + result); // Extra, non-standard, bonus step 7. If javax.naming.OBJECT_FACTORIES is set as // a property in the environment, use its value to construct additional object factories. // Added under Aries-822, with reference // to https://www.osgi.org/bugzilla/show_bug.cgi?id=138 if (result == null || result == obj) { result = getObjectInstanceViaContextDotObjectFactories(obj, name, nameCtx, environment); } if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "Step 7: result = " + result); return (result == null) ? obj : result; } /* * Attempt to obtain an Object instance via the java.naming.factory.object property */ protected Object getObjectInstanceViaContextDotObjectFactories(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { return getObjectInstanceViaContextDotObjectFactories(obj, name, nameCtx, environment, null); } /* * Attempt to obtain an Object instance via the java.naming.factory.object property */ protected Object getObjectInstanceViaContextDotObjectFactories(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment, Attributes attrs) throws Exception { Object result = null; String factories = (String) environment.get(Context.OBJECT_FACTORIES); if (factories != null && factories.length() > 0) { String[] candidates = factories.split(":"); ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } }); for (String cand : candidates) { ObjectFactory factory = null; try { @SuppressWarnings("unchecked") Class<ObjectFactory> clz = (Class<ObjectFactory>) cl.loadClass(cand); factory = clz.newInstance(); } catch (Exception e) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "Exception instantiating factory: " + e); continue; } if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "cand=" + cand + " factory=" + factory); if (factory != null) { if(factory instanceof DirObjectFactory) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "its a DirObjectFactory"); final DirObjectFactory dirFactory = (DirObjectFactory) factory; result = dirFactory.getObjectInstance(obj, name, nameCtx, environment, attrs); } else { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "its an ObjectFactory"); result = factory.getObjectInstance(obj, name, nameCtx, environment); } } if (result != null && result != obj) break; } } if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "result = " + result); return (result == null) ? obj : result; } protected Object getObjectInstanceUsingObjectFactories(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { Object result = null; ServiceReference[] refs = Utils.getReferencesPrivileged(callerContext, ObjectFactory.class); if (refs != null) { Arrays.sort(refs, Utils.SERVICE_REFERENCE_COMPARATOR); for (ServiceReference ref : refs) { if (canCallObjectFactory(obj, ref)) { ObjectFactory factory = (ObjectFactory) Utils.getServicePrivileged(callerContext, ref); try { result = factory.getObjectInstance(obj, name, nameCtx, environment); } catch (NamingException ne) { // Ignore this since we are doing last ditch finding, another OF might work. } finally { callerContext.ungetService(ref); } // if the result comes back and is not null and not the reference // object then we should return the result, so break out of the // loop we are in. if (result != null && result != obj) { break; } } } } return (result == null) ? obj : result; } private boolean canCallObjectFactory(Object obj, ServiceReference ref) { if (obj instanceof Reference) return true; Object prop = ref.getProperty("aries.object.factory.requires.reference"); if (prop == null) return true; if (prop instanceof Boolean) return !!!(Boolean) prop; // if set to true we don't call. return true; } protected static String getUrlScheme(String name) { String scheme = name; int index = name.indexOf(':'); if (index != -1) { scheme = name.substring(0, index); } return scheme; } private Object getObjectInstanceUsingRefAddress(Enumeration<RefAddr> addresses, Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { Object result = null; while (addresses.hasMoreElements()) { RefAddr address = addresses.nextElement(); if (address instanceof StringRefAddr && "URL".equals(address.getType())) { String urlScheme = getUrlScheme( (String) address.getContent() ); ServicePair<ObjectFactory> factoryService = ContextHelper.getURLObjectFactory(callerContext, urlScheme, environment); if (factoryService != null) { ObjectFactory factory = factoryService.get(); String value = (String) address.getContent(); try { result = factory.getObjectInstance(value, name, nameCtx, environment); } finally { factoryService.unget(); } // if the result comes back and is not null and not the reference // object then we should return the result, so break out of the // loop we are in. if (result != null && result != obj) { break; } } } } return (result == null) ? obj : result; } static Tuple<ServiceReference,ObjectFactory> findObjectFactoryByClassName(final BundleContext ctx, final String className) { return AccessController.doPrivileged(new PrivilegedAction<Tuple<ServiceReference,ObjectFactory>>() { public Tuple<ServiceReference,ObjectFactory> run() { ServiceReference serviceReference = null; try { ServiceReference[] refs = ctx.getServiceReferences(className, null); if (refs != null && refs.length > 0) { serviceReference = refs[0]; } } catch (InvalidSyntaxException e) { // should not happen throw new RuntimeException(Utils.MESSAGES.getMessage("null.is.invalid.filter"), e); } ObjectFactory factory = null; if (serviceReference != null) { factory = (ObjectFactory) ctx.getService(serviceReference); } return new Tuple<ServiceReference, ObjectFactory>(serviceReference, factory); } }); } private Object getObjectInstanceUsingClassName(Object reference, String className, Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { Tuple<ServiceReference,ObjectFactory> tuple = findObjectFactoryByClassName(defaultContext, className); Object result = null; if (tuple.second != null) { try { result = tuple.second.getObjectInstance(reference, name, nameCtx, environment); } finally { defaultContext.ungetService(tuple.first); } } return (result == null) ? obj : result; } private Object getObjectInstanceUsingObjectFactoryBuilders(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { ObjectFactory factory = null; ServiceReference[] refs = Utils.getReferencesPrivileged(callerContext, ObjectFactoryBuilder.class); if (refs != null) { Arrays.sort(refs, Utils.SERVICE_REFERENCE_COMPARATOR); for (ServiceReference ref : refs) { ObjectFactoryBuilder builder = (ObjectFactoryBuilder) Utils.getServicePrivileged(callerContext, ref); try { factory = builder.createObjectFactory(obj, environment); } catch (NamingException e) { // TODO: log it } finally { callerContext.ungetService(ref); } if (factory != null) { break; } } } Object result = null; if (factory != null) { result = factory.getObjectInstance(obj, name, nameCtx, environment); } return (result == null) ? obj : result; } }