View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit.internal.injection.full;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import java.io.IOException;
11  import java.io.InputStream;
12  import java.lang.annotation.Annotation;
13  
14  import javax.persistence.EntityManager;
15  import javax.persistence.EntityManagerFactory;
16  import javax.persistence.Persistence;
17  import javax.persistence.PersistenceContext;
18  import javax.persistence.PersistenceUnit;
19  import javax.xml.parsers.ParserConfigurationException;
20  import javax.xml.parsers.SAXParser;
21  import javax.xml.parsers.SAXParserFactory;
22  
23  import mockit.internal.injection.InjectionPoint;
24  import mockit.internal.injection.InjectionProvider;
25  import mockit.internal.injection.InjectionState;
26  
27  import org.xml.sax.Attributes;
28  import org.xml.sax.SAXException;
29  import org.xml.sax.helpers.DefaultHandler;
30  
31  /**
32   * Detects and resolves dependencies belonging to the <code>javax.persistence</code> API, namely
33   * <code>EntityManagerFactory</code> and <code>EntityManager</code>.
34   */
35  final class JPADependencies {
36      static boolean isApplicable(@NonNull Class<?> dependencyType) {
37          return dependencyType == EntityManager.class || dependencyType == EntityManagerFactory.class;
38      }
39  
40      @NonNull
41      private final InjectionState injectionState;
42      @Nullable
43      private String defaultPersistenceUnitName;
44  
45      JPADependencies(@NonNull InjectionState injectionState) {
46          this.injectionState = injectionState;
47      }
48  
49      @Nullable
50      InjectionPoint getInjectionPointIfAvailable(@NonNull Annotation jpaAnnotation) {
51          Class<? extends Annotation> annotationType = jpaAnnotation.annotationType();
52          Class<?> jpaClass;
53          String unitName;
54  
55          if (annotationType == PersistenceUnit.class) {
56              jpaClass = EntityManagerFactory.class;
57              unitName = ((PersistenceUnit) jpaAnnotation).unitName();
58          } else if (annotationType == PersistenceContext.class) {
59              jpaClass = EntityManager.class;
60              unitName = ((PersistenceContext) jpaAnnotation).unitName();
61          } else {
62              return null;
63          }
64  
65          if (unitName.isEmpty()) {
66              unitName = discoverNameOfDefaultPersistenceUnit();
67          }
68  
69          return new InjectionPoint(jpaClass, unitName, true);
70      }
71  
72      @NonNull
73      private String discoverNameOfDefaultPersistenceUnit() {
74          if (defaultPersistenceUnitName != null) {
75              return defaultPersistenceUnitName;
76          }
77  
78          defaultPersistenceUnitName = "<unknown>";
79          InputStream xmlFile = getClass().getResourceAsStream("/META-INF/persistence.xml");
80  
81          if (xmlFile != null) {
82              try {
83                  SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
84                  parser.parse(xmlFile, new DefaultHandler() {
85                      @Override
86                      public void startElement(String uri, String localName, String qName, Attributes attributes) {
87                          if ("persistence-unit".equals(qName)) {
88                              defaultPersistenceUnitName = attributes.getValue("name");
89                          }
90                      }
91                  });
92                  xmlFile.close();
93              } catch (ParserConfigurationException | SAXException | IOException ignore) {
94              }
95          }
96  
97          return defaultPersistenceUnitName;
98      }
99  
100     @Nullable
101     Object createAndRegisterDependency(@NonNull Class<?> dependencyType, @NonNull InjectionPoint dependencyKey,
102             @Nullable InjectionProvider injectionProvider) {
103         if (injectionProvider != null) {
104             if (dependencyType == EntityManagerFactory.class
105                     && injectionProvider.hasAnnotation(PersistenceUnit.class)) {
106                 InjectionPoint injectionPoint = createFactoryInjectionPoint(dependencyKey);
107                 return createAndRegisterEntityManagerFactory(injectionPoint);
108             }
109 
110             if (dependencyType == EntityManager.class && injectionProvider.hasAnnotation(PersistenceContext.class)) {
111                 return createAndRegisterEntityManager(dependencyKey);
112             }
113         }
114 
115         return null;
116     }
117 
118     @NonNull
119     private InjectionPoint createFactoryInjectionPoint(@NonNull InjectionPoint injectionPoint) {
120         String persistenceUnitName = getNameOfPersistentUnit(injectionPoint.name);
121         return new InjectionPoint(EntityManagerFactory.class, persistenceUnitName, injectionPoint.qualified);
122     }
123 
124     @NonNull
125     private String getNameOfPersistentUnit(@Nullable String injectionPointName) {
126         return injectionPointName != null && !injectionPointName.isEmpty() ? injectionPointName
127                 : discoverNameOfDefaultPersistenceUnit();
128     }
129 
130     @NonNull
131     private static EntityManagerFactory createAndRegisterEntityManagerFactory(@NonNull InjectionPoint injectionPoint) {
132         String persistenceUnitName = injectionPoint.name;
133         EntityManagerFactory emFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
134         InjectionState.saveGlobalDependency(injectionPoint, emFactory);
135         return emFactory;
136     }
137 
138     @NonNull
139     private EntityManager createAndRegisterEntityManager(@NonNull InjectionPoint injectionPoint) {
140         InjectionPoint emFactoryKey = createFactoryInjectionPoint(injectionPoint);
141         EntityManagerFactory emFactory = InjectionState.getGlobalDependency(emFactoryKey);
142 
143         if (emFactory == null) {
144             emFactory = createAndRegisterEntityManagerFactory(emFactoryKey);
145         }
146 
147         EntityManager entityManager = emFactory.createEntityManager();
148         injectionState.saveInstantiatedDependency(injectionPoint, entityManager);
149         return entityManager;
150     }
151 }