1
17 package net.bull.javamelody;
18
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.Method;
21 import java.security.AccessController;
22 import java.security.PrivilegedAction;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.persistence.EntityManagerFactory;
29 import javax.persistence.spi.LoadState;
30 import javax.persistence.spi.PersistenceProvider;
31 import javax.persistence.spi.PersistenceProviderResolver;
32 import javax.persistence.spi.PersistenceProviderResolverHolder;
33 import javax.persistence.spi.PersistenceUnitInfo;
34 import javax.persistence.spi.ProviderUtil;
35
36 import net.bull.javamelody.internal.common.LOG;
37 import net.bull.javamelody.internal.common.Parameters;
38 import net.bull.javamelody.internal.model.Counter;
39
40
44 public class JpaPersistence implements PersistenceProvider {
45 private static final Counter JPA_COUNTER = MonitoringProxy.getJpaCounter();
46 private static final boolean COUNTER_HIDDEN = Parameters.isCounterHidden(JPA_COUNTER.getName());
47
48
53 private static final String JPA_PERSISTENCE_PROVIDER = "javax.persistence.provider";
54 private static final String OWN_PACKAGE = JpaPersistence.class.getName().substring(0,
55 JpaPersistence.class.getName().lastIndexOf('.'));
56 private static final String DELEGATE_PROVIDER_KEY = OWN_PACKAGE + ".jpa.provider";
57
58 private static final String[] PROVIDERS = {
59 "org.apache.openjpa.persistence.PersistenceProviderImpl",
60 "org.hibernate.jpa.HibernatePersistenceProvider",
61 "org.hibernate.ejb.HibernatePersistence",
62 "org.eclipse.persistence.jpa.PersistenceProvider",
63 "oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider",
64 "oracle.toplink.essentials.PersistenceProvider",
65 "me.prettyprint.hom.CassandraPersistenceProvider",
66 "org.datanucleus.jpa.PersistenceProviderImpl",
67 "com.orientechnologies.orient.core.db.object.jpa.OJPAPersistenceProvider",
68 "com.orientechnologies.orient.object.jpa.OJPAPersistenceProvider",
69 "com.spaceprogram.simplejpa.PersistenceProviderImpl", };
70
71 private static final ProviderUtil DUMMY_PROVIDER_UTIL = new ProviderUtil() {
72 @Override
73 public LoadState isLoadedWithoutReference(Object entity, String attributeName) {
74 return LoadState.UNKNOWN;
75 }
76
77 @Override
78 public LoadState isLoadedWithReference(Object entity, String attributeName) {
79 return LoadState.UNKNOWN;
80 }
81
82 @Override
83 public LoadState isLoaded(Object entity) {
84 return LoadState.UNKNOWN;
85 }
86 };
87
88 private volatile PersistenceProvider delegate;
89
90 private static class JavaMelodyPersistenceProviderResolver
91 implements PersistenceProviderResolver {
92 private final PersistenceProviderResolver delegate;
93
94 JavaMelodyPersistenceProviderResolver(PersistenceProviderResolver delegate) {
95 super();
96 this.delegate = delegate;
97 }
98
99 @Override
100 public List<PersistenceProvider> getPersistenceProviders() {
101
102
103
104 final List<PersistenceProvider> providers = delegate.getPersistenceProviders();
105 final List<PersistenceProvider> result = new ArrayList<>();
106 for (final PersistenceProvider provider : providers) {
107 if (provider instanceof JpaPersistence) {
108 result.add(0, provider);
109 } else {
110 result.add(provider);
111 }
112 }
113 return result;
114 }
115
116 @Override
117 public void clearCachedProviders() {
118 delegate.clearCachedProviders();
119 }
120 }
121
122
126 public static void initPersistenceProviderResolver() {
127 try {
128 PersistenceProviderResolver resolver = PersistenceProviderResolverHolder
129 .getPersistenceProviderResolver();
130 if (!(resolver instanceof JavaMelodyPersistenceProviderResolver)) {
131 resolver = new JavaMelodyPersistenceProviderResolver(resolver);
132 PersistenceProviderResolverHolder.setPersistenceProviderResolver(resolver);
133 LOG.debug("JPA persistence provider resolver initialized");
134 }
135 } catch (final Throwable t) {
136 LOG.info("initialization of jpa persistence provider resolver failed, skipping");
137 }
138 }
139
140
141
142
143 private void initJpaCounter() {
144
145
146 JPA_COUNTER.setDisplayed(!COUNTER_HIDDEN);
147
148
149 JPA_COUNTER.setUsed(true);
150 LOG.debug("jpa persistence initialized");
151 }
152
153
154 @SuppressWarnings({ "rawtypes", "unchecked" })
155 @Override
156 public EntityManagerFactory createEntityManagerFactory(final String unit, final Map map) {
157 initJpaCounter();
158 final PersistenceProvider persistenceProvider = findDelegate(map);
159 final ClassLoader tccl = tccl();
160
161 final ClassLoader hack = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
162
163 @Override
164 public ClassLoader run() {
165 return new JpaOverridePersistenceXmlClassLoader(tccl,
166 persistenceProvider.getClass().getName());
167 }
168 });
169
170 Thread.currentThread().setContextClassLoader(hack);
171 try {
172 final Map overridenMap = new HashMap();
173 if (map != null) {
174 overridenMap.putAll(map);
175 }
176
177
178 overridenMap.put(JPA_PERSISTENCE_PROVIDER, persistenceProvider.getClass().getName());
179 final EntityManagerFactory entityManagerFactory = persistenceProvider
180 .createEntityManagerFactory(unit, overridenMap);
181 if (entityManagerFactory == null) {
182 return null;
183 }
184 return JpaWrapper.createEntityManagerFactoryProxy(entityManagerFactory);
185 } finally {
186 Thread.currentThread().setContextClassLoader(tccl);
187 }
188 }
189
190
191 @SuppressWarnings({ "rawtypes", "unchecked" })
192 @Override
193 public EntityManagerFactory createContainerEntityManagerFactory(final PersistenceUnitInfo info,
194 final Map map) {
195 initJpaCounter();
196 final PersistenceProvider persistenceProvider = findDelegate(map);
197
198
199 final PersistenceUnitInfo proxiedInfo = createPersistentUnitInfoProxy(info,
200 persistenceProvider);
201 final Map overridenMap = new HashMap();
202 if (map != null) {
203 overridenMap.putAll(map);
204 }
205
206
207 overridenMap.put(JPA_PERSISTENCE_PROVIDER, persistenceProvider.getClass().getName());
208 final EntityManagerFactory entityManagerFactory = persistenceProvider
209 .createContainerEntityManagerFactory(proxiedInfo, overridenMap);
210 if (entityManagerFactory == null) {
211 return null;
212 }
213 return JpaWrapper.createEntityManagerFactoryProxy(entityManagerFactory);
214 }
215
216 private PersistenceUnitInfo createPersistentUnitInfoProxy(final PersistenceUnitInfo info,
217 final PersistenceProvider persistenceProvider) {
218 final InvocationHandler invocationHandler = new ProviderAwareHandler(
219 persistenceProvider.getClass().getName(), info);
220 return JdbcWrapper.createProxy(info, invocationHandler);
221 }
222
223
224 @Override
225 public ProviderUtil getProviderUtil() {
226 if (delegate == null) {
227
228
229
230
231
232 return DUMMY_PROVIDER_UTIL;
233 }
234 return delegate.getProviderUtil();
235 }
236
237 private PersistenceProvider findDelegate(final Map<?, ?> map) {
238 if (map == null) {
239 return loadOrGuessDelegate(null);
240 }
241 return loadOrGuessDelegate(String.class.cast(map.get(DELEGATE_PROVIDER_KEY)));
242 }
243
244 private PersistenceProvider loadOrGuessDelegate(final String name) {
245 if (delegate == null) {
246 synchronized (this) {
247 if (delegate == null) {
248 if (name == null) {
249 guessDelegate();
250 } else {
251 try {
252 delegate = newPersistence(name);
253 } catch (final Exception e) {
254 throw new IllegalStateException(new ClassNotFoundException(
255 "Can't instantiate '" + name + "'", e));
256 }
257 }
258 }
259 }
260 }
261 if (name != null && !delegate.getClass().getName().equals(name)) {
262 try {
263 return newPersistence(name);
264 } catch (final Exception e) {
265 throw new IllegalStateException(
266 new ClassNotFoundException("Can't instantiate '" + name + "'", e));
267 }
268 }
269 return delegate;
270 }
271
272 private void guessDelegate() {
273
274
275 final List<PersistenceProvider> persistenceProviders = PersistenceProviderResolverHolder
276 .getPersistenceProviderResolver().getPersistenceProviders();
277 for (final PersistenceProvider persistenceProvider : persistenceProviders) {
278 if (!getClass().isInstance(persistenceProvider)) {
279 delegate = persistenceProvider;
280 break;
281 }
282 }
283 if (delegate == null) {
284 for (final String provider : PROVIDERS) {
285 try {
286 delegate = newPersistence(provider);
287 break;
288 } catch (final Throwable th2) {
289 continue;
290 }
291 }
292 if (delegate == null) {
293 throw new IllegalStateException(
294 new ClassNotFoundException("Can't find a delegate"));
295 }
296 }
297 }
298
299 private static ClassLoader tccl() {
300 return Thread.currentThread().getContextClassLoader();
301 }
302
303 private static PersistenceProvider newPersistence(final String name) throws Exception {
304 return PersistenceProvider.class.cast(tccl().loadClass(name).newInstance());
305 }
306
307 private static class ProviderAwareHandler implements InvocationHandler {
308 private final String provider;
309 private final PersistenceUnitInfo info;
310
311 ProviderAwareHandler(final String provider, final PersistenceUnitInfo info) {
312 super();
313 this.provider = provider;
314 this.info = info;
315 }
316
317
318 @Override
319 public Object invoke(final Object proxy, final Method method, final Object[] args)
320 throws Throwable {
321 if ("getPersistenceProviderClassName".equals(method.getName())) {
322 return provider;
323 }
324 return method.invoke(info, args);
325 }
326 }
327
328
329 @SuppressWarnings("rawtypes")
330 @Override
331 public void generateSchema(final PersistenceUnitInfo info, final Map map) {
332 final PersistenceProvider persistenceProvider = findDelegate(map);
333 persistenceProvider.generateSchema(info, map);
334 }
335
336
337 @SuppressWarnings("rawtypes")
338 @Override
339 public boolean generateSchema(final String persistenceUnitName, final Map map) {
340 final PersistenceProvider persistenceProvider = findDelegate(map);
341 return persistenceProvider.generateSchema(persistenceUnitName, map);
342 }
343 }
344