001/* 002 * (C) Copyright 2009-2017 Nuxeo (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 */ 019package org.nuxeo.runtime.datasource; 020 021import java.util.HashMap; 022import java.util.Map; 023 024import javax.naming.CompositeName; 025import javax.naming.Context; 026import javax.naming.Name; 027import javax.naming.NamingException; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.runtime.datasource.DatasourceExceptionSorter.Configuration; 032import org.nuxeo.runtime.jtajca.NuxeoContainer; 033import org.nuxeo.runtime.model.ComponentContext; 034import org.nuxeo.runtime.model.ComponentInstance; 035import org.nuxeo.runtime.model.DefaultComponent; 036 037/** 038 * Nuxeo component allowing the JNDI registration of datasources by extension 039 * point contributions. 040 * <p> 041 * For now only the internal Nuxeo JNDI server is supported. 042 */ 043public class DataSourceComponent extends DefaultComponent { 044 045 private final Log log = LogFactory.getLog(DataSourceComponent.class); 046 047 static DataSourceComponent instance; 048 049 public static final String DATASOURCES_XP = "datasources"; 050 051 public static final String ENV_CTX_NAME = "java:comp/env/"; 052 053 protected Map<String, DataSourceDescriptor> datasources = new HashMap<>(); 054 055 protected Map<String, DataSourceLinkDescriptor> links = new HashMap<>(); 056 057 protected final DatasourceExceptionSorter.Registry sorterRegistry = new DatasourceExceptionSorter.Registry(); 058 059 protected final PooledDataSourceRegistry poolRegistry = new PooledDataSourceRegistry(); 060 061 protected Context namingContext; 062 063 @Override 064 public void activate(ComponentContext context) { 065 instance = this; 066 datasources = new HashMap<>(); 067 links = new HashMap<>(); 068 } 069 070 @Override 071 public void deactivate(ComponentContext context) { 072 super.deactivate(context); 073 links = null; 074 datasources = null; 075 instance = null; 076 //TODO should poolRegistry and sorterRegistry be removed? 077 } 078 079 @Override 080 public void registerContribution(Object contrib, String extensionPoint, ComponentInstance component) { 081 if (contrib instanceof DataSourceDescriptor) { 082 addDataSource((DataSourceDescriptor) contrib); 083 } else if (contrib instanceof DataSourceLinkDescriptor) { 084 addDataSourceLink((DataSourceLinkDescriptor) contrib); 085 } else if (contrib instanceof DatasourceExceptionSorter.Configuration) { 086 sorterRegistry.addContribution((Configuration) contrib); 087 } else { 088 log.error("Wrong datasource extension type " + contrib.getClass().getName()); 089 } 090 } 091 092 @Override 093 public void unregisterContribution(Object contrib, String extensionPoint, ComponentInstance component) { 094 if (contrib instanceof DataSourceDescriptor) { 095 removeDataSource((DataSourceDescriptor) contrib); 096 } else if (contrib instanceof DataSourceLinkDescriptor) { 097 removeDataSourceLink((DataSourceLinkDescriptor) contrib); 098 } else if (contrib instanceof DatasourceExceptionSorter.Configuration) { 099 sorterRegistry.removeContribution((Configuration) contrib); 100 } 101 } 102 103 @Override 104 public int getApplicationStartedOrder() { 105 return -1000; 106 } 107 108 public boolean isStarted() { 109 return namingContext != null; 110 } 111 112 @Override 113 public void start(ComponentContext context) { 114 if (namingContext != null) { 115 return; 116 } 117 namingContext = NuxeoContainer.getRootContext(); 118 // allocate datasource sub-contexts 119 Name comp; 120 try { 121 comp = new CompositeName(DataSourceHelper.getDataSourceJNDIPrefix()); 122 } catch (NamingException e) { 123 throw new RuntimeException(e); 124 } 125 Context ctx = namingContext; 126 for (int i = 0; i < comp.size(); i++) { 127 try { 128 ctx = (Context) ctx.lookup(comp.get(i)); 129 } catch (NamingException e) { 130 try { 131 ctx = ctx.createSubcontext(comp.get(i)); 132 } catch (NamingException e1) { 133 throw new RuntimeException(e1); 134 } 135 } 136 } 137 // bind datasources 138 for (DataSourceDescriptor datasourceDesc : datasources.values()) { 139 bindDataSource(datasourceDesc); 140 } 141 // bind links 142 for (DataSourceLinkDescriptor linkDesc : links.values()) { 143 bindDataSourceLink(linkDesc); 144 } 145 } 146 147 @Override 148 public void stop(ComponentContext context) { 149 try { 150 for (DataSourceLinkDescriptor desc : links.values()) { 151 unbindDataSourceLink(desc); 152 } 153 for (DataSourceDescriptor desc : datasources.values()) { 154 unbindDataSource(desc); 155 } 156 namingContext = null; 157 } finally { 158 namingContext = null; 159 } 160 } 161 162 protected void addDataSource(DataSourceDescriptor contrib) { 163 datasources.put(contrib.getName(), contrib); 164 bindDataSource(contrib); 165 } 166 167 protected void removeDataSource(DataSourceDescriptor contrib) { 168 unbindDataSource(contrib); 169 datasources.remove(contrib.getName()); 170 } 171 172 protected void bindDataSource(DataSourceDescriptor descr) { 173 if (namingContext == null) { 174 return; 175 } 176 log.info("Registering datasource: " + descr.getName()); 177 try { 178 descr.bindSelf(namingContext); 179 } catch (NamingException e) { 180 log.error("Cannot bind datasource '" + descr.getName() + "' in JNDI", e); 181 } 182 } 183 184 protected void unbindDataSource(DataSourceDescriptor descr) { 185 if (namingContext == null) { 186 return; 187 } 188 log.info("Unregistering datasource: " + descr.name); 189 try { 190 descr.unbindSelf(namingContext); 191 } catch (NamingException cause) { 192 log.error("Cannot unbind datasource '" + descr.name + "' in JNDI", cause); 193 } 194 } 195 196 protected void addDataSourceLink(DataSourceLinkDescriptor contrib) { 197 links.put(contrib.name, contrib); 198 bindDataSourceLink(contrib); 199 } 200 201 protected void removeDataSourceLink(DataSourceLinkDescriptor contrib) { 202 unbindDataSourceLink(contrib); 203 links.remove(contrib.name); 204 } 205 206 protected void bindDataSourceLink(DataSourceLinkDescriptor descr) { 207 if (namingContext == null) { 208 return; 209 } 210 log.info("Registering DataSourceLink: " + descr.name); 211 try { 212 descr.bindSelf(namingContext); 213 } catch (NamingException e) { 214 log.error("Cannot bind DataSourceLink '" + descr.name + "' in JNDI", e); 215 } 216 } 217 218 protected void unbindDataSourceLink(DataSourceLinkDescriptor descr) { 219 if (namingContext == null) { 220 return; 221 } 222 log.info("Unregistering DataSourceLink: " + descr.name); 223 try { 224 descr.unbindSelf(namingContext); 225 } catch (NamingException e) { 226 log.error("Cannot unbind DataSourceLink '" + descr.name + "' in JNDI", e); 227 } 228 } 229 230 @Override 231 public <T> T getAdapter(Class<T> adapter) { 232 if (adapter.isAssignableFrom(PooledDataSourceRegistry.class)) { 233 return adapter.cast(poolRegistry); 234 } 235 return super.getAdapter(adapter); 236 } 237 238}