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: 735769 $ $Date: 2009-01-19 13:29:38 -0500 (Mon, 19 Jan 2009) $
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 //Per the EJB3.0 Persistence Specification section 6.2, the jar-file should be related to the Persistence Unit Root, which is the jar or directory where the persistence.xml is found
096 URI persistenceUnitBaseURI = configurationBaseURI.resolve(persistenceUnitRoot);
097 for (String urlString: jarFileUrlsUntyped) {
098 URL url = persistenceUnitBaseURI.resolve(urlString).normalize().toURL();
099 jarFileUrls.add(url);
100 }
101 }
102 if (managedClassNames == null) {
103 managedClassNames = NO_STRINGS;
104 }
105 if (properties == null) {
106 properties = new Properties();
107 }
108 PersistenceUnitTransactionType persistenceUnitTransactionType = persistenceUnitTransactionTypeString == null? PersistenceUnitTransactionType.JTA: PersistenceUnitTransactionType.valueOf(persistenceUnitTransactionTypeString);
109
110 if (persistenceProviderClassName == null) persistenceProviderClassName = "org.apache.openjpa.persistence.PersistenceProviderImpl";
111
112 persistenceUnitInfo = new PersistenceUnitInfoImpl(persistenceUnitName,
113 persistenceProviderClassName,
114 persistenceUnitTransactionType,
115 jtaDataSourceWrapper == null? null: (DataSource)jtaDataSourceWrapper.$getResource(),
116 nonJtaDataSourceWrapper == null? null: (DataSource)nonJtaDataSourceWrapper.$getResource(),
117 mappingFileNames,
118 jarFileUrls,
119 rootURL,
120 managedClassNames,
121 excludeUnlistedClassesValue,
122 properties,
123 classLoader);
124 try {
125 Class clazz = classLoader.loadClass(persistenceProviderClassName);
126 PersistenceProvider persistenceProvider = (PersistenceProvider) clazz.newInstance();
127 entityManagerFactory = persistenceProvider.createContainerEntityManagerFactory(persistenceUnitInfo, properties);
128 } catch (ClassNotFoundException e) {
129 persistenceUnitInfo.destroy();
130 throw new PersistenceException("Could not locate PersistenceProvider class: " + persistenceProviderClassName + " in classloader " + classLoader, e);
131 } catch (InstantiationException e) {
132 persistenceUnitInfo.destroy();
133 throw new PersistenceException("Could not create PersistenceProvider instance: " + persistenceProviderClassName + " loaded from classloader " + classLoader, e);
134 } catch (IllegalAccessException e) {
135 persistenceUnitInfo.destroy();
136 throw new PersistenceException("Could not create PersistenceProvider instance: " + persistenceProviderClassName + " loaded from classloader " + classLoader, e);
137 }
138 this.transactionManager = transactionManager;
139 this.entityManagerRegistry = new SingleElementCollection<ExtendedEntityManagerRegistry>(entityManagerRegistry);
140 }
141
142 public EntityManagerFactory getEntityManagerFactory() {
143 return entityManagerFactory;
144 }
145
146 public EntityManager getEntityManager(boolean transactionScoped, Map properties) {
147 if (transactionScoped) {
148 return new CMPEntityManagerTxScoped(transactionManager, getPersistenceUnitName(), entityManagerFactory, properties);
149 } else if (entityManagerRegistry.getElement() != null) {
150 return new CMPEntityManagerExtended(entityManagerRegistry.getElement(), entityManagerFactory, properties);
151 } else {
152 throw new NullPointerException("No ExtendedEntityManagerRegistry supplied, you cannot use extended persistence contexts");
153 }
154 }
155
156 public String getPersistenceUnitName() {
157 return persistenceUnitInfo.getPersistenceUnitName();
158 }
159
160
161 public String getPersistenceUnitRoot() {
162 return persistenceUnitRoot;
163 }
164
165 public String getPersistenceProviderClassName() {
166 return persistenceUnitInfo.getPersistenceProviderClassName();
167 }
168
169 public PersistenceUnitTransactionType getTransactionType() {
170 return persistenceUnitInfo.getTransactionType();
171 }
172
173 public DataSource getJtaDataSource() {
174 return persistenceUnitInfo.getJtaDataSource();
175 }
176
177 public DataSource getNonJtaDataSource() {
178 return persistenceUnitInfo.getNonJtaDataSource();
179 }
180
181 public List<String> getMappingFileNames() {
182 return persistenceUnitInfo.getMappingFileNames();
183 }
184
185 public List<URL> getJarFileUrls() {
186 return persistenceUnitInfo.getJarFileUrls();
187 }
188
189 public URL getPersistenceUnitRootUrl() {
190 return persistenceUnitInfo.getPersistenceUnitRootUrl();
191 }
192
193 public List<String> getManagedClassNames() {
194 return persistenceUnitInfo.getManagedClassNames();
195 }
196
197 public boolean excludeUnlistedClasses() {
198 return persistenceUnitInfo.excludeUnlistedClasses();
199 }
200
201 public Properties getProperties() {
202 return persistenceUnitInfo.getProperties();
203 }
204
205 public ClassLoader getClassLoader() {
206 return persistenceUnitInfo.getClassLoader();
207 }
208
209 public void addTransformer(ClassTransformer classTransformer) {
210 persistenceUnitInfo.addTransformer(classTransformer);
211 }
212
213 public ClassLoader getNewTempClassLoader() {
214 return persistenceUnitInfo.getNewTempClassLoader();
215 }
216
217 public void doStart() throws Exception {
218 }
219
220 public void doStop() throws Exception {
221 //TODO remove any classtransformers added
222 entityManagerFactory.close();
223 persistenceUnitInfo.destroy();
224 }
225
226 public void doFail() {
227 entityManagerFactory.close();
228 persistenceUnitInfo.destroy();
229 }
230
231 private static class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
232 private final String persistenceUnitName;
233 private final String persistenceProviderClassName;
234 private final PersistenceUnitTransactionType persistenceUnitTransactionType;
235 private final DataSource jtaDataSource;
236 private final DataSource nonJtaDataSource;
237 private final List<String> mappingFileNames;
238 private final List<URL> jarFileUrls;
239 private final URL persistenceUnitRootUrl;
240 private final List<String> managedClassNames;
241 private final boolean excludeUnlistedClassesValue;
242 private final Properties properties;
243 private final ClassLoader classLoader;
244 private final TemporaryClassLoader tempClassLoader;
245 private final List<TransformerWrapper> transformers;
246
247
248 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) {
249 this.persistenceUnitName = persistenceUnitName;
250 this.persistenceProviderClassName = persistenceProviderClassName;
251 this.persistenceUnitTransactionType = persistenceUnitTransactionType;
252 this.jtaDataSource = jtaDataSource;
253 this.nonJtaDataSource = nonJtaDataSource;
254 this.mappingFileNames = mappingFileNames;
255 this.jarFileUrls = jarFileUrls;
256 this.persistenceUnitRootUrl = persistenceUnitRootUrl;
257 this.managedClassNames = managedClassNames;
258 this.excludeUnlistedClassesValue = excludeUnlistedClassesValue;
259 this.properties = properties;
260 this.classLoader = classLoader;
261 this.transformers = new ArrayList<TransformerWrapper>();
262
263 // This classloader can only be used during PersistenceProvider.createContainerEntityManagerFactory() calls
264 // Possible that it could be cleaned up sooner, but for now it's destroyed when the PUGBean is stopped
265 this.tempClassLoader = new TemporaryClassLoader(classLoader);
266 }
267
268 public String getPersistenceUnitName() {
269 return persistenceUnitName;
270 }
271
272 public String getPersistenceProviderClassName() {
273 return persistenceProviderClassName;
274 }
275
276 public PersistenceUnitTransactionType getTransactionType() {
277 return persistenceUnitTransactionType;
278 }
279
280 public DataSource getJtaDataSource() {
281 return jtaDataSource;
282 }
283
284 public DataSource getNonJtaDataSource() {
285 return nonJtaDataSource;
286 }
287
288 public List<String> getMappingFileNames() {
289 return mappingFileNames;
290 }
291
292 public List<URL> getJarFileUrls() {
293 return jarFileUrls;
294 }
295
296 public URL getPersistenceUnitRootUrl() {
297 return persistenceUnitRootUrl;
298 }
299
300 public List<String> getManagedClassNames() {
301 return managedClassNames;
302 }
303
304 public boolean excludeUnlistedClasses() {
305 return excludeUnlistedClassesValue;
306 }
307
308 public Properties getProperties() {
309 return properties;
310 }
311
312 public ClassLoader getClassLoader() {
313 return classLoader;
314 }
315
316 public void addTransformer(ClassTransformer classTransformer) {
317 TransformerWrapper transformer = new TransformerWrapper(classTransformer, classLoader);
318 transformers.add(transformer);
319 TransformerAgent.addTransformer(transformer);
320 }
321
322 public ClassLoader getNewTempClassLoader() {
323 return tempClassLoader;
324 }
325
326 private void destroy() {
327 for (TransformerWrapper t : transformers) {
328 TransformerAgent.removeTransformer(t);
329 }
330 }
331
332 }
333
334 public static final GBeanInfo GBEAN_INFO;
335
336 static {
337 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(PersistenceUnitGBean.class, NameFactory.PERSISTENCE_UNIT);
338 infoBuilder.setPriority(GBeanInfo.PRIORITY_CLASSLOADER);
339
340 infoBuilder.addAttribute("persistenceUnitName", String.class, true, true);
341 infoBuilder.addAttribute("persistenceProviderClassName", String.class, true, true);
342 infoBuilder.addAttribute("persistenceUnitTransactionType", String.class, true, true);
343 infoBuilder.addAttribute("mappingFileNames", List.class, true, true);
344 infoBuilder.addAttribute("jarFileUrls", List.class, true, true);
345 infoBuilder.addAttribute("persistenceUnitRoot", String.class, true, true);
346 infoBuilder.addAttribute("managedClassNames", List.class, true, true);
347 infoBuilder.addAttribute("excludeUnlistedClasses", boolean.class, true, true);
348 infoBuilder.addAttribute("properties", Properties.class, true, true);
349 infoBuilder.addAttribute("configurationBaseUrl", URL.class, true);
350
351 infoBuilder.addReference("TransactionManager", TransactionManagerImpl.class, NameFactory.JTA_RESOURCE);
352 infoBuilder.addReference("JtaDataSourceWrapper", ResourceSource.class, NameFactory.JCA_MANAGED_CONNECTION_FACTORY);
353 infoBuilder.addReference("NonJtaDataSourceWrapper", ResourceSource.class, NameFactory.JCA_MANAGED_CONNECTION_FACTORY);
354 infoBuilder.addReference("EntityManagerRegistry", ExtendedEntityManagerRegistry.class, NameFactory.GERONIMO_SERVICE);
355
356 infoBuilder.setConstructor(new String[] {
357 "persistenceUnitName",
358 "persistenceProviderClassName",
359 "persistenceUnitTransactionType",
360 "JtaDataSourceWrapper",
361 "NonJtaDataSourceWrapper",
362 "mappingFileNames",
363 "jarFileUrls",
364 "persistenceUnitRoot",
365 "managedClassNames",
366 "excludeUnlistedClasses",
367 "properties",
368 "TransactionManager",
369 "EntityManagerRegistry",
370 "configurationBaseUrl",
371 "classLoader"
372 });
373
374 GBEAN_INFO = infoBuilder.getBeanInfo();
375
376 }
377
378 public static GBeanInfo getGBeanInfo() {
379 return GBEAN_INFO;
380 }
381
382 }