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
031 import javax.persistence.EntityManager;
032 import javax.persistence.EntityManagerFactory;
033 import javax.persistence.PersistenceException;
034 import javax.persistence.spi.ClassTransformer;
035 import javax.persistence.spi.PersistenceProvider;
036 import javax.persistence.spi.PersistenceUnitInfo;
037 import javax.persistence.spi.PersistenceUnitTransactionType;
038 import javax.sql.DataSource;
039 import javax.resource.ResourceException;
040
041 import org.apache.geronimo.connector.outbound.ConnectionFactorySource;
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.j2ee.j2eeobjectnames.NameFactory;
047 import org.apache.geronimo.kernel.classloader.TemporaryClassLoader;
048 import org.apache.geronimo.transaction.manager.TransactionManagerImpl;
049 import org.apache.geronimo.transformer.TransformerAgent;
050
051 /**
052 * @version $Rev: 545396 $ $Date: 2007-06-07 23:49:40 -0400 (Thu, 07 Jun 2007) $
053 */
054 public class PersistenceUnitGBean implements GBeanLifecycle {
055 private final String persistenceUnitRoot;
056 private final PersistenceUnitInfoImpl persistenceUnitInfo;
057 private final EntityManagerFactory entityManagerFactory;
058 private final TransactionManagerImpl transactionManager;
059 private final SingleElementCollection<ExtendedEntityManagerRegistry> entityManagerRegistry;
060
061
062 public PersistenceUnitGBean() {
063 persistenceUnitRoot = null;
064 persistenceUnitInfo = null;
065 entityManagerFactory = null;
066 transactionManager = null;
067 entityManagerRegistry = null;
068 }
069
070 public PersistenceUnitGBean(String persistenceUnitName,
071 String persistenceProviderClassName,
072 String persistenceUnitTransactionTypeString,
073 ConnectionFactorySource jtaDataSourceWrapper,
074 ConnectionFactorySource nonJtaDataSourceWrapper,
075 List<String> mappingFileNamesUntyped,
076 List<String> jarFileUrlsUntyped,
077 String persistenceUnitRoot,
078 List<String> managedClassNames,
079 boolean excludeUnlistedClassesValue,
080 Properties properties,
081 TransactionManagerImpl transactionManager,
082 Collection<ExtendedEntityManagerRegistry > entityManagerRegistry,
083 URL configurationBaseURL,
084 ClassLoader classLoader) throws URISyntaxException, MalformedURLException, ResourceException {
085 List<String> mappingFileNames = mappingFileNamesUntyped == null? new ArrayList<String>(): new ArrayList<String>(mappingFileNamesUntyped);
086 this.persistenceUnitRoot = persistenceUnitRoot;
087 URI configurationBaseURI = new File(configurationBaseURL.getFile()).toURI();
088 URL rootURL = null;
089 List<URL> jarFileUrls = null;
090 if (!excludeUnlistedClassesValue) {
091 rootURL = configurationBaseURI.resolve(persistenceUnitRoot).normalize().toURL();
092 jarFileUrls = new ArrayList<URL>();
093 for (String urlString: jarFileUrlsUntyped) {
094 URL url = configurationBaseURI.resolve(urlString).normalize().toURL();
095 jarFileUrls.add(url);
096 }
097 }
098 PersistenceUnitTransactionType persistenceUnitTransactionType = persistenceUnitTransactionTypeString == null? PersistenceUnitTransactionType.JTA: PersistenceUnitTransactionType.valueOf(persistenceUnitTransactionTypeString);
099
100 if (persistenceProviderClassName == null) persistenceProviderClassName = "org.apache.openjpa.persistence.PersistenceProviderImpl";
101
102 persistenceUnitInfo = new PersistenceUnitInfoImpl(persistenceUnitName,
103 persistenceProviderClassName,
104 persistenceUnitTransactionType,
105 jtaDataSourceWrapper == null? null: (DataSource)jtaDataSourceWrapper.$getResource(),
106 nonJtaDataSourceWrapper == null? null: (DataSource)nonJtaDataSourceWrapper.$getResource(),
107 mappingFileNames,
108 jarFileUrls,
109 rootURL,
110 managedClassNames,
111 excludeUnlistedClassesValue,
112 properties,
113 classLoader);
114 try {
115 Class clazz = classLoader.loadClass(persistenceProviderClassName);
116 PersistenceProvider persistenceProvider = (PersistenceProvider) clazz.newInstance();
117 entityManagerFactory = persistenceProvider.createContainerEntityManagerFactory(persistenceUnitInfo, properties);
118 } catch (ClassNotFoundException e) {
119 persistenceUnitInfo.destroy();
120 throw new PersistenceException("Could not locate PersistenceProvider class: " + persistenceProviderClassName + " in classloader " + classLoader, e);
121 } catch (InstantiationException e) {
122 persistenceUnitInfo.destroy();
123 throw new PersistenceException("Could not create PersistenceProvider instance: " + persistenceProviderClassName + " loaded from classloader " + classLoader, e);
124 } catch (IllegalAccessException e) {
125 persistenceUnitInfo.destroy();
126 throw new PersistenceException("Could not create PersistenceProvider instance: " + persistenceProviderClassName + " loaded from classloader " + classLoader, e);
127 }
128 this.transactionManager = transactionManager;
129 this.entityManagerRegistry = new SingleElementCollection<ExtendedEntityManagerRegistry>(entityManagerRegistry);
130 }
131
132 public EntityManagerFactory getEntityManagerFactory() {
133 return entityManagerFactory;
134 }
135
136 public EntityManager getEntityManager(boolean transactionScoped, Map properties) {
137 if (transactionScoped) {
138 return new CMPEntityManagerTxScoped(transactionManager, getPersistenceUnitName(), entityManagerFactory, properties);
139 } else if (entityManagerRegistry.getElement() != null) {
140 return new CMPEntityManagerExtended(entityManagerRegistry.getElement(), entityManagerFactory, properties);
141 } else {
142 throw new NullPointerException("No ExtendedEntityManagerRegistry supplied, you cannot use extended persistence contexts");
143 }
144 }
145
146 public String getPersistenceUnitName() {
147 return persistenceUnitInfo.getPersistenceUnitName();
148 }
149
150
151 public String getPersistenceUnitRoot() {
152 return persistenceUnitRoot;
153 }
154
155 public String getPersistenceProviderClassName() {
156 return persistenceUnitInfo.getPersistenceProviderClassName();
157 }
158
159 public PersistenceUnitTransactionType getTransactionType() {
160 return persistenceUnitInfo.getTransactionType();
161 }
162
163 public DataSource getJtaDataSource() {
164 return persistenceUnitInfo.getJtaDataSource();
165 }
166
167 public DataSource getNonJtaDataSource() {
168 return persistenceUnitInfo.getNonJtaDataSource();
169 }
170
171 public List<String> getMappingFileNames() {
172 return persistenceUnitInfo.getMappingFileNames();
173 }
174
175 public List<URL> getJarFileUrls() {
176 return persistenceUnitInfo.getJarFileUrls();
177 }
178
179 public URL getPersistenceUnitRootUrl() {
180 return persistenceUnitInfo.getPersistenceUnitRootUrl();
181 }
182
183 public List<String> getManagedClassNames() {
184 return persistenceUnitInfo.getManagedClassNames();
185 }
186
187 public boolean excludeUnlistedClasses() {
188 return persistenceUnitInfo.excludeUnlistedClasses();
189 }
190
191 public Properties getProperties() {
192 return persistenceUnitInfo.getProperties();
193 }
194
195 public ClassLoader getClassLoader() {
196 return persistenceUnitInfo.getClassLoader();
197 }
198
199 public void addTransformer(ClassTransformer classTransformer) {
200 persistenceUnitInfo.addTransformer(classTransformer);
201 }
202
203 public ClassLoader getNewTempClassLoader() {
204 return persistenceUnitInfo.getNewTempClassLoader();
205 }
206
207 public void doStart() throws Exception {
208 }
209
210 public void doStop() throws Exception {
211 //TODO remove any classtransformers added
212 entityManagerFactory.close();
213 persistenceUnitInfo.destroy();
214 }
215
216 public void doFail() {
217 entityManagerFactory.close();
218 persistenceUnitInfo.destroy();
219 }
220
221 private static class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
222 private final String persistenceUnitName;
223 private final String persistenceProviderClassName;
224 private final PersistenceUnitTransactionType persistenceUnitTransactionType;
225 private final DataSource jtaDataSource;
226 private final DataSource nonJtaDataSource;
227 private final List<String> mappingFileNames;
228 private final List<URL> jarFileUrls;
229 private final URL persistenceUnitRootUrl;
230 private final List<String> managedClassNames;
231 private final boolean excludeUnlistedClassesValue;
232 private final Properties properties;
233 private final ClassLoader classLoader;
234 private final TemporaryClassLoader tempClassLoader;
235 private final List<TransformerWrapper> transformers;
236
237
238 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) {
239 this.persistenceUnitName = persistenceUnitName;
240 this.persistenceProviderClassName = persistenceProviderClassName;
241 this.persistenceUnitTransactionType = persistenceUnitTransactionType;
242 this.jtaDataSource = jtaDataSource;
243 this.nonJtaDataSource = nonJtaDataSource;
244 this.mappingFileNames = mappingFileNames;
245 this.jarFileUrls = jarFileUrls;
246 this.persistenceUnitRootUrl = persistenceUnitRootUrl;
247 this.managedClassNames = managedClassNames;
248 this.excludeUnlistedClassesValue = excludeUnlistedClassesValue;
249 this.properties = properties;
250 this.classLoader = classLoader;
251 this.transformers = new ArrayList<TransformerWrapper>();
252
253 // This classloader can only be used during PersistenceProvider.createContainerEntityManagerFactory() calls
254 // Possible that it could be cleaned up sooner, but for now it's destroyed when the PUGBean is stopped
255 this.tempClassLoader = new TemporaryClassLoader(classLoader);
256 }
257
258 public String getPersistenceUnitName() {
259 return persistenceUnitName;
260 }
261
262 public String getPersistenceProviderClassName() {
263 return persistenceProviderClassName;
264 }
265
266 public PersistenceUnitTransactionType getTransactionType() {
267 return persistenceUnitTransactionType;
268 }
269
270 public DataSource getJtaDataSource() {
271 return jtaDataSource;
272 }
273
274 public DataSource getNonJtaDataSource() {
275 return nonJtaDataSource;
276 }
277
278 public List<String> getMappingFileNames() {
279 return mappingFileNames;
280 }
281
282 public List<URL> getJarFileUrls() {
283 return jarFileUrls;
284 }
285
286 public URL getPersistenceUnitRootUrl() {
287 return persistenceUnitRootUrl;
288 }
289
290 public List<String> getManagedClassNames() {
291 return managedClassNames;
292 }
293
294 public boolean excludeUnlistedClasses() {
295 return excludeUnlistedClassesValue;
296 }
297
298 public Properties getProperties() {
299 return properties;
300 }
301
302 public ClassLoader getClassLoader() {
303 return classLoader;
304 }
305
306 public void addTransformer(ClassTransformer classTransformer) {
307 TransformerWrapper transformer = new TransformerWrapper(classTransformer, classLoader);
308 transformers.add(transformer);
309 TransformerAgent.addTransformer(transformer);
310 }
311
312 public ClassLoader getNewTempClassLoader() {
313 return tempClassLoader;
314 }
315
316 private void destroy() {
317 for (TransformerWrapper t : transformers) {
318 TransformerAgent.removeTransformer(t);
319 }
320 }
321
322 }
323
324 public static final GBeanInfo GBEAN_INFO;
325
326 static {
327 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(PersistenceUnitGBean.class, NameFactory.PERSISTENCE_UNIT);
328 infoBuilder.setPriority(GBeanInfo.PRIORITY_CLASSLOADER);
329
330 infoBuilder.addAttribute("persistenceUnitName", String.class, true, true);
331 infoBuilder.addAttribute("persistenceProviderClassName", String.class, true, true);
332 infoBuilder.addAttribute("persistenceUnitTransactionType", String.class, true, true);
333 infoBuilder.addAttribute("mappingFileNames", List.class, true, true);
334 infoBuilder.addAttribute("jarFileUrls", List.class, true, true);
335 infoBuilder.addAttribute("persistenceUnitRoot", String.class, true, true);
336 infoBuilder.addAttribute("managedClassNames", List.class, true, true);
337 infoBuilder.addAttribute("excludeUnlistedClasses", boolean.class, true, true);
338 infoBuilder.addAttribute("properties", Properties.class, true, true);
339 infoBuilder.addAttribute("configurationBaseUrl", URL.class, true);
340
341 infoBuilder.addReference("TransactionManager", TransactionManagerImpl.class, NameFactory.TRANSACTION_MANAGER);
342 infoBuilder.addReference("JtaDataSourceWrapper", ConnectionFactorySource.class, NameFactory.JCA_MANAGED_CONNECTION_FACTORY);
343 infoBuilder.addReference("NonJtaDataSourceWrapper", ConnectionFactorySource.class, NameFactory.JCA_MANAGED_CONNECTION_FACTORY);
344 infoBuilder.addReference("EntityManagerRegistry", ExtendedEntityManagerRegistry.class, NameFactory.GERONIMO_SERVICE);
345
346 infoBuilder.setConstructor(new String[] {
347 "persistenceUnitName",
348 "persistenceProviderClassName",
349 "persistenceUnitTransactionType",
350 "JtaDataSourceWrapper",
351 "NonJtaDataSourceWrapper",
352 "mappingFileNames",
353 "jarFileUrls",
354 "persistenceUnitRoot",
355 "managedClassNames",
356 "excludeUnlistedClasses",
357 "properties",
358 "TransactionManager",
359 "EntityManagerRegistry",
360 "configurationBaseUrl",
361 "classLoader"
362 });
363
364 GBEAN_INFO = infoBuilder.getBeanInfo();
365
366 }
367
368 public static GBeanInfo getGBeanInfo() {
369 return GBEAN_INFO;
370 }
371
372 }