/*
* 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.startup;
import java.lang.reflect.Field;
import java.util.Arrays;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import javax.naming.spi.InitialContextFactoryBuilder;
import javax.naming.spi.NamingManager;
import javax.naming.spi.ObjectFactory;
import javax.naming.spi.ObjectFactoryBuilder;
import org.apache.aries.jndi.ContextManagerServiceFactory;
import org.apache.aries.jndi.JREInitialContextFactoryBuilder;
import org.apache.aries.jndi.OSGiInitialContextFactoryBuilder;
import org.apache.aries.jndi.OSGiObjectFactoryBuilder;
import org.apache.aries.jndi.ProviderAdminServiceFactory;
import org.apache.aries.jndi.Utils;
import org.apache.aries.jndi.AugmenterInvokerImpl;
import org.apache.aries.jndi.spi.EnvironmentAugmentation;
import org.apache.aries.jndi.spi.EnvironmentUnaugmentation;
import org.apache.aries.jndi.spi.AugmenterInvoker;
import org.apache.aries.jndi.tracker.ServiceTrackerCustomizers;
import org.apache.aries.jndi.urls.URLObjectFactoryFinder;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.service.jndi.JNDIContextManager;
import org.osgi.service.jndi.JNDIProviderAdmin;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The activator for this bundle makes sure the static classes in it are
* driven so they can do their magic stuff properly.
*/
public class Activator implements BundleActivator {
private static final Logger LOGGER = LoggerFactory.getLogger(Activator.class.getName());
private static String FORCE_BUILDER = "org.apache.aries.jndi.force.builder";
private OSGiInitialContextFactoryBuilder icfBuilder;
private static InitialContextFactoryBuilder originalICFBuilder;
private OSGiObjectFactoryBuilder ofBuilder;
private static ObjectFactoryBuilder originalOFBuilder;
private static volatile ServiceTracker icfBuilders;
private static volatile ServiceTracker urlObjectFactoryFinders;
private static volatile ServiceTracker initialContextFactories;
private static volatile ServiceTracker objectFactories;
private static volatile ServiceTracker environmentAugmentors;
private static volatile ServiceTracker environmentUnaugmentors;
public void start(BundleContext context) {
initialContextFactories = initServiceTracker(context, InitialContextFactory.class, ServiceTrackerCustomizers.ICF_CACHE);
objectFactories = initServiceTracker(context, ObjectFactory.class, ServiceTrackerCustomizers.URL_FACTORY_CACHE);
icfBuilders = initServiceTracker(context, InitialContextFactoryBuilder.class, ServiceTrackerCustomizers.LAZY);
urlObjectFactoryFinders = initServiceTracker(context, URLObjectFactoryFinder.class, ServiceTrackerCustomizers.LAZY);
environmentAugmentors = initServiceTracker(context, EnvironmentAugmentation.class, null);
environmentUnaugmentors = initServiceTracker(context, EnvironmentUnaugmentation.class, null);
try {
OSGiInitialContextFactoryBuilder builder = new OSGiInitialContextFactoryBuilder();
try {
NamingManager.setInitialContextFactoryBuilder(builder);
} catch (IllegalStateException e) {
// use reflection to force the builder to be used
if (forceBuilder(context)) {
setField(InitialContextFactoryBuilder.class, builder, true);
}
}
icfBuilder = builder;
} catch (NamingException e) {
LOGGER.debug(Utils.MESSAGES.getMessage("unable.to.set.static.ICFB"), e);
} catch (IllegalStateException e) {
// Log the problem at info level, but only log the exception at debug level, as in many cases this is not a real issue and people
// don't want to see stack traces at info level when everything it working as expected.
LOGGER.info(Utils.MESSAGES.getMessage("unable.to.set.static.ICFB.already.exists", getClassName(InitialContextFactoryBuilder.class)));
LOGGER.debug(Utils.MESSAGES.getMessage("unable.to.set.static.ICFB.already.exists", getClassName(InitialContextFactoryBuilder.class)), e);
}
try {
OSGiObjectFactoryBuilder builder = new OSGiObjectFactoryBuilder(context);
try {
NamingManager.setObjectFactoryBuilder(builder);
} catch (IllegalStateException e) {
// use reflection to force the builder to be used
if (forceBuilder(context)) {
setField(ObjectFactoryBuilder.class, builder, true);
}
}
ofBuilder = builder;
} catch (NamingException e) {
LOGGER.info(Utils.MESSAGES.getMessage("unable.to.set.static.OFB"), e);
} catch (IllegalStateException e) {
// Log the problem at info level, but only log the exception at debug level, as in many cases this is not a real issue and people
// don't want to see stack traces at info level when everything it working as expected.
LOGGER.info(Utils.MESSAGES.getMessage("unable.to.set.static.OFB.already.exists", getClassName(ObjectFactoryBuilder.class)));
LOGGER.debug(Utils.MESSAGES.getMessage("unable.to.set.static.OFB.already.exists", getClassName(ObjectFactoryBuilder.class)), e);
}
context.registerService(JNDIProviderAdmin.class.getName(),
new ProviderAdminServiceFactory(context),
null);
context.registerService(InitialContextFactoryBuilder.class.getName(),
new JREInitialContextFactoryBuilder(),
null);
context.registerService(JNDIContextManager.class.getName(),
new ContextManagerServiceFactory(),
null);
context.registerService(AugmenterInvoker.class.getName(),
AugmenterInvokerImpl.getInstance(),
null);
}
private boolean forceBuilder(BundleContext context) {
String forceBuilderProp = context.getProperty(FORCE_BUILDER);
if (forceBuilderProp != null) {
return true;
}
BundleRevision revision = context.getBundle().adapt(BundleRevision.class);
return !(revision.getDeclaredCapabilities(FORCE_BUILDER).isEmpty());
}
private String getClassName(Class<?> expectedType)
{
try {
for (Field field : NamingManager.class.getDeclaredFields()) {
if (expectedType.equals(field.getType())) {
field.setAccessible(true);
Object icf = field.get(null);
return icf.getClass().getName();
}
}
} catch (Throwable t) {
// Ignore
}
return "";
}
private ServiceTracker initServiceTracker(BundleContext context,
Class<?> type, ServiceTrackerCustomizer custom)
{
ServiceTracker t = new ServiceTracker(context, type.getName(), custom);
t.open();
return t;
}
public void stop(BundleContext context) {
/*
* Try to reset the InitialContextFactoryBuilder and ObjectFactoryBuilder
* on the NamingManager.
*/
if (icfBuilder != null) {
setField(InitialContextFactoryBuilder.class, originalICFBuilder, false);
}
if (ofBuilder != null) {
setField(ObjectFactoryBuilder.class, originalOFBuilder, false);
}
icfBuilders.close();
urlObjectFactoryFinders.close();
objectFactories.close();
initialContextFactories.close();
environmentAugmentors.close();
environmentUnaugmentors.close();
}
/*
* There are no public API to reset the InitialContextFactoryBuilder or
* ObjectFactoryBuilder on the NamingManager so try to use reflection.
*/
private static void setField(Class<?> expectedType, Object value, boolean saveOriginal) throws IllegalStateException {
try {
for (Field field : NamingManager.class.getDeclaredFields()) {
if (expectedType.equals(field.getType())) {
field.setAccessible(true);
if (saveOriginal) {
if (expectedType.equals(InitialContextFactoryBuilder.class)) {
originalICFBuilder = (InitialContextFactoryBuilder) field.get(null);
} else {
originalOFBuilder = (ObjectFactoryBuilder) field.get(null);
}
}
field.set(null, value);
}
}
} catch (Throwable t) {
// Ignore
LOGGER.debug("Error setting field.", t);
throw new IllegalStateException(t);
}
}
public static ServiceReference[] getInitialContextFactoryBuilderServices()
{
ServiceReference[] refs = icfBuilders.getServiceReferences();
if (refs != null) {
Arrays.sort(refs, Utils.SERVICE_REFERENCE_COMPARATOR);
}
return refs;
}
public static ServiceReference[] getInitialContextFactoryServices()
{
ServiceReference[] refs = initialContextFactories.getServiceReferences();
if (refs != null) {
Arrays.sort(refs, Utils.SERVICE_REFERENCE_COMPARATOR);
}
return refs;
}
public static ServiceReference[] getURLObectFactoryFinderServices()
{
ServiceReference[] refs = urlObjectFactoryFinders.getServiceReferences();
if (refs != null) {
Arrays.sort(refs, Utils.SERVICE_REFERENCE_COMPARATOR);
}
return refs;
}
public static Object[] getEnvironmentAugmentors()
{
return environmentAugmentors.getServices();
}
public static Object[] getEnvironmentUnaugmentors()
{
return environmentUnaugmentors.getServices();
}
}