1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.rice.krad.data.jpa.eclipselink;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.eclipse.persistence.config.SessionCustomizer;
20  import org.eclipse.persistence.descriptors.ClassDescriptor;
21  import org.eclipse.persistence.exceptions.DescriptorException;
22  import org.eclipse.persistence.internal.databaseaccess.Accessor;
23  import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy;
24  import org.eclipse.persistence.internal.sessions.AbstractSession;
25  import org.eclipse.persistence.mappings.DatabaseMapping;
26  import org.eclipse.persistence.sequencing.Sequence;
27  import org.eclipse.persistence.sessions.DatabaseLogin;
28  import org.eclipse.persistence.sessions.JNDIConnector;
29  import org.eclipse.persistence.sessions.Session;
30  import org.kuali.rice.krad.data.jpa.DisableVersioning;
31  import org.kuali.rice.krad.data.jpa.Filter;
32  import org.kuali.rice.krad.data.jpa.FilterGenerator;
33  import org.kuali.rice.krad.data.jpa.FilterGenerators;
34  import org.kuali.rice.krad.data.jpa.PortableSequenceGenerator;
35  import org.kuali.rice.krad.data.jpa.RemoveMapping;
36  import org.kuali.rice.krad.data.jpa.RemoveMappings;
37  import org.kuali.rice.krad.data.platform.MaxValueIncrementerFactory;
38  import org.springframework.core.annotation.AnnotationUtils;
39  import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
40  
41  import javax.sql.DataSource;
42  import java.lang.reflect.Field;
43  import java.lang.reflect.Method;
44  import java.util.ArrayList;
45  import java.util.Arrays;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Vector;
49  import java.util.concurrent.ConcurrentHashMap;
50  import java.util.concurrent.ConcurrentMap;
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  public class KradEclipseLinkCustomizer implements SessionCustomizer {
66  
67      private static ConcurrentMap<String, List<Sequence>> sequenceMap = new ConcurrentHashMap<String, List<Sequence>>(8,
68              0.9f, 1);
69  
70      
71      private static ConcurrentMap<String, Boolean> modDescMap = new ConcurrentHashMap<String, Boolean>();
72  
73      private static ConcurrentMap<String, List<FilterGenerator>> queryCustomizerMap =
74              new ConcurrentHashMap<String, List<FilterGenerator>>();
75  
76      
77  
78  
79      @Override
80      public void customize(Session session) throws Exception {
81          String sessionName = session.getName();
82  
83          
84          List<Sequence> sequences = sequenceMap.get(sessionName);
85          if (sequences == null) {
86              sequences = sequenceMap.putIfAbsent(sessionName, loadSequences(session));
87              if (sequences == null) {
88                  sequences = sequenceMap.get(sessionName);
89              }
90          }
91  
92          loadQueryCustomizers(session);
93  
94          DatabaseLogin login = session.getLogin();
95          for (Sequence sequence : sequences) {
96              login.addSequence(sequence);
97          }
98  
99          handleDescriptorModifications(session);
100 
101     }
102 
103     
104 
105 
106 
107 
108     protected void loadQueryCustomizers(Session session) {
109         Map<Class, ClassDescriptor> descriptors = session.getDescriptors();
110         for (Class<?> entityClass : descriptors.keySet()) {
111             for (Field field : entityClass.getDeclaredFields()) {
112                 String queryCustEntry = entityClass.getName() + "_" + field.getName();
113                 buildQueryCustomizers(entityClass,field,queryCustEntry);
114 
115                 List<FilterGenerator> queryCustomizers = queryCustomizerMap.get(queryCustEntry);
116                 if (queryCustomizers != null && !queryCustomizers.isEmpty()) {
117                     Filter.customizeField(queryCustomizers, descriptors.get(entityClass), field.getName());
118                 }
119             }
120         }
121 
122     }
123 
124     
125 
126 
127 
128 
129 
130 
131     protected void buildQueryCustomizers(Class<?> entityClass,Field field, String key){
132         FilterGenerators customizers = field.getAnnotation(FilterGenerators.class);
133         List<FilterGenerator> filterGenerators = new ArrayList<FilterGenerator>();
134         if(customizers != null){
135             filterGenerators.addAll(Arrays.asList(customizers.value()));
136         } else {
137             FilterGenerator customizer = field.getAnnotation(FilterGenerator.class);
138             if(customizer != null){
139                 filterGenerators.add(customizer);
140             }
141         }
142         for(FilterGenerator customizer : filterGenerators){
143             List<FilterGenerator> filterCustomizers = queryCustomizerMap.get(key);
144             if (filterCustomizers == null) {
145                 filterCustomizers =
146                         new ArrayList<FilterGenerator>();
147                 filterCustomizers.add(customizer);
148                 queryCustomizerMap.putIfAbsent(key, filterCustomizers);
149             } else {
150                 filterCustomizers.add(customizer);
151                 queryCustomizerMap.put(key,filterCustomizers);
152             }
153         }
154     }
155 
156     
157 
158 
159 
160 
161     protected void handleDescriptorModifications(Session session) {
162         String sessionName = session.getName();
163 
164         
165         Boolean descModified = modDescMap.get(sessionName);
166         if (descModified == null) {
167             descModified = modDescMap.putIfAbsent(sessionName, Boolean.FALSE);
168             if (descModified == null) {
169                 descModified = modDescMap.get(sessionName);
170             }
171         }
172 
173         if (Boolean.FALSE.equals(descModified)) {
174             modDescMap.put(sessionName, Boolean.TRUE);
175             handleDisableVersioning(session);
176             handleRemoveMapping(session);
177         }
178     }
179 
180     
181 
182 
183 
184 
185 
186     protected void handleDisableVersioning(Session session) {
187         Map<Class, ClassDescriptor> descriptors = session.getDescriptors();
188 
189         if (descriptors == null || descriptors.isEmpty()) {
190             return;
191         }
192 
193         for (ClassDescriptor classDescriptor : descriptors.values()) {
194             if (classDescriptor != null && AnnotationUtils.findAnnotation(classDescriptor.getJavaClass(),
195                     DisableVersioning.class) != null) {
196                 OptimisticLockingPolicy olPolicy = classDescriptor.getOptimisticLockingPolicy();
197                 if (olPolicy != null) {
198                     classDescriptor.setOptimisticLockingPolicy(null);
199                 }
200             }
201         }
202     }
203 
204     
205 
206 
207 
208 
209 
210     protected void handleRemoveMapping(Session session) {
211         Map<Class, ClassDescriptor> descriptors = session.getDescriptors();
212 
213         if (descriptors == null || descriptors.isEmpty()) {
214             return;
215         }
216 
217         for (ClassDescriptor classDescriptor : descriptors.values()) {
218             List<DatabaseMapping> mappingsToRemove = new ArrayList<DatabaseMapping>();
219             List<RemoveMapping> removeMappings = scanForRemoveMappings(classDescriptor);
220 
221             for (RemoveMapping removeMapping : removeMappings) {
222                 if (StringUtils.isBlank(removeMapping.name())) {
223                     throw DescriptorException.attributeNameNotSpecified();
224                 }
225 
226                 DatabaseMapping databaseMapping = classDescriptor.getMappingForAttributeName(removeMapping.name());
227 
228                 if (databaseMapping == null) {
229                     throw DescriptorException.mappingForAttributeIsMissing(removeMapping.name(), classDescriptor);
230                 }
231 
232                 mappingsToRemove.add(databaseMapping);
233             }
234 
235             for (DatabaseMapping mappingToRemove : mappingsToRemove) {
236                 classDescriptor.removeMappingForAttributeName(mappingToRemove.getAttributeName());
237             }
238         }
239     }
240 
241     
242 
243 
244 
245 
246 
247     protected List<RemoveMapping> scanForRemoveMappings(ClassDescriptor classDescriptor) {
248         List<RemoveMapping> removeMappings = new ArrayList<RemoveMapping>();
249         RemoveMappings removeMappingsAnnotation = AnnotationUtils.findAnnotation(classDescriptor.getJavaClass(),
250                 RemoveMappings.class);
251         if (removeMappingsAnnotation == null) {
252             RemoveMapping removeMappingAnnotation = AnnotationUtils.findAnnotation(classDescriptor.getJavaClass(),
253                     RemoveMapping.class);
254             if (removeMappingAnnotation != null) {
255                 removeMappings.add(removeMappingAnnotation);
256             }
257         } else {
258             for (RemoveMapping removeMapping : removeMappingsAnnotation.value()) {
259                 removeMappings.add(removeMapping);
260             }
261         }
262         return removeMappings;
263     }
264 
265     
266 
267 
268 
269 
270 
271     protected List<Sequence> loadSequences(Session session) {
272         Map<Class, ClassDescriptor> descriptors = session.getDescriptors();
273         List<PortableSequenceGenerator> sequenceGenerators = new ArrayList<PortableSequenceGenerator>();
274         for (Class<?> entityClass : descriptors.keySet()) {
275             PortableSequenceGenerator sequenceGenerator = AnnotationUtils.findAnnotation(entityClass,
276                     PortableSequenceGenerator.class);
277             if (sequenceGenerator != null) {
278                 sequenceGenerators.add(sequenceGenerator);
279             }
280             loadFieldSequences(entityClass, sequenceGenerators);
281             for (Method method : entityClass.getMethods()) {
282                 PortableSequenceGenerator methodSequenceGenerator = method.getAnnotation(
283                         PortableSequenceGenerator.class);
284                 if (methodSequenceGenerator != null) {
285                     sequenceGenerators.add(methodSequenceGenerator);
286                 }
287             }
288         }
289         List<Sequence> sequences = new ArrayList<Sequence>();
290         for (PortableSequenceGenerator sequenceGenerator : sequenceGenerators) {
291             Sequence sequence = new MaxValueIncrementerSequenceWrapper(sequenceGenerator);
292             sequences.add(sequence);
293         }
294         return sequences;
295     }
296 
297     
298 
299 
300 
301 
302 
303     protected void loadFieldSequences(Class<?> entityClass, List<PortableSequenceGenerator> sequenceGenerators) {
304         for (Field field : entityClass.getDeclaredFields()) {
305             PortableSequenceGenerator fieldSequenceGenerator = field.getAnnotation(PortableSequenceGenerator.class);
306             if (fieldSequenceGenerator != null) {
307                 sequenceGenerators.add(fieldSequenceGenerator);
308             }
309         }
310         
311         if (entityClass.getSuperclass() != null) {
312             loadFieldSequences(entityClass.getSuperclass(), sequenceGenerators);
313         }
314     }
315 
316     
317 
318 
319     private static final class MaxValueIncrementerSequenceWrapper extends Sequence {
320 
321         private static final long serialVersionUID = 2375805962996574386L;
322 
323         private final String sequenceName;
324 
325         
326 
327 
328 
329 
330         MaxValueIncrementerSequenceWrapper(PortableSequenceGenerator sequenceGenerator) {
331             super(sequenceGenerator.name(), 0);
332             
333             if (StringUtils.isBlank(sequenceGenerator.sequenceName())) {
334                 sequenceName = sequenceGenerator.name();
335             } else {
336                 sequenceName = sequenceGenerator.sequenceName();
337             }
338         }
339 
340         
341 
342 
343         @Override
344         public boolean shouldAcquireValueAfterInsert() {
345             return false;
346         }
347 
348         
349 
350 
351         @Override
352         public boolean shouldUseTransaction() {
353             return true;
354         }
355 
356         
357 
358 
359         @Override
360         public boolean shouldUsePreallocation() {
361             return false;
362         }
363 
364         
365 
366 
367         @Override
368         public Object getGeneratedValue(Accessor accessor, AbstractSession writeSession, String seqName) {
369             DataSource dataSource = ((JNDIConnector) writeSession.getLogin().getConnector()).getDataSource();
370             DataFieldMaxValueIncrementer incrementer = MaxValueIncrementerFactory.getIncrementer(dataSource,
371                     sequenceName);
372             return Long.valueOf(incrementer.nextLongValue());
373         }
374 
375         
376 
377 
378         @Override
379         public Vector<?> getGeneratedVector(Accessor accessor, AbstractSession writeSession, String seqName, int size) {
380             
381             throw new UnsupportedOperationException(getClass().getName() + " does pre-generate sequence ids");
382         }
383 
384         
385 
386 
387         @Override
388         public void onConnect() {}
389 
390         
391 
392 
393         @Override
394         public void onDisconnect() {}
395 
396         
397 
398 
399         @Override
400         public MaxValueIncrementerSequenceWrapper clone() {
401             return (MaxValueIncrementerSequenceWrapper) super.clone();
402         }
403 
404     }
405 
406 }