001/* 002 * (C) Copyright 2009 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019 020package org.nuxeo.runtime.datasource; 021 022import java.util.HashMap; 023import java.util.Map; 024 025import javax.naming.CompositeName; 026import javax.naming.Context; 027import javax.naming.Name; 028import javax.naming.NamingException; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.runtime.datasource.DatasourceExceptionSorter.Configuration; 033import org.nuxeo.runtime.jtajca.NuxeoContainer; 034import org.nuxeo.runtime.model.ComponentContext; 035import org.nuxeo.runtime.model.ComponentInstance; 036import org.nuxeo.runtime.model.DefaultComponent; 037 038/** 039 * Nuxeo component allowing the JNDI registration of datasources by extension 040 * point contributions. 041 * <p> 042 * For now only the internal Nuxeo JNDI server is supported. 043 */ 044public class DataSourceComponent extends DefaultComponent { 045 046 private final Log log = LogFactory.getLog(DataSourceComponent.class); 047 048 static DataSourceComponent instance; 049 050 public static final String DATASOURCES_XP = "datasources"; 051 052 public static final String ENV_CTX_NAME = "java:comp/env/"; 053 054 protected final Map<String, DataSourceDescriptor> datasources = new HashMap<>(); 055 056 protected final Map<String, DataSourceLinkDescriptor> links = new HashMap<>(); 057 058 protected final DatasourceExceptionSorter.Registry sorterRegistry = new DatasourceExceptionSorter.Registry(); 059 060 protected final PooledDataSourceRegistry poolRegistry = new PooledDataSourceRegistry(); 061 062 protected Context namingContext; 063 064 @Override 065 public void activate(ComponentContext context) { 066 instance = this; 067 } 068 069 public void deactivate() { 070 instance = null; 071 } 072 073 @Override 074 public void registerContribution(Object contrib, String extensionPoint, ComponentInstance component) { 075 if (contrib instanceof DataSourceDescriptor) { 076 addDataSource((DataSourceDescriptor) contrib); 077 } else if (contrib instanceof DataSourceLinkDescriptor) { 078 addDataSourceLink((DataSourceLinkDescriptor) contrib); 079 } else if (contrib instanceof DatasourceExceptionSorter.Configuration) { 080 sorterRegistry.addContribution((Configuration) contrib); 081 } else { 082 log.error("Wrong datasource extension type " + contrib.getClass().getName()); 083 } 084 } 085 086 @Override 087 public void unregisterContribution(Object contrib, String extensionPoint, ComponentInstance component) { 088 if (contrib instanceof DataSourceDescriptor) { 089 removeDataSource((DataSourceDescriptor) contrib); 090 } else if (contrib instanceof DataSourceLinkDescriptor) { 091 removeDataSourceLink((DataSourceLinkDescriptor) contrib); 092 } else if (contrib instanceof DatasourceExceptionSorter.Configuration) { 093 sorterRegistry.removeContribution((Configuration) contrib); 094 } 095 } 096 097 @Override 098 public int getApplicationStartedOrder() { 099 return -1000; 100 } 101 102 public boolean isStarted() { 103 return namingContext != null; 104 } 105 106 @Override 107 public void applicationStarted(ComponentContext context) { 108 if (namingContext != null) { 109 return; 110 } 111 namingContext = NuxeoContainer.getRootContext(); 112 // allocate datasource sub-contexts 113 Name comp; 114 try { 115 comp = new CompositeName(DataSourceHelper.getDataSourceJNDIPrefix()); 116 } catch (NamingException e) { 117 throw new RuntimeException(e); 118 } 119 Context ctx = namingContext; 120 for (int i = 0; i < comp.size(); i++) { 121 try { 122 ctx = (Context) ctx.lookup(comp.get(i)); 123 } catch (NamingException e) { 124 try { 125 ctx = ctx.createSubcontext(comp.get(i)); 126 } catch (NamingException e1) { 127 throw new RuntimeException(e1); 128 } 129 } 130 } 131 // bind datasources 132 for (DataSourceDescriptor datasourceDesc : datasources.values()) { 133 bindDataSource(datasourceDesc); 134 } 135 // bind links 136 for (DataSourceLinkDescriptor linkDesc : links.values()) { 137 bindDataSourceLink(linkDesc); 138 } 139 } 140 141 @Override 142 public void deactivate(ComponentContext context) { 143 super.deactivate(context); 144 for (DataSourceLinkDescriptor desc : links.values()) { 145 unbindDataSourceLink(desc); 146 } 147 links.clear(); 148 for (DataSourceDescriptor desc : datasources.values()) { 149 unbindDataSource(desc); 150 } 151 datasources.clear(); 152 namingContext = null; 153 } 154 155 protected void addDataSource(DataSourceDescriptor contrib) { 156 datasources.put(contrib.getName(), contrib); 157 bindDataSource(contrib); 158 } 159 160 protected void removeDataSource(DataSourceDescriptor contrib) { 161 unbindDataSource(contrib); 162 datasources.remove(contrib.getName()); 163 } 164 165 protected void bindDataSource(DataSourceDescriptor descr) { 166 if (namingContext == null) { 167 return; 168 } 169 log.info("Registering datasource: " + descr.getName()); 170 try { 171 descr.bindSelf(namingContext); 172 } catch (NamingException e) { 173 log.error("Cannot bind datasource '" + descr.getName() + "' in JNDI", e); 174 } 175 } 176 177 protected void unbindDataSource(DataSourceDescriptor descr) { 178 if (namingContext == null) { 179 return; 180 } 181 log.info("Unregistering datasource: " + descr.name); 182 try { 183 descr.unbindSelf(namingContext); 184 } catch (NamingException cause) { 185 log.error("Cannot unbind datasource '" + descr.name + "' in JNDI", cause); 186 } 187 } 188 189 protected void addDataSourceLink(DataSourceLinkDescriptor contrib) { 190 links.put(contrib.name, contrib); 191 bindDataSourceLink(contrib); 192 } 193 194 protected void removeDataSourceLink(DataSourceLinkDescriptor contrib) { 195 unbindDataSourceLink(contrib); 196 links.remove(contrib.name); 197 } 198 199 protected void bindDataSourceLink(DataSourceLinkDescriptor descr) { 200 if (namingContext == null) { 201 return; 202 } 203 log.info("Registering DataSourceLink: " + descr.name); 204 try { 205 descr.bindSelf(namingContext); 206 } catch (NamingException e) { 207 log.error("Cannot bind DataSourceLink '" + descr.name + "' in JNDI", e); 208 } 209 } 210 211 protected void unbindDataSourceLink(DataSourceLinkDescriptor descr) { 212 if (namingContext == null) { 213 return; 214 } 215 log.info("Unregistering DataSourceLink: " + descr.name); 216 try { 217 descr.unbindSelf(namingContext); 218 } catch (NamingException e) { 219 log.error("Cannot unbind DataSourceLink '" + descr.name + "' in JNDI", e); 220 } 221 } 222 223 @Override 224 public <T> T getAdapter(Class<T> adapter) { 225 if (adapter.isAssignableFrom(PooledDataSourceRegistry.class)) { 226 return adapter.cast(poolRegistry); 227 } 228 return super.getAdapter(adapter); 229 } 230 231}