001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.persistence; 019 020 import java.io.File; 021 import java.net.MalformedURLException; 022 import java.net.URI; 023 import java.net.URISyntaxException; 024 import java.net.URL; 025 import java.util.ArrayList; 026 import java.util.Collection; 027 import java.util.List; 028 import java.util.Map; 029 import java.util.Properties; 030 import java.util.Collections; 031 032 import javax.persistence.EntityManager; 033 import javax.persistence.EntityManagerFactory; 034 import javax.persistence.PersistenceException; 035 import javax.persistence.spi.ClassTransformer; 036 import javax.persistence.spi.PersistenceProvider; 037 import javax.persistence.spi.PersistenceUnitInfo; 038 import javax.persistence.spi.PersistenceUnitTransactionType; 039 import javax.resource.ResourceException; 040 import javax.sql.DataSource; 041 042 import org.apache.geronimo.gbean.GBeanInfo; 043 import org.apache.geronimo.gbean.GBeanInfoBuilder; 044 import org.apache.geronimo.gbean.GBeanLifecycle; 045 import org.apache.geronimo.gbean.SingleElementCollection; 046 import org.apache.geronimo.naming.ResourceSource; 047 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 048 import org.apache.geronimo.kernel.classloader.TemporaryClassLoader; 049 import org.apache.geronimo.transaction.manager.TransactionManagerImpl; 050 import org.apache.geronimo.transformer.TransformerAgent; 051 052 /** 053 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 054 */ 055 public class PersistenceUnitGBean implements GBeanLifecycle { 056 private static final List<URL> NO_URLS = Collections.emptyList(); 057 private static final List<String> NO_STRINGS = Collections.emptyList(); 058 private final String persistenceUnitRoot; 059 private final PersistenceUnitInfoImpl persistenceUnitInfo; 060 private final EntityManagerFactory entityManagerFactory; 061 private final TransactionManagerImpl transactionManager; 062 private final SingleElementCollection<ExtendedEntityManagerRegistry> entityManagerRegistry; 063 064 065 public PersistenceUnitGBean() { 066 persistenceUnitRoot = null; 067 persistenceUnitInfo = null; 068 entityManagerFactory = null; 069 transactionManager = null; 070 entityManagerRegistry = null; 071 } 072 073 public PersistenceUnitGBean(String persistenceUnitName, 074 String persistenceProviderClassName, 075 String persistenceUnitTransactionTypeString, 076 ResourceSource<ResourceException> jtaDataSourceWrapper, 077 ResourceSource<ResourceException> nonJtaDataSourceWrapper, 078 List<String> mappingFileNamesUntyped, 079 List<String> jarFileUrlsUntyped, 080 String persistenceUnitRoot, 081 List<String> managedClassNames, 082 boolean excludeUnlistedClassesValue, 083 Properties properties, 084 TransactionManagerImpl transactionManager, 085 Collection<ExtendedEntityManagerRegistry > entityManagerRegistry, 086 URL configurationBaseURL, 087 ClassLoader classLoader) throws URISyntaxException, MalformedURLException, ResourceException { 088 List<String> mappingFileNames = mappingFileNamesUntyped == null? NO_STRINGS: new ArrayList<String>(mappingFileNamesUntyped); 089 this.persistenceUnitRoot = persistenceUnitRoot; 090 URI configurationBaseURI = new File(configurationBaseURL.getFile()).toURI(); 091 URL rootURL = configurationBaseURI.resolve(persistenceUnitRoot).normalize().toURL(); 092 List<URL> jarFileUrls = NO_URLS; 093 if (!excludeUnlistedClassesValue) { 094 jarFileUrls = new ArrayList<URL>(); 095 for (String urlString: jarFileUrlsUntyped) { 096 URL url = configurationBaseURI.resolve(urlString).normalize().toURL(); 097 jarFileUrls.add(url); 098 } 099 } 100 if (managedClassNames == null) { 101 managedClassNames = NO_STRINGS; 102 } 103 if (properties == null) { 104 properties = new Properties(); 105 } 106 PersistenceUnitTransactionType persistenceUnitTransactionType = persistenceUnitTransactionTypeString == null? PersistenceUnitTransactionType.JTA: PersistenceUnitTransactionType.valueOf(persistenceUnitTransactionTypeString); 107 108 if (persistenceProviderClassName == null) persistenceProviderClassName = "org.apache.openjpa.persistence.PersistenceProviderImpl"; 109 110 persistenceUnitInfo = new PersistenceUnitInfoImpl(persistenceUnitName, 111 persistenceProviderClassName, 112 persistenceUnitTransactionType, 113 jtaDataSourceWrapper == null? null: (DataSource)jtaDataSourceWrapper.$getResource(), 114 nonJtaDataSourceWrapper == null? null: (DataSource)nonJtaDataSourceWrapper.$getResource(), 115 mappingFileNames, 116 jarFileUrls, 117 rootURL, 118 managedClassNames, 119 excludeUnlistedClassesValue, 120 properties, 121 classLoader); 122 try { 123 Class clazz = classLoader.loadClass(persistenceProviderClassName); 124 PersistenceProvider persistenceProvider = (PersistenceProvider) clazz.newInstance(); 125 entityManagerFactory = persistenceProvider.createContainerEntityManagerFactory(persistenceUnitInfo, properties); 126 } catch (ClassNotFoundException e) { 127 persistenceUnitInfo.destroy(); 128 throw new PersistenceException("Could not locate PersistenceProvider class: " + persistenceProviderClassName + " in classloader " + classLoader, e); 129 } catch (InstantiationException e) { 130 persistenceUnitInfo.destroy(); 131 throw new PersistenceException("Could not create PersistenceProvider instance: " + persistenceProviderClassName + " loaded from classloader " + classLoader, e); 132 } catch (IllegalAccessException e) { 133 persistenceUnitInfo.destroy(); 134 throw new PersistenceException("Could not create PersistenceProvider instance: " + persistenceProviderClassName + " loaded from classloader " + classLoader, e); 135 } 136 this.transactionManager = transactionManager; 137 this.entityManagerRegistry = new SingleElementCollection<ExtendedEntityManagerRegistry>(entityManagerRegistry); 138 } 139 140 public EntityManagerFactory getEntityManagerFactory() { 141 return entityManagerFactory; 142 } 143 144 public EntityManager getEntityManager(boolean transactionScoped, Map properties) { 145 if (transactionScoped) { 146 return new CMPEntityManagerTxScoped(transactionManager, getPersistenceUnitName(), entityManagerFactory, properties); 147 } else if (entityManagerRegistry.getElement() != null) { 148 return new CMPEntityManagerExtended(entityManagerRegistry.getElement(), entityManagerFactory, properties); 149 } else { 150 throw new NullPointerException("No ExtendedEntityManagerRegistry supplied, you cannot use extended persistence contexts"); 151 } 152 } 153 154 public String getPersistenceUnitName() { 155 return persistenceUnitInfo.getPersistenceUnitName(); 156 } 157 158 159 public String getPersistenceUnitRoot() { 160 return persistenceUnitRoot; 161 } 162 163 public String getPersistenceProviderClassName() { 164 return persistenceUnitInfo.getPersistenceProviderClassName(); 165 } 166 167 public PersistenceUnitTransactionType getTransactionType() { 168 return persistenceUnitInfo.getTransactionType(); 169 } 170 171 public DataSource getJtaDataSource() { 172 return persistenceUnitInfo.getJtaDataSource(); 173 } 174 175 public DataSource getNonJtaDataSource() { 176 return persistenceUnitInfo.getNonJtaDataSource(); 177 } 178 179 public List<String> getMappingFileNames() { 180 return persistenceUnitInfo.getMappingFileNames(); 181 } 182 183 public List<URL> getJarFileUrls() { 184 return persistenceUnitInfo.getJarFileUrls(); 185 } 186 187 public URL getPersistenceUnitRootUrl() { 188 return persistenceUnitInfo.getPersistenceUnitRootUrl(); 189 } 190 191 public List<String> getManagedClassNames() { 192 return persistenceUnitInfo.getManagedClassNames(); 193 } 194 195 public boolean excludeUnlistedClasses() { 196 return persistenceUnitInfo.excludeUnlistedClasses(); 197 } 198 199 public Properties getProperties() { 200 return persistenceUnitInfo.getProperties(); 201 } 202 203 public ClassLoader getClassLoader() { 204 return persistenceUnitInfo.getClassLoader(); 205 } 206 207 public void addTransformer(ClassTransformer classTransformer) { 208 persistenceUnitInfo.addTransformer(classTransformer); 209 } 210 211 public ClassLoader getNewTempClassLoader() { 212 return persistenceUnitInfo.getNewTempClassLoader(); 213 } 214 215 public void doStart() throws Exception { 216 } 217 218 public void doStop() throws Exception { 219 //TODO remove any classtransformers added 220 entityManagerFactory.close(); 221 persistenceUnitInfo.destroy(); 222 } 223 224 public void doFail() { 225 entityManagerFactory.close(); 226 persistenceUnitInfo.destroy(); 227 } 228 229 private static class PersistenceUnitInfoImpl implements PersistenceUnitInfo { 230 private final String persistenceUnitName; 231 private final String persistenceProviderClassName; 232 private final PersistenceUnitTransactionType persistenceUnitTransactionType; 233 private final DataSource jtaDataSource; 234 private final DataSource nonJtaDataSource; 235 private final List<String> mappingFileNames; 236 private final List<URL> jarFileUrls; 237 private final URL persistenceUnitRootUrl; 238 private final List<String> managedClassNames; 239 private final boolean excludeUnlistedClassesValue; 240 private final Properties properties; 241 private final ClassLoader classLoader; 242 private final TemporaryClassLoader tempClassLoader; 243 private final List<TransformerWrapper> transformers; 244 245 246 public PersistenceUnitInfoImpl(String persistenceUnitName, String persistenceProviderClassName, PersistenceUnitTransactionType persistenceUnitTransactionType, DataSource jtaDataSource, DataSource nonJtaDataSource, List<String> mappingFileNames, List<URL> jarFileUrls, URL persistenceUnitRootUrl, List<String> managedClassNames, boolean excludeUnlistedClassesValue, Properties properties, ClassLoader classLoader) { 247 this.persistenceUnitName = persistenceUnitName; 248 this.persistenceProviderClassName = persistenceProviderClassName; 249 this.persistenceUnitTransactionType = persistenceUnitTransactionType; 250 this.jtaDataSource = jtaDataSource; 251 this.nonJtaDataSource = nonJtaDataSource; 252 this.mappingFileNames = mappingFileNames; 253 this.jarFileUrls = jarFileUrls; 254 this.persistenceUnitRootUrl = persistenceUnitRootUrl; 255 this.managedClassNames = managedClassNames; 256 this.excludeUnlistedClassesValue = excludeUnlistedClassesValue; 257 this.properties = properties; 258 this.classLoader = classLoader; 259 this.transformers = new ArrayList<TransformerWrapper>(); 260 261 // This classloader can only be used during PersistenceProvider.createContainerEntityManagerFactory() calls 262 // Possible that it could be cleaned up sooner, but for now it's destroyed when the PUGBean is stopped 263 this.tempClassLoader = new TemporaryClassLoader(classLoader); 264 } 265 266 public String getPersistenceUnitName() { 267 return persistenceUnitName; 268 } 269 270 public String getPersistenceProviderClassName() { 271 return persistenceProviderClassName; 272 } 273 274 public PersistenceUnitTransactionType getTransactionType() { 275 return persistenceUnitTransactionType; 276 } 277 278 public DataSource getJtaDataSource() { 279 return jtaDataSource; 280 } 281 282 public DataSource getNonJtaDataSource() { 283 return nonJtaDataSource; 284 } 285 286 public List<String> getMappingFileNames() { 287 return mappingFileNames; 288 } 289 290 public List<URL> getJarFileUrls() { 291 return jarFileUrls; 292 } 293 294 public URL getPersistenceUnitRootUrl() { 295 return persistenceUnitRootUrl; 296 } 297 298 public List<String> getManagedClassNames() { 299 return managedClassNames; 300 } 301 302 public boolean excludeUnlistedClasses() { 303 return excludeUnlistedClassesValue; 304 } 305 306 public Properties getProperties() { 307 return properties; 308 } 309 310 public ClassLoader getClassLoader() { 311 return classLoader; 312 } 313 314 public void addTransformer(ClassTransformer classTransformer) { 315 TransformerWrapper transformer = new TransformerWrapper(classTransformer, classLoader); 316 transformers.add(transformer); 317 TransformerAgent.addTransformer(transformer); 318 } 319 320 public ClassLoader getNewTempClassLoader() { 321 return tempClassLoader; 322 } 323 324 private void destroy() { 325 for (TransformerWrapper t : transformers) { 326 TransformerAgent.removeTransformer(t); 327 } 328 } 329 330 } 331 332 public static final GBeanInfo GBEAN_INFO; 333 334 static { 335 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(PersistenceUnitGBean.class, NameFactory.PERSISTENCE_UNIT); 336 infoBuilder.setPriority(GBeanInfo.PRIORITY_CLASSLOADER); 337 338 infoBuilder.addAttribute("persistenceUnitName", String.class, true, true); 339 infoBuilder.addAttribute("persistenceProviderClassName", String.class, true, true); 340 infoBuilder.addAttribute("persistenceUnitTransactionType", String.class, true, true); 341 infoBuilder.addAttribute("mappingFileNames", List.class, true, true); 342 infoBuilder.addAttribute("jarFileUrls", List.class, true, true); 343 infoBuilder.addAttribute("persistenceUnitRoot", String.class, true, true); 344 infoBuilder.addAttribute("managedClassNames", List.class, true, true); 345 infoBuilder.addAttribute("excludeUnlistedClasses", boolean.class, true, true); 346 infoBuilder.addAttribute("properties", Properties.class, true, true); 347 infoBuilder.addAttribute("configurationBaseUrl", URL.class, true); 348 349 infoBuilder.addReference("TransactionManager", TransactionManagerImpl.class, NameFactory.JTA_RESOURCE); 350 infoBuilder.addReference("JtaDataSourceWrapper", ResourceSource.class, NameFactory.JCA_MANAGED_CONNECTION_FACTORY); 351 infoBuilder.addReference("NonJtaDataSourceWrapper", ResourceSource.class, NameFactory.JCA_MANAGED_CONNECTION_FACTORY); 352 infoBuilder.addReference("EntityManagerRegistry", ExtendedEntityManagerRegistry.class, NameFactory.GERONIMO_SERVICE); 353 354 infoBuilder.setConstructor(new String[] { 355 "persistenceUnitName", 356 "persistenceProviderClassName", 357 "persistenceUnitTransactionType", 358 "JtaDataSourceWrapper", 359 "NonJtaDataSourceWrapper", 360 "mappingFileNames", 361 "jarFileUrls", 362 "persistenceUnitRoot", 363 "managedClassNames", 364 "excludeUnlistedClasses", 365 "properties", 366 "TransactionManager", 367 "EntityManagerRegistry", 368 "configurationBaseUrl", 369 "classLoader" 370 }); 371 372 GBEAN_INFO = infoBuilder.getBeanInfo(); 373 374 } 375 376 public static GBeanInfo getGBeanInfo() { 377 return GBEAN_INFO; 378 } 379 380 }