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 }