001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.orm.jpa.support;
018:
019: import java.beans.PropertyDescriptor;
020: import java.lang.reflect.AccessibleObject;
021: import java.lang.reflect.AnnotatedElement;
022: import java.lang.reflect.Field;
023: import java.lang.reflect.InvocationTargetException;
024: import java.lang.reflect.Member;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027: import java.util.HashMap;
028: import java.util.LinkedList;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Properties;
032:
033: import javax.naming.NamingException;
034: import javax.persistence.EntityManager;
035: import javax.persistence.EntityManagerFactory;
036: import javax.persistence.PersistenceContext;
037: import javax.persistence.PersistenceContextType;
038: import javax.persistence.PersistenceProperty;
039: import javax.persistence.PersistenceUnit;
040:
041: import org.springframework.beans.BeansException;
042: import org.springframework.beans.PropertyValues;
043: import org.springframework.beans.factory.BeanFactory;
044: import org.springframework.beans.factory.BeanFactoryAware;
045: import org.springframework.beans.factory.BeanFactoryUtils;
046: import org.springframework.beans.factory.ListableBeanFactory;
047: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
048: import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
049: import org.springframework.jndi.JndiLocatorSupport;
050: import org.springframework.orm.jpa.EntityManagerFactoryInfo;
051: import org.springframework.orm.jpa.EntityManagerFactoryUtils;
052: import org.springframework.orm.jpa.ExtendedEntityManagerCreator;
053: import org.springframework.orm.jpa.SharedEntityManagerCreator;
054: import org.springframework.util.ObjectUtils;
055: import org.springframework.util.ReflectionUtils;
056:
057: /**
058: * BeanPostProcessor that processes {@link javax.persistence.PersistenceUnit}
059: * and {@link javax.persistence.PersistenceContext} annotations, for injection of
060: * the corresponding JPA resources {@link javax.persistence.EntityManagerFactory}
061: * and {@link javax.persistence.EntityManager}. Any such annotated fields or methods
062: * in any Spring-managed object will automatically be injected.
063: *
064: * <p>This post-processor will inject sub-interfaces of <code>EntityManagerFactory</code>
065: * and <code>EntityManager</code> if the annotated fields or methods are declared as such.
066: * The actual type will be verified early, with the exception of a shared ("transactional")
067: * <code>EntityManager</code> reference, where type mismatches might be detected as late
068: * as on the first actual invocation.
069: *
070: * <p>Note: In the present implementation, PersistenceAnnotationBeanPostProcessor
071: * only supports <code>@PersistenceUnit</code> and <code>@PersistenceContext</code>
072: * with the "unitName" attribute, or no attribute at all (for the default unit).
073: * If those annotations are present with the "name" attribute at the class level,
074: * they will simply be ignored, since those only serve as deployment hint
075: * (as per the Java EE 5 specification).
076: *
077: * <p>This post-processor can either obtain EntityManagerFactory beans defined
078: * in the Spring application context (the default), or obtain EntityManagerFactory
079: * references from JNDI ("persistence unit references"). In the bean case,
080: * the persistence unit name will be matched against the actual deployed unit,
081: * with the bean name used as fallback unit name if no deployed name found.
082: * Typically, Spring's {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
083: * will be used for setting up such EntityManagerFactory beans. The post-processor
084: * definition will then look as simple as this:
085: *
086: * <pre class="code">
087: * <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/></pre>
088: *
089: * In the JNDI case, specify the corresponding JNDI names in this post-processor's
090: * {@link #setPersistenceUnits "persistenceUnits" map}, typically with matching
091: * <code>persistence-unit-ref</code> entries in the Java EE deployment descriptor.
092: * By default, those names are considered as resource references (according to the
093: * Java EE resource-ref convention), located underneath the "java:comp/env/" namespace.
094: * For example:
095: *
096: * <pre class="code">
097: * <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
098: * <property name="persistenceUnits">
099: * <map/gt;
100: * <entry key="unit1" value="persistence/unit1"/>
101: * <entry key="unit2" value="persistence/unit2"/>
102: * </map/gt;
103: * </property>
104: * </bean></pre>
105: *
106: * In this case, the specified persistence units will always be resolved in JNDI
107: * rather than as Spring-defined beans. The entire persistence unit deployment,
108: * including the weaving of persistent classes, is then up to the Java EE server.
109: * Persistence contexts (i.e. EntityManager references) will be built based on
110: * those server-provided EntityManagerFactory references, using Spring's own
111: * transaction synchronization facilities for transactional EntityManager handling
112: * (typically with Spring's <code>@Transactional</code> annotation for demarcation
113: * and {@link org.springframework.transaction.jta.JtaTransactionManager} as backend).
114: *
115: * <p>If you prefer the Java EE server's own EntityManager handling, specify entries
116: * in this post-processor's {@link #setPersistenceContexts "persistenceContexts" map}
117: * (or {@link #setExtendedPersistenceContexts "extendedPersistenceContexts" map},
118: * typically with matching <code>persistence-context-ref</code> entries in the
119: * Java EE deployment descriptor. For example:
120: *
121: * <pre class="code">
122: * <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
123: * <property name="persistenceContexts">
124: * <map/gt;
125: * <entry key="unit1" value="persistence/context1"/>
126: * <entry key="unit2" value="persistence/context2"/>
127: * </map/gt;
128: * </property>
129: * </bean></pre>
130: *
131: * If the application only obtains EntityManager references in the first place,
132: * this is all you need to specify. If you need EntityManagerFactory references
133: * as well, specify entries for both "persistenceUnits" and "persistenceContexts",
134: * pointing to matching JNDI locations.
135: *
136: * <p><b>NOTE: In general, do not inject EXTENDED EntityManagers into STATELESS beans,
137: * i.e. do not use <code>@PersistenceContext</code> with type <code>EXTENDED</code> in
138: * Spring beans defined with scope 'singleton' (Spring's default scope).</b>
139: * Extended EntityManagers are <i>not</i> thread-safe, hence they must not be used
140: * in concurrently accessed beans (which Spring-managed singletons usually are).
141: *
142: * @author Rod Johnson
143: * @author Juergen Hoeller
144: * @since 2.0
145: * @see javax.persistence.PersistenceUnit
146: * @see javax.persistence.PersistenceContext
147: */
148: public class PersistenceAnnotationBeanPostProcessor extends
149: JndiLocatorSupport implements
150: InstantiationAwareBeanPostProcessor, BeanFactoryAware {
151:
152: private Map<String, String> persistenceUnits;
153:
154: private Map<String, String> persistenceContexts;
155:
156: private Map<String, String> extendedPersistenceContexts;
157:
158: private String defaultPersistenceUnitName = "";
159:
160: private ListableBeanFactory beanFactory;
161:
162: private final Map<Class<?>, List<AnnotatedMember>> annotationMetadataCache = new HashMap<Class<?>, List<AnnotatedMember>>();
163:
164: public PersistenceAnnotationBeanPostProcessor() {
165: setResourceRef(true);
166: }
167:
168: /**
169: * Specify the persistence units for EntityManagerFactory lookups,
170: * as a Map from persistence unit name to persistence unit JNDI name
171: * (which needs to resolve to an EntityManagerFactory instance).
172: * <p>JNDI names specified here should refer to <code>persistence-unit-ref</code>
173: * entries in the Java EE deployment descriptor, matching the target persistence unit.
174: * <p>In case of no unit name specified in the annotation, the specified value
175: * for the {@link #setDefaultPersistenceUnitName default persistence unit}
176: * will be taken (by default, the value mapped to the empty String),
177: * or simply the single persistence unit if there is only one.
178: * <p>This is mainly intended for use in a Java EE 5 environment, with all
179: * lookup driven by the standard JPA annotations, and all EntityManagerFactory
180: * references obtained from JNDI. No separate EntityManagerFactory bean
181: * definitions are necessary in such a scenario.
182: * <p>If no corresponding "persistenceContexts"/"extendedPersistenceContexts"
183: * are specified, <code>@PersistenceContext</code> will be resolved to
184: * EntityManagers built on top of the EntityManagerFactory defined here.
185: * Note that those will be Spring-managed EntityManagers, which implement
186: * transaction synchronization based on Spring's facilities.
187: * If you prefer the Java EE 5 server's own EntityManager handling,
188: * specify corresponding "persistenceContexts"/"extendedPersistenceContexts".
189: */
190: public void setPersistenceUnits(Map<String, String> persistenceUnits) {
191: this .persistenceUnits = persistenceUnits;
192: }
193:
194: /**
195: * Specify the <i>transactional</i> persistence contexts for EntityManager lookups,
196: * as a Map from persistence unit name to persistence context JNDI name
197: * (which needs to resolve to an EntityManager instance).
198: * <p>JNDI names specified here should refer to <code>persistence-context-ref</code>
199: * entries in the Java EE deployment descriptors, matching the target persistence unit
200: * and being set up with persistence context type <code>Transaction</code>.
201: * <p>In case of no unit name specified in the annotation, the specified value
202: * for the {@link #setDefaultPersistenceUnitName default persistence unit}
203: * will be taken (by default, the value mapped to the empty String),
204: * or simply the single persistence unit if there is only one.
205: * <p>This is mainly intended for use in a Java EE 5 environment, with all
206: * lookup driven by the standard JPA annotations, and all EntityManager
207: * references obtained from JNDI. No separate EntityManagerFactory bean
208: * definitions are necessary in such a scenario, and all EntityManager
209: * handling is done by the Java EE 5 server itself.
210: */
211: public void setPersistenceContexts(
212: Map<String, String> persistenceContexts) {
213: this .persistenceContexts = persistenceContexts;
214: }
215:
216: /**
217: * Specify the <i>extended</i> persistence contexts for EntityManager lookups,
218: * as a Map from persistence unit name to persistence context JNDI name
219: * (which needs to resolve to an EntityManager instance).
220: * <p>JNDI names specified here should refer to <code>persistence-context-ref</code>
221: * entries in the Java EE deployment descriptors, matching the target persistence unit
222: * and being set up with persistence context type <code>Extended</code>.
223: * <p>In case of no unit name specified in the annotation, the specified value
224: * for the {@link #setDefaultPersistenceUnitName default persistence unit}
225: * will be taken (by default, the value mapped to the empty String),
226: * or simply the single persistence unit if there is only one.
227: * <p>This is mainly intended for use in a Java EE 5 environment, with all
228: * lookup driven by the standard JPA annotations, and all EntityManager
229: * references obtained from JNDI. No separate EntityManagerFactory bean
230: * definitions are necessary in such a scenario, and all EntityManager
231: * handling is done by the Java EE 5 server itself.
232: */
233: public void setExtendedPersistenceContexts(
234: Map<String, String> extendedPersistenceContexts) {
235: this .extendedPersistenceContexts = extendedPersistenceContexts;
236: }
237:
238: /**
239: * Specify the default persistence unit name, to be used in case
240: * of no unit name specified in an <code>@PersistenceUnit</code> /
241: * <code>@PersistenceContext</code> annotation.
242: * <p>This is mainly intended for lookups in the application context,
243: * indicating the target persistence unit name (typically matching
244: * the bean name), but also applies to lookups in the
245: * {@link #setPersistenceUnits "persistenceUnits"} /
246: * {@link #setPersistenceContexts "persistenceContexts"} /
247: * {@link #setExtendedPersistenceContexts "extendedPersistenceContexts"} map,
248: * avoiding the need for duplicated mappings for the empty String there.
249: * <p>Default is to check for a single EntityManagerFactory bean
250: * in the Spring application context, if any. If there are multiple
251: * such factories, either specify this default persistence unit name
252: * or explicitly refer to named persistence units in your annotations.
253: */
254: public void setDefaultPersistenceUnitName(String unitName) {
255: this .defaultPersistenceUnitName = (unitName != null ? unitName
256: : "");
257: }
258:
259: public void setBeanFactory(BeanFactory beanFactory) {
260: if (beanFactory instanceof ListableBeanFactory) {
261: this .beanFactory = (ListableBeanFactory) beanFactory;
262: }
263: }
264:
265: public Object postProcessBeforeInstantiation(Class beanClass,
266: String beanName) throws BeansException {
267: return null;
268: }
269:
270: public boolean postProcessAfterInstantiation(Object bean,
271: String beanName) throws BeansException {
272: List<AnnotatedMember> metadata = findAnnotationMetadata(bean
273: .getClass());
274: for (AnnotatedMember member : metadata) {
275: member.inject(bean);
276: }
277: return true;
278: }
279:
280: public PropertyValues postProcessPropertyValues(PropertyValues pvs,
281: PropertyDescriptor[] pds, Object bean, String beanName)
282: throws BeansException {
283:
284: return pvs;
285: }
286:
287: public Object postProcessBeforeInitialization(Object bean,
288: String beanName) throws BeansException {
289: return bean;
290: }
291:
292: public Object postProcessAfterInitialization(Object bean,
293: String beanName) throws BeansException {
294: return bean;
295: }
296:
297: private List<AnnotatedMember> findAnnotationMetadata(Class clazz) {
298: synchronized (this .annotationMetadataCache) {
299: List<AnnotatedMember> metadata = this .annotationMetadataCache
300: .get(clazz);
301: if (metadata == null) {
302: final List<AnnotatedMember> newMetadata = new LinkedList<AnnotatedMember>();
303: ReflectionUtils.doWithFields(clazz,
304: new ReflectionUtils.FieldCallback() {
305: public void doWith(Field field) {
306: addIfPresent(newMetadata, field);
307: }
308: });
309: ReflectionUtils.doWithMethods(clazz,
310: new ReflectionUtils.MethodCallback() {
311: public void doWith(Method method) {
312: addIfPresent(newMetadata, method);
313: }
314: });
315: metadata = newMetadata;
316: this .annotationMetadataCache.put(clazz, metadata);
317: }
318: return metadata;
319: }
320: }
321:
322: private void addIfPresent(List<AnnotatedMember> metadata,
323: Member member) {
324: AnnotatedElement ae = (AnnotatedElement) member;
325: PersistenceContext pc = ae
326: .getAnnotation(PersistenceContext.class);
327: PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class);
328: if (pc != null) {
329: if (pu != null) {
330: throw new IllegalStateException(
331: "Method may only be annotated with either @PersistenceContext or @PersistenceUnit, not both");
332: }
333: if (member instanceof Method
334: && ((Method) member).getParameterTypes().length != 1) {
335: throw new IllegalStateException(
336: "PersistenceContext annotation requires a single-arg method: "
337: + member);
338: }
339: Properties properties = null;
340: PersistenceProperty[] pps = pc.properties();
341: if (!ObjectUtils.isEmpty(pps)) {
342: properties = new Properties();
343: for (int i = 0; i < pps.length; i++) {
344: PersistenceProperty pp = pps[i];
345: properties.setProperty(pp.name(), pp.value());
346: }
347: }
348: metadata.add(new AnnotatedMember(member, pc.unitName(), pc
349: .type(), properties));
350: } else if (pu != null) {
351: if (member instanceof Method
352: && ((Method) member).getParameterTypes().length != 1) {
353: throw new IllegalStateException(
354: "PersistenceUnit annotation requires a single-arg method: "
355: + member);
356: }
357: metadata.add(new AnnotatedMember(member, pu.unitName()));
358: }
359: }
360:
361: /**
362: * Return a specified persistence unit for the given unit name,
363: * as defined through the "persistenceUnits" map.
364: * @param unitName the name of the persistence unit
365: * @return the corresponding EntityManagerFactory,
366: * or <code>null</code> if none found
367: * @see #setPersistenceUnits
368: */
369: protected EntityManagerFactory getPersistenceUnit(String unitName) {
370: if (this .persistenceUnits != null) {
371: String unitNameForLookup = (unitName != null ? unitName
372: : "");
373: if ("".equals(unitNameForLookup)) {
374: unitNameForLookup = this .defaultPersistenceUnitName;
375: }
376: String jndiName = this .persistenceUnits
377: .get(unitNameForLookup);
378: if (jndiName == null && "".equals(unitNameForLookup)
379: && this .persistenceUnits.size() == 1) {
380: jndiName = this .persistenceUnits.values().iterator()
381: .next();
382: }
383: if (jndiName != null) {
384: try {
385: return (EntityManagerFactory) lookup(jndiName,
386: EntityManagerFactory.class);
387: } catch (NamingException ex) {
388: throw new IllegalStateException(
389: "Could not obtain EntityManagerFactory ["
390: + jndiName + "] from JNDI", ex);
391: }
392: }
393: }
394: return null;
395: }
396:
397: /**
398: * Return a specified persistence context for the given unit name, as defined
399: * through the "persistenceContexts" (or "extendedPersistenceContexts") map.
400: * @param unitName the name of the persistence unit
401: * @param extended whether to obtain an extended persistence context
402: * @return the corresponding EntityManager, or <code>null</code> if none found
403: * @see #setPersistenceContexts
404: * @see #setExtendedPersistenceContexts
405: */
406: protected EntityManager getPersistenceContext(String unitName,
407: boolean extended) {
408: Map<String, String> contexts = (extended ? this .extendedPersistenceContexts
409: : this .persistenceContexts);
410: if (contexts != null) {
411: String unitNameForLookup = (unitName != null ? unitName
412: : "");
413: if ("".equals(unitNameForLookup)) {
414: unitNameForLookup = this .defaultPersistenceUnitName;
415: }
416: String jndiName = contexts.get(unitNameForLookup);
417: if (jndiName == null && "".equals(unitNameForLookup)
418: && contexts.size() == 1) {
419: jndiName = contexts.values().iterator().next();
420: }
421: if (jndiName != null) {
422: try {
423: return (EntityManager) lookup(jndiName,
424: EntityManager.class);
425: } catch (NamingException ex) {
426: throw new IllegalStateException(
427: "Could not obtain EntityManager ["
428: + jndiName + "] from JNDI", ex);
429: }
430: }
431: }
432: return null;
433: }
434:
435: /**
436: * Find an EntityManagerFactory with the given name in the current Spring
437: * application context, falling back to a single default EntityManagerFactory
438: * (if any) in case of no unit name specified.
439: * @param unitName the name of the persistence unit (may be <code>null</code> or empty)
440: * @return the EntityManagerFactory
441: * @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context
442: */
443: protected EntityManagerFactory findEntityManagerFactory(
444: String unitName) throws NoSuchBeanDefinitionException {
445: if (this .beanFactory == null) {
446: throw new IllegalStateException(
447: "ListableBeanFactory required for EntityManagerFactory lookup");
448: }
449: String unitNameForLookup = (unitName != null ? unitName : "");
450: if ("".equals(unitNameForLookup)) {
451: unitNameForLookup = this .defaultPersistenceUnitName;
452: }
453: if (!"".equals(unitNameForLookup)) {
454: return findNamedEntityManagerFactory(unitNameForLookup);
455: } else {
456: return findDefaultEntityManagerFactory();
457: }
458: }
459:
460: /**
461: * Find an EntityManagerFactory with the given name in the current
462: * Spring application context.
463: * @param unitName the name of the persistence unit (never empty)
464: * @return the EntityManagerFactory
465: * @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context
466: */
467: protected EntityManagerFactory findNamedEntityManagerFactory(
468: String unitName) throws NoSuchBeanDefinitionException {
469:
470: return EntityManagerFactoryUtils.findEntityManagerFactory(
471: this .beanFactory, unitName);
472: }
473:
474: /**
475: * Find a single default EntityManagerFactory in the Spring application context.
476: * @return the default EntityManagerFactory
477: * @throws NoSuchBeanDefinitionException if there is no single EntityManagerFactory in the context
478: */
479: protected EntityManagerFactory findDefaultEntityManagerFactory() {
480: return (EntityManagerFactory) BeanFactoryUtils
481: .beanOfTypeIncludingAncestors(this .beanFactory,
482: EntityManagerFactory.class);
483: }
484:
485: /**
486: * Class representing injection information about an annotated field
487: * or setter method.
488: */
489: private class AnnotatedMember {
490:
491: private final Member member;
492:
493: private final String unitName;
494:
495: private final PersistenceContextType type;
496:
497: private final Properties properties;
498:
499: public AnnotatedMember(Member member, String unitName) {
500: this (member, unitName, null, null);
501: }
502:
503: public AnnotatedMember(Member member, String unitName,
504: PersistenceContextType type, Properties properties) {
505: this .member = member;
506: this .unitName = unitName;
507: this .type = type;
508: this .properties = properties;
509:
510: // Validate member type
511: Class<?> memberType = getMemberType();
512: if (!(EntityManagerFactory.class
513: .isAssignableFrom(memberType) || EntityManager.class
514: .isAssignableFrom(memberType))) {
515: throw new IllegalArgumentException("Cannot inject "
516: + member + ": not a supported JPA type");
517: }
518: }
519:
520: public void inject(Object instance) {
521: Object value = resolve();
522: try {
523: if (!Modifier.isPublic(this .member.getModifiers())
524: || !Modifier.isPublic(this .member
525: .getDeclaringClass().getModifiers())) {
526: ((AccessibleObject) this .member)
527: .setAccessible(true);
528: }
529: if (this .member instanceof Field) {
530: ((Field) this .member).set(instance, value);
531: } else if (this .member instanceof Method) {
532: ((Method) this .member).invoke(instance, value);
533: } else {
534: throw new IllegalArgumentException(
535: "Cannot inject unknown AccessibleObject type "
536: + this .member);
537: }
538: } catch (IllegalAccessException ex) {
539: throw new IllegalArgumentException(
540: "Cannot inject member " + this .member, ex);
541: } catch (InvocationTargetException ex) {
542: // Method threw an exception
543: throw new IllegalArgumentException(
544: "Attempt to inject setter method "
545: + this .member
546: + " resulted in an exception", ex);
547: }
548: }
549:
550: /**
551: * Return the type of the member, whether it's a field or a method.
552: */
553: public Class<?> getMemberType() {
554: if (this .member instanceof Field) {
555: return ((Field) member).getType();
556: } else if (this .member instanceof Method) {
557: Method setter = (Method) this .member;
558: if (setter.getParameterTypes().length != 1) {
559: throw new IllegalArgumentException(
560: "Supposed setter [" + this .member
561: + "] must have 1 argument, not "
562: + setter.getParameterTypes().length);
563: }
564: return setter.getParameterTypes()[0];
565: } else {
566: throw new IllegalArgumentException(
567: "Unknown AccessibleObject type ["
568: + this .member.getClass()
569: + "]; can only inject setter methods and fields");
570: }
571: }
572:
573: /**
574: * Resolve the object against the application context.
575: */
576: private Object resolve() {
577: // Resolves to EntityManagerFactory or EntityManager.
578: if (EntityManagerFactory.class
579: .isAssignableFrom(getMemberType())) {
580: EntityManagerFactory emf = resolveEntityManagerFactory();
581: if (!getMemberType().isInstance(emf)) {
582: throw new IllegalArgumentException(
583: "Cannot inject [" + this .member
584: + "] with EntityManagerFactory ["
585: + emf + "]: type mismatch");
586: }
587: return emf;
588: } else {
589: // OK, so we need an EntityManager...
590: EntityManager em = (this .type == PersistenceContextType.EXTENDED ? resolveExtendedEntityManager()
591: : resolveEntityManager());
592: if (!getMemberType().isInstance(em)) {
593: throw new IllegalArgumentException(
594: "Cannot inject [" + this .member
595: + "] with EntityManager [" + em
596: + "]: type mismatch");
597: }
598: return em;
599: }
600: }
601:
602: private EntityManagerFactory resolveEntityManagerFactory() {
603: // Obtain EntityManagerFactory from JNDI?
604: EntityManagerFactory emf = getPersistenceUnit(this .unitName);
605: if (emf == null) {
606: // Need to search for EntityManagerFactory beans.
607: emf = findEntityManagerFactory(this .unitName);
608: }
609: return emf;
610: }
611:
612: private EntityManager resolveEntityManager() {
613: // Obtain EntityManager reference from JNDI?
614: EntityManager em = getPersistenceContext(this .unitName,
615: false);
616: if (em == null) {
617: // No pre-built EntityManager found -> build one based on factory.
618: // Obtain EntityManagerFactory from JNDI?
619: EntityManagerFactory emf = getPersistenceUnit(this .unitName);
620: if (emf == null) {
621: // Need to search for EntityManagerFactory beans.
622: emf = findEntityManagerFactory(this .unitName);
623: }
624: // Inject a shared transactional EntityManager proxy.
625: if (emf instanceof EntityManagerFactoryInfo
626: && !EntityManager.class
627: .equals(((EntityManagerFactoryInfo) emf)
628: .getEntityManagerInterface())) {
629: // Create EntityManager based on the info's vendor-specific type
630: // (which might be more specific than the field's type).
631: em = SharedEntityManagerCreator
632: .createSharedEntityManager(emf,
633: this .properties);
634: } else {
635: // Create EntityManager based on the field's type.
636: em = SharedEntityManagerCreator
637: .createSharedEntityManager(emf,
638: this .properties, getMemberType());
639: }
640: }
641: return em;
642: }
643:
644: private EntityManager resolveExtendedEntityManager() {
645: // Obtain EntityManager reference from JNDI?
646: EntityManager em = getPersistenceContext(this .unitName,
647: true);
648: if (em == null) {
649: // No pre-built EntityManager found -> build one based on factory.
650: // Obtain EntityManagerFactory from JNDI?
651: EntityManagerFactory emf = getPersistenceUnit(this .unitName);
652: if (emf == null) {
653: // Need to search for EntityManagerFactory beans.
654: emf = findEntityManagerFactory(this .unitName);
655: }
656: // Inject a container-managed extended EntityManager.
657: em = ExtendedEntityManagerCreator
658: .createContainerManagedEntityManager(emf,
659: this.properties);
660: }
661: return em;
662: }
663: }
664:
665: }
|