1 /*
2  * Copyright 2002-2011 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;
18 
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Properties;
22 import javax.persistence.EntityManager;
23 import javax.persistence.EntityManagerFactory;
24 
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 
28 import org.springframework.beans.BeansException;
29 import org.springframework.beans.factory.BeanFactory;
30 import org.springframework.beans.factory.BeanFactoryAware;
31 import org.springframework.beans.factory.ListableBeanFactory;
32 import org.springframework.util.Assert;
33 import org.springframework.util.CollectionUtils;
34 
35 /**
36  * Base class for any class that needs to access an EntityManagerFactory,
37  * usually in order to obtain an EntityManager. Defines common properties.
38  *
39  * <p>Not intended to be used directly. See {@link JpaAccessor}.
40  *
41  * @author Juergen Hoeller
42  * @since 2.0
43  * @see JpaAccessor
44  * @see EntityManagerFactoryUtils
45  */
46 public abstract class EntityManagerFactoryAccessor implements BeanFactoryAware {
47 
48 	/** Logger available to subclasses */
49 	protected final Log logger = LogFactory.getLog(getClass());
50 
51 	private EntityManagerFactory entityManagerFactory;
52 
53 	private String persistenceUnitName;
54 
55 	private final Map<String, Object> jpaPropertyMap = new HashMap<String, Object>();
56 
57 
58 	/**
59 	 * Set the JPA EntityManagerFactory that should be used to create
60 	 * EntityManagers.
61 	 * @see javax.persistence.EntityManagerFactory#createEntityManager()
62 	 * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
63 	 */
setEntityManagerFactory(EntityManagerFactory emf)64 	public void setEntityManagerFactory(EntityManagerFactory emf) {
65 		this.entityManagerFactory = emf;
66 	}
67 
68 	/**
69 	 * Return the JPA EntityManagerFactory that should be used to create
70 	 * EntityManagers.
71 	 */
getEntityManagerFactory()72 	public EntityManagerFactory getEntityManagerFactory() {
73 		return this.entityManagerFactory;
74 	}
75 
76 	/**
77 	 * Set the name of the persistence unit to access the EntityManagerFactory for.
78 	 * <p>This is an alternative to specifying the EntityManagerFactory by direct reference,
79 	 * resolving it by its persistence unit name instead. If no EntityManagerFactory and
80 	 * no persistence unit name have been specified, a default EntityManagerFactory will
81 	 * be retrieved through finding a single unique bean of type EntityManagerFactory.
82 	 * @see #setEntityManagerFactory
83 	 */
setPersistenceUnitName(String persistenceUnitName)84 	public void setPersistenceUnitName(String persistenceUnitName) {
85 		this.persistenceUnitName = persistenceUnitName;
86 	}
87 
88 	/**
89 	 * Return the name of the persistence unit to access the EntityManagerFactory for, if any.
90 	 */
getPersistenceUnitName()91 	public String getPersistenceUnitName() {
92 		return this.persistenceUnitName;
93 	}
94 
95 	/**
96 	 * Specify JPA properties, to be passed into
97 	 * <code>EntityManagerFactory.createEntityManager(Map)</code> (if any).
98 	 * <p>Can be populated with a String "value" (parsed via PropertiesEditor)
99 	 * or a "props" element in XML bean definitions.
100 	 * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
101 	 */
setJpaProperties(Properties jpaProperties)102 	public void setJpaProperties(Properties jpaProperties) {
103 		CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.jpaPropertyMap);
104 	}
105 
106 	/**
107 	 * Specify JPA properties as a Map, to be passed into
108 	 * <code>EntityManagerFactory.createEntityManager(Map)</code> (if any).
109 	 * <p>Can be populated with a "map" or "props" element in XML bean definitions.
110 	 * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
111 	 */
setJpaPropertyMap(Map<String, Object> jpaProperties)112 	public void setJpaPropertyMap(Map<String, Object> jpaProperties) {
113 		if (jpaProperties != null) {
114 			this.jpaPropertyMap.putAll(jpaProperties);
115 		}
116 	}
117 
118 	/**
119 	 * Allow Map access to the JPA properties to be passed to the persistence
120 	 * provider, with the option to add or override specific entries.
121 	 * <p>Useful for specifying entries directly, for example via "jpaPropertyMap[myKey]".
122 	 */
getJpaPropertyMap()123 	public Map<String, Object> getJpaPropertyMap() {
124 		return this.jpaPropertyMap;
125 	}
126 
127 	/**
128 	 * Retrieves an EntityManagerFactory by persistence unit name, if none set explicitly.
129 	 * Falls back to a default EntityManagerFactory bean if no persistence unit specified.
130 	 * @see #setPersistenceUnitName
131 	 */
setBeanFactory(BeanFactory beanFactory)132 	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
133 		if (getEntityManagerFactory() == null) {
134 			if (!(beanFactory instanceof ListableBeanFactory)) {
135 				throw new IllegalStateException("Cannot retrieve EntityManagerFactory by persistence unit name " +
136 						"in a non-listable BeanFactory: " + beanFactory);
137 			}
138 			ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
139 			setEntityManagerFactory(EntityManagerFactoryUtils.findEntityManagerFactory(lbf, getPersistenceUnitName()));
140 		}
141 	}
142 
143 
144 	/**
145 	 * Obtain a new EntityManager from this accessor's EntityManagerFactory.
146 	 * <p>Can be overridden in subclasses to create specific EntityManager variants.
147 	 * @return a new EntityManager
148 	 * @throws IllegalStateException if this accessor is not configured with an EntityManagerFactory
149 	 * @see javax.persistence.EntityManagerFactory#createEntityManager()
150 	 * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
151 	 */
createEntityManager()152 	protected EntityManager createEntityManager() throws IllegalStateException {
153 		EntityManagerFactory emf = getEntityManagerFactory();
154 		Assert.state(emf != null, "No EntityManagerFactory specified");
155 		Map<String, Object> properties = getJpaPropertyMap();
156 		return (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager());
157 	}
158 
159 	/**
160 	 * Obtain the transactional EntityManager for this accessor's EntityManagerFactory, if any.
161 	 * @return the transactional EntityManager, or <code>null</code> if none
162 	 * @throws IllegalStateException if this accessor is not configured with an EntityManagerFactory
163 	 * @see EntityManagerFactoryUtils#getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
164 	 * @see EntityManagerFactoryUtils#getTransactionalEntityManager(javax.persistence.EntityManagerFactory, java.util.Map)
165 	 */
getTransactionalEntityManager()166 	protected EntityManager getTransactionalEntityManager() throws IllegalStateException{
167 		EntityManagerFactory emf = getEntityManagerFactory();
168 		Assert.state(emf != null, "No EntityManagerFactory specified");
169 		return EntityManagerFactoryUtils.getTransactionalEntityManager(emf, getJpaPropertyMap());
170 	}
171 
172 }
173