/* * Copyright 2004-2009 the original author or authors. * * Licensed 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.compass.core.jndi; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.naming.Context; import javax.naming.InvalidNameException; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.event.EventContext; import javax.naming.event.NamespaceChangeListener; import javax.naming.event.NamingEvent; import javax.naming.event.NamingExceptionEvent; import javax.naming.event.NamingListener; import javax.naming.spi.ObjectFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.compass.core.Compass; import org.compass.core.config.CompassSettings; /** * Resolves <code>Compass</code> JNDI lookups and deserialization */ public class CompassObjectFactory implements ObjectFactory { // to stop the class from being unloaded private static final CompassObjectFactory INSTANCE; private static final Log log; static { log = LogFactory.getLog(CompassObjectFactory.class); INSTANCE = new CompassObjectFactory(); log.debug("Initializing class CompassObjectFactory. Using static instance [" + INSTANCE + "]"); } private static final Map INSTANCES = new ConcurrentHashMap(); private static final Map NAMED_INSTANCES = new ConcurrentHashMap(); private static final NamingListener LISTENER = new NamespaceChangeListener() { public void objectAdded(NamingEvent evt) { log.debug("Compass was successfully bound to name [" + evt.getNewBinding().getName() + "]"); } public void objectRemoved(NamingEvent evt) { String name = evt.getOldBinding().getName(); if (log.isInfoEnabled()) { log.info("Compass was unbound from name [" + name + "]"); } Object instance = NAMED_INSTANCES.remove(name); Iterator iter = INSTANCES.values().iterator(); while (iter.hasNext()) { if (iter.next() == instance) iter.remove(); } } public void objectRenamed(NamingEvent evt) { String name = evt.getOldBinding().getName(); if (log.isInfoEnabled()) { log.info("Compass was renamed from name [" + name + "]"); } NAMED_INSTANCES.put(evt.getNewBinding().getName(), NAMED_INSTANCES.remove(name)); } public void namingExceptionThrown(NamingExceptionEvent evt) { log.warn("Naming exception occurred accessing compass: " + evt.getException()); } }; public Object getObjectInstance(Object reference, Name name, Context ctx, Hashtable env) throws Exception { if (log.isDebugEnabled()) { log.debug("JNDI lookup for [" + name + "]"); } String uid = (String) ((Reference) reference).get(0).getContent(); return getInstance(uid); } public static void addInstance(String uid, String name, Compass instance, CompassSettings settings) { if (log.isDebugEnabled()) { log.debug("Registering compass [" + uid + "] with [" + ((name == null) ? "unnamed" : name) + ']'); } INSTANCES.put(uid, instance); if (name != null) NAMED_INSTANCES.put(name, instance); // must add to JNDI _after_ adding to HashMaps, because some JNDI // servers use serialization if (name == null) { log.info("Not binding compass to JNDI, no JNDI name configured"); } else { if (log.isInfoEnabled()) { log.info("Binding compass to JNDI under [" + name + "]"); } try { Context ctx = NamingHelper.getInitialContext(settings); NamingHelper.bind(ctx, name, instance); ((EventContext) ctx).addNamingListener(name, EventContext.OBJECT_SCOPE, LISTENER); } catch (InvalidNameException ine) { log.error("Invalid JNDI name [" + name + "]", ine); } catch (NamingException ne) { log.warn("Could not bind compass to JNDI", ne); } catch (ClassCastException cce) { log.warn("InitialContext did not implement EventContext"); } } } public static void removeInstance(String uid, String name, CompassSettings settings) { // TODO: theoretically non-threadsafe... if (name != null) { if (log.isInfoEnabled()) { log.info("Unbinding compass from JNDI name [" + name + "]"); } try { Context ctx = NamingHelper.getInitialContext(settings); ctx.unbind(name); } catch (InvalidNameException ine) { log.error("Invalid JNDI name [" + name + "]", ine); } catch (NamingException ne) { log.warn("Could not unbind compass from JNDI", ne); } NAMED_INSTANCES.remove(name); } INSTANCES.remove(uid); } public static Object getNamedInstance(String name) { if (log.isDebugEnabled()) { log.debug("lookup with name [" + name + "]"); } Object result = NAMED_INSTANCES.get(name); if (result == null) { log.warn("Not found [" + name + "]"); log.debug(NAMED_INSTANCES); } return result; } public static Object getInstance(String uid) { if (log.isDebugEnabled()) { log.debug("JNDI lookup for uid [" + uid + "]"); } Object result = INSTANCES.get(uid); if (result == null) { log.warn("Not found [" + uid + "]"); log.debug(INSTANCES); } return result; } }