(no commit message)
[utils] / support / general / src / main / java / org / wamblee / persistence / PersistentFactory.java
1 /*
2  * Copyright 2005-2010 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 package org.wamblee.persistence;
17
18 import java.io.Serializable;
19 import java.util.Map;
20 import java.util.concurrent.ConcurrentHashMap;
21
22 import javax.persistence.Id;
23 import javax.persistence.Version;
24
25 import org.wamblee.reflection.Accessor;
26 import org.wamblee.reflection.AnnotationUtils;
27
28 /**
29  * Factory which creates a {@link Persistent} object for a given JPA entity for
30  * interfacing with the primary key and version of the entity.
31  * 
32  * This utility only treats primary keys and fields that are annotated with @Id
33  * and @Version. In case ORM files are used for the definition of primary key
34  * and or version, then those fields are ignored.
35  * 
36  * @author Erik Brakkee
37  * 
38  */
39 public class PersistentFactory {
40
41     /**
42      * Cache of a mapping of class names to entity accessors.
43      */
44     private static Map<String, EntityAccessor> CACHE = new ConcurrentHashMap<String, EntityAccessor>();
45
46     static class EntityAccessor {
47         private Accessor pk;
48         private Accessor version;
49
50         public EntityAccessor(Accessor<?> aPk, Accessor<?> aVersion) {
51             pk = aPk;
52             version = aVersion;
53         }
54
55         public Accessor getPk() {
56             return pk;
57         }
58
59         public Accessor getVersion() {
60             return version;
61         }
62     }
63
64     public static class EntityObjectAccessor implements Persistent {
65         private EntityAccessor accessor;
66         private Object entity;
67
68         public EntityObjectAccessor(Object aEntity, EntityAccessor aAccessor) {
69             accessor = aAccessor;
70             entity = aEntity;
71         }
72
73         public EntityAccessor getAccessor() {
74             return accessor;
75         };
76
77         @Override
78         public Serializable getPrimaryKey() {
79             if (accessor == null || accessor.getPk() == null) {
80                 return null;
81             }
82             return (Serializable) accessor.getPk().get(entity);
83         }
84
85         @Override
86         public void setPrimaryKey(Serializable aKey) {
87             if (accessor == null || accessor.getPk() == null) {
88                 return;
89             }
90             accessor.getPk().set(entity, aKey);
91         }
92
93         @Override
94         public Number getPersistedVersion() {
95             if (accessor == null || accessor.getVersion() == null) {
96                 return null;
97             }
98             return (Number) accessor.getVersion().get(entity);
99         }
100
101         @Override
102         public void setPersistedVersion(Number aVersion) {
103             if (accessor == null || accessor.getVersion() == null) {
104                 return;
105             }
106             accessor.getVersion().set(entity, aVersion);
107         }
108     }
109
110     /**
111      * Create the entity accessor for a given class or returns a cached instance
112      * if one already exists.
113      * 
114      * @param aClass
115      *            Class.
116      * @return Entity accessor for the given class or null of the given object
117      *         is not an entity.
118      */
119     public static EntityAccessor createEntityAccessor(Class aClass) {
120         EntityAccessor accessor = CACHE.get(aClass.getName());
121         if (accessor == null) {
122             accessor = analyse(aClass);
123             if (accessor != null) {
124                 CACHE.put(aClass.getName(), accessor);
125             }
126         }
127         return accessor;
128     }
129
130     private static EntityAccessor analyse(Class aClass) {
131         Accessor<Serializable> pk = AnnotationUtils.analyse(aClass, Id.class);
132         Accessor<Integer> version = AnnotationUtils.analyse(aClass, Version.class);
133         if (pk != null || version != null) {
134             return new EntityAccessor(pk, version);
135         }
136         return null;
137     }
138
139     /**
140      * Creates the {@link Persistent} wrapper for interfacing with primary key
141      * and version of the entity.
142      * 
143      * @param aEntity
144      *            Entity to use.
145      * @return Persistent object or null if this is not an entity.
146      */
147     public static Persistent create(Object aEntity) {
148         EntityAccessor accessor = createEntityAccessor(aEntity.getClass());
149         if (accessor == null) {
150             return null;
151         }
152         return new EntityObjectAccessor(aEntity, accessor);
153     }
154 }