KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > jpa > persistenceunit > DefaultPersistenceUnitManager


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.orm.jpa.persistenceunit;
18
19 import java.io.IOException JavaDoc;
20 import java.net.URL JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25
26 import javax.persistence.PersistenceException;
27 import javax.persistence.spi.PersistenceUnitInfo;
28 import javax.sql.DataSource JavaDoc;
29
30 import org.springframework.beans.factory.InitializingBean;
31 import org.springframework.context.ResourceLoaderAware;
32 import org.springframework.core.io.Resource;
33 import org.springframework.core.io.ResourceLoader;
34 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
35 import org.springframework.core.io.support.ResourcePatternResolver;
36 import org.springframework.core.io.support.ResourcePatternUtils;
37 import org.springframework.instrument.classloading.LoadTimeWeaver;
38 import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
39 import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
40 import org.springframework.jdbc.datasource.lookup.MapDataSourceLookup;
41 import org.springframework.util.ObjectUtils;
42
43 /**
44  * Default implementation of the PersistenceUnitManager interface.
45  * Used as internal default by LocalContainerEntityManagerFactoryBean.
46  *
47  * <p>Supports standard JPA scanning for <code>persistence.xml</code> files,
48  * with configurable file locations, JDBC DataSource lookup and load-time weaving.
49  *
50  * <p>The default XML file location is <code>classpath:META-INF/persistence.xml</code>,
51  * scanning for all matching files in the class path (as defined in the JPA specification).
52  * DataSource names are by default interpreted as JNDI names, and no load time weaving
53  * is available (which requires weaving to be turned off in the persistence provider).
54  *
55  * @author Juergen Hoeller
56  * @since 2.0
57  * @see #setPersistenceXmlLocations
58  * @see #setDataSourceLookup
59  * @see #setLoadTimeWeaver
60  * @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
61  */

62 public class DefaultPersistenceUnitManager implements PersistenceUnitManager, ResourceLoaderAware, InitializingBean {
63
64     /**
65      * Default location of the <code>persistence.xml</code> file:
66      * "classpath*:META-INF/persistence.xml".
67      */

68     public final static String JavaDoc DEFAULT_PERSISTENCE_XML_LOCATION = "classpath*:META-INF/persistence.xml";
69
70     /**
71      * Default location for the persistence unit root URL:
72      * "classpath:", indicating the root of the class path.
73      */

74     public final static String JavaDoc ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION = "classpath:";
75
76
77     /** Location of persistence.xml file(s) */
78     private String JavaDoc[] persistenceXmlLocations = new String JavaDoc[] {DEFAULT_PERSISTENCE_XML_LOCATION};
79
80     private String JavaDoc defaultPersistenceUnitRootLocation = ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION;
81
82     private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
83
84     private DataSource JavaDoc defaultDataSource;
85
86     private LoadTimeWeaver loadTimeWeaver;
87
88     private PersistenceUnitPostProcessor[] persistenceUnitPostProcessors;
89
90     private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
91
92     private final Set JavaDoc<String JavaDoc> persistenceUnitInfoNames = new HashSet JavaDoc<String JavaDoc>();
93
94     private final Map JavaDoc<String JavaDoc, PersistenceUnitInfo> persistenceUnitInfos = new HashMap JavaDoc<String JavaDoc, PersistenceUnitInfo>();
95
96
97     /**
98      * Set the locations of the <code>persistence.xml</code> files to load.
99      * These can be specified as Spring resource locations and/or location patterns.
100      * <p>Default is "classpath*:META-INF/persistence.xml".
101      * @param persistenceXmlLocations an array of Spring resource Strings
102      * identifying the location of the <code>persistence.xml</code> files to read
103      */

104     public void setPersistenceXmlLocations(String JavaDoc[] persistenceXmlLocations) {
105         this.persistenceXmlLocations = persistenceXmlLocations;
106     }
107
108     /**
109      * Set the default persistence unit root location, to be applied
110      * if no unit-specific persistence unit root could be determined.
111      * <p>Default is "classpath:", that is, the root of the current class path
112      * (nearest root directory). To be overridden if unit-specific resolution
113      * does not work and the class path root is not appropriate either.
114      */

115     public void setDefaultPersistenceUnitRootLocation(String JavaDoc defaultPersistenceUnitRootLocation) {
116         this.defaultPersistenceUnitRootLocation = defaultPersistenceUnitRootLocation;
117     }
118
119     /**
120      * Specify the JDBC DataSources that the JPA persistence provider is supposed
121      * to use for accessing the database, resolving data source names in
122      * <code>persistence.xml</code> against Spring-managed DataSources.
123      * <p>The specified Map needs to define data source names for specific DataSource
124      * objects, matching the data source names used in <code>persistence.xml</code>.
125      * If not specified, data source names will be resolved as JNDI names instead
126      * (as defined by standard JPA).
127      * @see org.springframework.jdbc.datasource.lookup.MapDataSourceLookup
128      */

129     public void setDataSources(Map JavaDoc<String JavaDoc, DataSource JavaDoc> dataSources) {
130         this.dataSourceLookup = new MapDataSourceLookup(dataSources);
131     }
132
133     /**
134      * Specify the JDBC DataSourceLookup that provides DataSources for the
135      * persistence provider, resolving data source names in <code>persistence.xml</code>
136      * against Spring-managed DataSource instances.
137      * <p>Default is JndiDataSourceLookup, which resolves DataSource names as
138      * JNDI names (as defined by standard JPA). Specify a BeanFactoryDataSourceLookup
139      * instance if you want DataSource names to be resolved against Spring bean names.
140      * <p>Alternatively, consider passing in a map from names to DataSource instances
141      * via the "dataSources" property. If the <code>persistence.xml</code> file
142      * does not define DataSource names at all, specify a default DataSource
143      * via the "defaultDataSource" property.
144      * @see org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup
145      * @see org.springframework.jdbc.datasource.lookup.BeanFactoryDataSourceLookup
146      * @see #setDataSources
147      * @see #setDefaultDataSource
148      */

149     public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
150         this.dataSourceLookup = (dataSourceLookup != null ? dataSourceLookup : new JndiDataSourceLookup());
151     }
152
153     /**
154      * Return the JDBC DataSourceLookup that provides DataSources for the
155      * persistence provider, resolving data source names in <code>persistence.xml</code>
156      * against Spring-managed DataSource instances.
157      */

158     public DataSourceLookup getDataSourceLookup() {
159         return dataSourceLookup;
160     }
161
162     /**
163      * Specify the JDBC DataSource that the JPA persistence provider is supposed
164      * to use for accessing the database if none has been specified in
165      * <code>persistence.xml</code>.
166      * <p>In JPA speak, a DataSource passed in here will be uses as "nonJtaDataSource"
167      * on the PersistenceUnitInfo passed to the PersistenceProvider, provided that
168      * none has been registered before.
169      * @see javax.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource()
170      */

171     public void setDefaultDataSource(DataSource JavaDoc defaultDataSource) {
172         this.defaultDataSource = defaultDataSource;
173     }
174
175     /**
176      * Return the JDBC DataSource that the JPA persistence provider is supposed
177      * to use for accessing the database if none has been specified in
178      * <code>persistence.xml</code>.
179      */

180     public DataSource JavaDoc getDefaultDataSource() {
181         return defaultDataSource;
182     }
183
184     /**
185      * Specify the Spring LoadTimeWeaver to use for class instrumentation according
186      * to the JPA class transformer contract.
187      * <p>It is not required to specify a LoadTimeWeaver: Most providers will be
188      * able to provide a subset of their functionality without class instrumentation
189      * as well, or operate with their VM agent specified on JVM startup.
190      * <p>In terms of Spring-provided weaving options, the most important ones are
191      * InstrumentationLoadTimeWeaver, which requires a Spring-specific (but very general)
192      * VM agent specified on JVM startup, and ReflectiveLoadTimeWeaver, which interacts
193      * with an underlying ClassLoader based on specific extended methods being available
194      * on it (for example, interacting with Spring's TomcatInstrumentableClassLoader).
195      * @see org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver
196      * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
197      * @see org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader
198      */

199     public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
200         this.loadTimeWeaver = loadTimeWeaver;
201     }
202
203     /**
204      * Return the Spring LoadTimeWeaver to use for class instrumentation according
205      * to the JPA class transformer contract.
206      */

207     public LoadTimeWeaver getLoadTimeWeaver() {
208         return loadTimeWeaver;
209     }
210
211     /**
212      * Set the PersistenceUnitPostProcessors to be applied to each
213      * PersistenceUnitInfo that has been parsed by this manager.
214      * <p>Such post-processors can, for example, register further entity
215      * classes and jar files, in addition to the metadata read in from
216      * <code>persistence.xml</code>.
217      */

218     public void setPersistenceUnitPostProcessors(PersistenceUnitPostProcessor[] postProcessors) {
219         this.persistenceUnitPostProcessors = postProcessors;
220     }
221
222     /**
223      * Return the PersistenceUnitPostProcessors to be applied to each
224      * PersistenceUnitInfo that has been parsed by this manager.
225      */

226     public PersistenceUnitPostProcessor[] getPersistenceUnitPostProcessors() {
227         return persistenceUnitPostProcessors;
228     }
229
230     public void setResourceLoader(ResourceLoader resourceLoader) {
231         this.resourcePatternResolver = (resourceLoader != null ?
232                 ResourcePatternUtils.getResourcePatternResolver(resourceLoader) :
233                 new PathMatchingResourcePatternResolver());
234     }
235
236
237     public void afterPropertiesSet() {
238         preparePersistenceUnitInfos();
239     }
240
241     /**
242      * Prepare the PersistenceUnitInfos according to the configuration
243      * of this manager: scanning for <code>persistence.xml</code> files,
244      * parsing all matching files, configurating and post-processing them.
245      * <p>PersistenceUnitInfos cannot be obtained before this preparation
246      * method has been invoked.
247      * @see #obtainDefaultPersistenceUnitInfo()
248      * @see #obtainPersistenceUnitInfo(String)
249      */

250     public void preparePersistenceUnitInfos() {
251         this.persistenceUnitInfoNames.clear();
252         this.persistenceUnitInfos.clear();
253         SpringPersistenceUnitInfo[] puis = readPersistenceUnitInfos();
254         for (int i = 0; i < puis.length; i++) {
255             SpringPersistenceUnitInfo pui = puis[i];
256             if (pui.getPersistenceUnitRootUrl() == null) {
257                 pui.setPersistenceUnitRootUrl(determineDefaultPersistenceUnitRootUrl());
258             }
259             if (pui.getNonJtaDataSource() == null) {
260                 pui.setNonJtaDataSource(this.defaultDataSource);
261             }
262             pui.setLoadTimeWeaver(this.loadTimeWeaver);
263             postProcessPersistenceUnitInfo(pui);
264             String JavaDoc name = pui.getPersistenceUnitName();
265             this.persistenceUnitInfoNames.add(name);
266             this.persistenceUnitInfos.put(name, pui);
267         }
268     }
269
270     /**
271      * Read all persistence unit infos from <code>persistence.xml</code>,
272      * as defined in the JPA specification.
273      */

274     private SpringPersistenceUnitInfo[] readPersistenceUnitInfos() {
275         PersistenceUnitReader reader = new PersistenceUnitReader(this.resourcePatternResolver, this.dataSourceLookup);
276         return reader.readPersistenceUnitInfos(this.persistenceXmlLocations);
277     }
278
279     /**
280      * Try to determine the persistence unit root URL based on the given
281      * "defaultPersistenceUnitRootLocation".
282      * @return the persistence unit root URL to pass to the JPA PersistenceProvider
283      * @see #setDefaultPersistenceUnitRootLocation
284      */

285     private URL JavaDoc determineDefaultPersistenceUnitRootUrl() {
286         if (this.defaultPersistenceUnitRootLocation == null) {
287             return null;
288         }
289         try {
290             Resource res = this.resourcePatternResolver.getResource(this.defaultPersistenceUnitRootLocation);
291             return res.getURL();
292         }
293         catch (IOException JavaDoc ex) {
294             throw new PersistenceException("Unable to resolve persistence unit root URL", ex);
295         }
296     }
297
298     /**
299      * Hook method allowing subclasses to customize each PersistenceUnitInfo.
300      * <p>Default implementation delegates to all registered PersistenceUnitPostProcessors.
301      * It is usually preferable to register further entity classes, jar files etc there
302      * rather than in a subclass of this manager, to be able to reuse the post-processors.
303      * @param pui the chosen PersistenceUnitInfo, as read from <code>persistence.xml</code>.
304      * Passed in as MutablePersistenceUnitInfo.
305      * @see #setPersistenceUnitPostProcessors
306      */

307     protected void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
308         PersistenceUnitPostProcessor[] postProcessors = getPersistenceUnitPostProcessors();
309         if (postProcessors != null) {
310             for (int i = 0; i < postProcessors.length; i++) {
311                 postProcessors[i].postProcessPersistenceUnitInfo(pui);
312             }
313         }
314     }
315
316
317     public PersistenceUnitInfo obtainDefaultPersistenceUnitInfo() {
318         if (this.persistenceUnitInfoNames.isEmpty()) {
319             throw new IllegalStateException JavaDoc("No persistence units parsed from " +
320                     ObjectUtils.nullSafeToString(this.persistenceXmlLocations));
321         }
322         if (this.persistenceUnitInfos.isEmpty()) {
323             throw new IllegalStateException JavaDoc("All persistence units from " +
324                     ObjectUtils.nullSafeToString(this.persistenceXmlLocations) + " already obtained");
325         }
326         if (this.persistenceUnitInfos.size() > 1) {
327             throw new IllegalStateException JavaDoc("No single default persistence unit defined in " +
328                     ObjectUtils.nullSafeToString(this.persistenceXmlLocations));
329         }
330         return this.persistenceUnitInfos.values().iterator().next();
331     }
332
333     public PersistenceUnitInfo obtainPersistenceUnitInfo(String JavaDoc persistenceUnitName) {
334         PersistenceUnitInfo pui = this.persistenceUnitInfos.remove(persistenceUnitName);
335         if (pui == null) {
336             if (!this.persistenceUnitInfoNames.contains(persistenceUnitName)) {
337                 throw new IllegalArgumentException JavaDoc(
338                         "No persistence unit with name '" + persistenceUnitName + "' found");
339             }
340             else {
341                 throw new IllegalStateException JavaDoc(
342                         "Persistence unit with name '" + persistenceUnitName + "' already obtained");
343             }
344         }
345         return pui;
346     }
347
348 }
349
Popular Tags