/* * 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.sling.jcr.registration.impl; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Dictionary; import java.util.Enumeration; import java.util.Properties; import javax.jcr.Repository; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.ReferencePolicy; import org.apache.felix.scr.annotations.References; import org.apache.sling.jcr.registration.AbstractRegistrationSupport; import org.osgi.service.log.LogService; /** * The <code>JndiRegistrationSupport</code> extends the * {@link AbstractRegistrationSupport} class to register repositories with a * JNDI context whose provider URL and initial factory class name may be * configured. * <p> * Note: Currently, only these two properties are declared to be configurable, * in the future a mechanism should be devised to support declaration of more * properties. */ @Component( immediate = true, metatype = true, label = "%jndi.name", description = "%jndi.description", name = "org.apache.sling.jcr.jackrabbit.server.JndiRegistrationSupport", policy = ConfigurationPolicy.REQUIRE ) @org.apache.felix.scr.annotations.Properties({ @Property( name = "java.naming.factory.initial", value = "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory", label = "%jndi.factory.name", description = "%jndi.factory.description"), @Property( name = "java.naming.provider.url", value = "http://sling.apache.org", label = "%jndi.providerurl.name", description = "%jndi.providerurl.description"), @Property(name = "service.vendor", value = "The Apache Software Foundation", propertyPrivate = true), @Property(name = "service.description", value = "JNDI Repository Registration", propertyPrivate = true) }) @References({ @Reference( name = "Repository", policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, referenceInterface = Repository.class), @Reference(referenceInterface=LogService.class, bind="bindLog", unbind="unbindLog", cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC) }) public class JndiRegistrationSupport extends AbstractRegistrationSupport { private Context jndiContext; // ---------- SCR intergration --------------------------------------------- @Override protected boolean doActivate() { @SuppressWarnings("unchecked") Dictionary<String, Object> props = this.getComponentContext().getProperties(); Properties env = new Properties(); for (Enumeration<String> pe = props.keys(); pe.hasMoreElements();) { String key = pe.nextElement(); if (key.startsWith("java.naming.")) { env.setProperty(key, (String) props.get(key)); } } try { // create the JNDI context for registration this.jndiContext = this.createInitialContext(env); this.log(LogService.LOG_INFO, "Using JNDI context " + this.jndiContext.getEnvironment() + " to register repositories", null); return true; } catch (NamingException ne) { this.log( LogService.LOG_ERROR, "Problem setting up JNDI initial context, repositories will not be registered. Reason: " + ne.getMessage(), null); } // fallback to false return false; } @Override protected void doDeactivate() { if (this.jndiContext != null) { try { this.jndiContext.close(); } catch (NamingException ne) { this.log(LogService.LOG_INFO, "Problem closing JNDI context", ne); } this.jndiContext = null; } } private Context createInitialContext(final Properties env) throws NamingException { try { return AccessController.doPrivileged(new PrivilegedExceptionAction<Context>() { public Context run() throws NamingException { Thread currentThread = Thread.currentThread(); ClassLoader old = currentThread.getContextClassLoader(); currentThread.setContextClassLoader(JndiRegistrationSupport.this.getClass().getClassLoader()); try { return new InitialContext(env); } finally { currentThread.setContextClassLoader(old); } } }); } catch (PrivilegedActionException pae) { // we now that this method only throws a NamingException throw (NamingException) pae.getCause(); } } @Override protected Object bindRepository(String name, Repository repository) { if (this.jndiContext != null) { try { this.jndiContext.bind(name, repository); this.log(LogService.LOG_INFO, "Repository bound to JNDI as " + name, null); return repository; } catch (NamingException ne) { this.log(LogService.LOG_ERROR, "Failed to register repository " + name, ne); } } // fall back to unregistered in case of failures or no context return null; } @Override protected void unbindRepository(String name, Object data) { if (this.jndiContext != null) { try { this.jndiContext.unbind(name); this.log(LogService.LOG_INFO, "Repository " + name + " unbound from JNDI", null); } catch (NamingException ne) { this.log(LogService.LOG_ERROR, "Problem unregistering repository " + name, ne); } } } }