/* * (C) Copyright 2009 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Florent Guillaume */ package org.nuxeo.runtime.datasource; import java.time.Instant; import java.util.HashMap; import java.util.Map; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.runtime.datasource.DatasourceExceptionSorter.Configuration; import org.nuxeo.runtime.jtajca.NuxeoContainer; import org.nuxeo.runtime.model.ComponentContext; import org.nuxeo.runtime.model.ComponentInstance; import org.nuxeo.runtime.model.DefaultComponent; /** * Nuxeo component allowing the JNDI registration of datasources by extension * point contributions. * <p> * For now only the internal Nuxeo JNDI server is supported. */ public class DataSourceComponent extends DefaultComponent { private final Log log = LogFactory.getLog(DataSourceComponent.class); static DataSourceComponent instance; public static final String DATASOURCES_XP = "datasources"; public static final String ENV_CTX_NAME = "java:comp/env/"; protected final Map<String, DataSourceDescriptor> datasources = new HashMap<>(); protected final Map<String, DataSourceLinkDescriptor> links = new HashMap<>(); protected final DatasourceExceptionSorter.Registry sorterRegistry = new DatasourceExceptionSorter.Registry(); protected final PooledDataSourceRegistry poolRegistry = new PooledDataSourceRegistry(); protected Context namingContext; @Override public void activate(ComponentContext context) { instance = this; } public void deactivate() { instance = null; } @Override public void registerContribution(Object contrib, String extensionPoint, ComponentInstance component) { if (contrib instanceof DataSourceDescriptor) { addDataSource((DataSourceDescriptor) contrib); } else if (contrib instanceof DataSourceLinkDescriptor) { addDataSourceLink((DataSourceLinkDescriptor) contrib); } else if (contrib instanceof DatasourceExceptionSorter.Configuration) { sorterRegistry.addContribution((Configuration) contrib); } else { log.error("Wrong datasource extension type " + contrib.getClass().getName()); } } @Override public void unregisterContribution(Object contrib, String extensionPoint, ComponentInstance component) { if (contrib instanceof DataSourceDescriptor) { removeDataSource((DataSourceDescriptor) contrib); } else if (contrib instanceof DataSourceLinkDescriptor) { removeDataSourceLink((DataSourceLinkDescriptor) contrib); } else if (contrib instanceof DatasourceExceptionSorter.Configuration) { sorterRegistry.removeContribution((Configuration) contrib); } } @Override public int getApplicationStartedOrder() { return -1000; } public boolean isStarted() { return namingContext != null; } @Override public void applicationStarted(ComponentContext context) { namingContext = NuxeoContainer.getRootContext(); // allocate datasource sub-contexts Name comp; try { comp = new CompositeName(DataSourceHelper.getDataSourceJNDIPrefix()); } catch (NamingException e) { throw new RuntimeException(e); } Context ctx = namingContext; for (int i = 0; i < comp.size(); i++) { try { ctx = (Context) ctx.lookup(comp.get(i)); } catch (NamingException e) { try { ctx = ctx.createSubcontext(comp.get(i)); } catch (NamingException e1) { throw new RuntimeException(e1); } } } // bind datasources for (DataSourceDescriptor datasourceDesc : datasources.values()) { bindDataSource(datasourceDesc); } // bind links for (DataSourceLinkDescriptor linkDesc : links.values()) { bindDataSourceLink(linkDesc); } } @Override public void applicationStopped(ComponentContext context, Instant deadline) { try { for (DataSourceLinkDescriptor desc : links.values()) { unbindDataSourceLink(desc); } for (DataSourceDescriptor desc : datasources.values()) { unbindDataSource(desc); } } finally { namingContext = null; } } protected void addDataSource(DataSourceDescriptor contrib) { datasources.put(contrib.getName(), contrib); bindDataSource(contrib); } protected void removeDataSource(DataSourceDescriptor contrib) { unbindDataSource(contrib); datasources.remove(contrib.getName()); } protected void bindDataSource(DataSourceDescriptor descr) { if (namingContext == null) { return; } log.info("Registering datasource: " + descr.getName()); try { descr.bindSelf(namingContext); } catch (NamingException e) { log.error("Cannot bind datasource '" + descr.getName() + "' in JNDI", e); } } protected void unbindDataSource(DataSourceDescriptor descr) { if (namingContext == null) { return; } log.info("Unregistering datasource: " + descr.name); try { descr.unbindSelf(namingContext); } catch (NamingException cause) { log.error("Cannot unbind datasource '" + descr.name + "' in JNDI", cause); } } protected void addDataSourceLink(DataSourceLinkDescriptor contrib) { links.put(contrib.name, contrib); bindDataSourceLink(contrib); } protected void removeDataSourceLink(DataSourceLinkDescriptor contrib) { unbindDataSourceLink(contrib); links.remove(contrib.name); } protected void bindDataSourceLink(DataSourceLinkDescriptor descr) { if (namingContext == null) { return; } log.info("Registering DataSourceLink: " + descr.name); try { descr.bindSelf(namingContext); } catch (NamingException e) { log.error("Cannot bind DataSourceLink '" + descr.name + "' in JNDI", e); } } protected void unbindDataSourceLink(DataSourceLinkDescriptor descr) { if (namingContext == null) { return; } log.info("Unregistering DataSourceLink: " + descr.name); try { descr.unbindSelf(namingContext); } catch (NamingException e) { log.error("Cannot unbind DataSourceLink '" + descr.name + "' in JNDI", e); } } @Override public <T> T getAdapter(Class<T> adapter) { if (adapter.isAssignableFrom(PooledDataSourceRegistry.class)) { return adapter.cast(poolRegistry); } return super.getAdapter(adapter); } }