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