001/* 002 * (C) Copyright 2009 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Florent Guillaume 016 */ 017 018package org.nuxeo.runtime.datasource; 019 020import java.util.HashMap; 021import java.util.Map; 022 023import javax.naming.CompositeName; 024import javax.naming.Context; 025import javax.naming.Name; 026import javax.naming.NamingException; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.nuxeo.runtime.jtajca.NuxeoContainer; 031import org.nuxeo.runtime.model.ComponentContext; 032import org.nuxeo.runtime.model.ComponentInstance; 033import org.nuxeo.runtime.model.DefaultComponent; 034 035/** 036 * Nuxeo component allowing the JNDI registration of datasources by extension point contributions. 037 * <p> 038 * For now only the internal Nuxeo JNDI server is supported. 039 */ 040public class DataSourceComponent extends DefaultComponent { 041 042 private final Log log = LogFactory.getLog(DataSourceComponent.class); 043 044 public static final String DATASOURCES_XP = "datasources"; 045 046 public static final String ENV_CTX_NAME = "java:comp/env/"; 047 048 protected final Map<String, DataSourceDescriptor> datasources = new HashMap<String, DataSourceDescriptor>(); 049 050 protected final Map<String, DataSourceLinkDescriptor> links = new HashMap<String, DataSourceLinkDescriptor>(); 051 052 protected final PooledDataSourceRegistry registry = new PooledDataSourceRegistry(); 053 054 protected Context namingContext; 055 056 @Override 057 public void registerContribution(Object contrib, String extensionPoint, ComponentInstance component) { 058 if (DATASOURCES_XP.equals(extensionPoint)) { 059 if (contrib instanceof DataSourceDescriptor) { 060 addDataSource((DataSourceDescriptor) contrib); 061 } else if (contrib instanceof DataSourceLinkDescriptor) { 062 addDataSourceLink((DataSourceLinkDescriptor) contrib); 063 } else { 064 log.error("Wrong datasource extension type " + contrib.getClass().getName()); 065 } 066 } else { 067 log.error("Ignoring unknown extension point: " + extensionPoint); 068 } 069 } 070 071 @Override 072 public void unregisterContribution(Object contrib, String extensionPoint, ComponentInstance component) { 073 if (DATASOURCES_XP.equals(extensionPoint)) { 074 if (contrib instanceof DataSourceDescriptor) { 075 removeDataSource((DataSourceDescriptor) contrib); 076 } else if (contrib instanceof DataSourceLinkDescriptor) { 077 removeDataSourceLink((DataSourceLinkDescriptor) contrib); 078 } 079 } 080 } 081 082 @Override 083 public int getApplicationStartedOrder() { 084 return -1000; 085 } 086 087 public boolean isStarted() { 088 return namingContext != null; 089 } 090 091 @Override 092 public void applicationStarted(ComponentContext context) { 093 if (namingContext != null) { 094 return; 095 } 096 namingContext = NuxeoContainer.getRootContext(); 097 // allocate datasource sub-contexts 098 Name comp; 099 try { 100 comp = new CompositeName(DataSourceHelper.getDataSourceJNDIPrefix()); 101 } catch (NamingException e) { 102 throw new RuntimeException(e); 103 } 104 Context ctx = namingContext; 105 for (int i = 0; i < comp.size(); i++) { 106 try { 107 ctx = (Context) ctx.lookup(comp.get(i)); 108 } catch (NamingException e) { 109 try { 110 ctx = ctx.createSubcontext(comp.get(i)); 111 } catch (NamingException e1) { 112 throw new RuntimeException(e1); 113 } 114 } 115 } 116 // bind datasources 117 for (DataSourceDescriptor datasourceDesc : datasources.values()) { 118 bindDataSource(datasourceDesc); 119 } 120 // bind links 121 for (DataSourceLinkDescriptor linkDesc : links.values()) { 122 bindDataSourceLink(linkDesc); 123 } 124 } 125 126 @Override 127 public void deactivate(ComponentContext context) { 128 super.deactivate(context); 129 for (DataSourceLinkDescriptor desc : links.values()) { 130 unbindDataSourceLink(desc); 131 } 132 links.clear(); 133 for (DataSourceDescriptor desc : datasources.values()) { 134 unbindDataSource(desc); 135 } 136 datasources.clear(); 137 namingContext = null; 138 } 139 140 protected void addDataSource(DataSourceDescriptor contrib) { 141 datasources.put(contrib.getName(), contrib); 142 bindDataSource(contrib); 143 } 144 145 protected void removeDataSource(DataSourceDescriptor contrib) { 146 unbindDataSource(contrib); 147 datasources.remove(contrib.getName()); 148 } 149 150 protected void bindDataSource(DataSourceDescriptor descr) { 151 if (namingContext == null) { 152 return; 153 } 154 log.info("Registering datasource: " + descr.getName()); 155 try { 156 descr.bindSelf(namingContext); 157 } catch (NamingException e) { 158 log.error("Cannot bind datasource '" + descr.getName() + "' in JNDI", e); 159 } 160 } 161 162 protected void unbindDataSource(DataSourceDescriptor descr) { 163 if (namingContext == null) { 164 return; 165 } 166 log.info("Unregistering datasource: " + descr.name); 167 try { 168 descr.unbindSelf(namingContext); 169 } catch (NamingException cause) { 170 log.error("Cannot unbind datasource '" + descr.name + "' in JNDI", cause); 171 } 172 } 173 174 protected void addDataSourceLink(DataSourceLinkDescriptor contrib) { 175 links.put(contrib.name, contrib); 176 bindDataSourceLink(contrib); 177 } 178 179 protected void removeDataSourceLink(DataSourceLinkDescriptor contrib) { 180 unbindDataSourceLink(contrib); 181 links.remove(contrib.name); 182 } 183 184 protected void bindDataSourceLink(DataSourceLinkDescriptor descr) { 185 if (namingContext == null) { 186 return; 187 } 188 log.info("Registering DataSourceLink: " + descr.name); 189 try { 190 descr.bindSelf(namingContext); 191 } catch (NamingException e) { 192 log.error("Cannot bind DataSourceLink '" + descr.name + "' in JNDI", e); 193 } 194 } 195 196 protected void unbindDataSourceLink(DataSourceLinkDescriptor descr) { 197 if (namingContext == null) { 198 return; 199 } 200 log.info("Unregistering DataSourceLink: " + descr.name); 201 try { 202 descr.unbindSelf(namingContext); 203 } catch (NamingException e) { 204 log.error("Cannot unbind DataSourceLink '" + descr.name + "' in JNDI", e); 205 } 206 } 207 208 @Override 209 public <T> T getAdapter(Class<T> adapter) { 210 if (adapter.isAssignableFrom(PooledDataSourceRegistry.class)) { 211 return adapter.cast(registry); 212 } 213 return super.getAdapter(adapter); 214 } 215 216}