1 8 9 package com.sleepycat.persist.model; 10 11 import java.lang.reflect.Field ; 12 import java.lang.reflect.Modifier ; 13 import java.lang.reflect.ParameterizedType ; 14 import java.lang.reflect.Type ; 15 import java.util.ArrayList ; 16 import java.util.Collections ; 17 import java.util.HashMap ; 18 import java.util.HashSet ; 19 import java.util.List ; 20 import java.util.Map ; 21 import java.util.Set ; 22 23 40 public class AnnotationModel extends EntityModel { 41 42 private static class EntityInfo { 43 PrimaryKeyMetadata priKey; 44 Map <String ,SecondaryKeyMetadata> secKeys = 45 new HashMap <String ,SecondaryKeyMetadata>(); 46 } 47 48 private Map <String ,ClassMetadata> classMap; 49 private Map <String ,EntityInfo> entityMap; 50 51 54 public AnnotationModel() { 55 super(); 56 classMap = new HashMap <String ,ClassMetadata>(); 57 entityMap = new HashMap <String ,EntityInfo>(); 58 } 59 60 61 62 @Override ![JavaDoc](../../../../../cmn/javadoc.gif) 63 public synchronized Set <String > getKnownClasses() { 64 return Collections.unmodifiableSet 65 (new HashSet <String >(classMap.keySet())); 66 } 67 68 @Override ![JavaDoc](../../../../../cmn/javadoc.gif) 69 public synchronized EntityMetadata getEntityMetadata(String className) { 70 71 getClassMetadata(className); 72 73 EntityInfo info = entityMap.get(className); 74 if (info != null) { 75 return new EntityMetadata 76 (className, info.priKey, 77 Collections.unmodifiableMap(info.secKeys)); 78 } else { 79 return null; 80 } 81 } 82 83 @Override ![JavaDoc](../../../../../cmn/javadoc.gif) 84 public synchronized ClassMetadata getClassMetadata(String className) { 85 ClassMetadata metadata = classMap.get(className); 86 if (metadata == null) { 87 Class <?> type; 88 try { 89 type = Class.forName(className); 90 } catch (ClassNotFoundException e) { 91 return null; 92 } 93 94 Entity entity = type.getAnnotation(Entity.class); 95 Persistent persistent = type.getAnnotation(Persistent.class); 96 if (entity == null && persistent == null) { 97 return null; 98 } 99 if (entity != null && persistent != null) { 100 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 101 ("Both @Entity and @Persistent are not allowed: " + 102 type.getName()); 103 } 104 boolean isEntity; 105 int version; 106 String proxiedClassName; 107 if (entity != null) { 108 isEntity = true; 109 version = entity.version(); 110 proxiedClassName = null; 111 } else { 112 isEntity = false; 113 version = persistent.version(); 114 Class proxiedClass = persistent.proxyFor(); 115 proxiedClassName = (proxiedClass != void.class) ? 116 proxiedClass.getName() : null; 117 } 118 119 List <Field > fields = new ArrayList <Field >(); 120 for (Field field : type.getDeclaredFields()) { 121 int mods = field.getModifiers(); 122 if (!Modifier.isTransient(mods) && !Modifier.isStatic(mods)) { 123 fields.add(field); 124 } 125 } 126 127 metadata = new ClassMetadata 128 (className, version, proxiedClassName, isEntity, 129 getPrimaryKey(type, fields), 130 getSecondaryKeys(type, fields), 131 getCompositeKeyFields(type, fields)); 132 classMap.put(className, metadata); 133 134 updateEntityInfo(metadata); 135 } 136 return metadata; 137 } 138 139 private PrimaryKeyMetadata getPrimaryKey(Class <?> type, 140 List <Field > fields) { 141 Field foundField = null; 142 String sequence = null; 143 for (Field field : fields) { 144 PrimaryKey priKey = field.getAnnotation(PrimaryKey.class); 145 if (priKey != null) { 146 if (foundField != null) { 147 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 148 ("Only one @PrimaryKey allowed: " + type.getName()); 149 } else { 150 foundField = field; 151 sequence = priKey.sequence(); 152 if (sequence.length() == 0) { 153 sequence = null; 154 } 155 } 156 } 157 } 158 if (foundField != null) { 159 return new PrimaryKeyMetadata 160 (foundField.getName(), foundField.getType().getName(), 161 type.getName(), sequence); 162 } else { 163 return null; 164 } 165 } 166 167 private Map <String ,SecondaryKeyMetadata> getSecondaryKeys(Class <?> type, 168 List <Field > fields) { 169 Map <String ,SecondaryKeyMetadata> map = null; 170 for (Field field : fields) { 171 SecondaryKey secKey = field.getAnnotation(SecondaryKey.class); 172 if (secKey != null) { 173 Relationship rel = secKey.relate(); 174 String elemClassName = null; 175 if (rel == Relationship.ONE_TO_MANY || 176 rel == Relationship.MANY_TO_MANY) { 177 elemClassName = getElementClass(field); 178 } 179 String keyName = secKey.name(); 180 if (keyName.length() == 0) { 181 keyName = field.getName(); 182 } 183 Class <?> relatedClass = secKey.relatedEntity(); 184 String relatedEntity = (relatedClass != void.class) ? 185 relatedClass.getName() : null; 186 DeleteAction deleteAction = (relatedEntity != null) ? 187 secKey.onRelatedEntityDelete() : null; 188 SecondaryKeyMetadata metadata = new SecondaryKeyMetadata 189 (field.getName(), field.getType().getName(), 190 type.getName(), elemClassName, keyName, rel, 191 relatedEntity, deleteAction); 192 if (map == null) { 193 map = new HashMap <String ,SecondaryKeyMetadata>(); 194 } 195 if (map.put(keyName, metadata) != null) { 196 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 197 ("Only one @SecondaryKey with the same name allowed: " 198 + type.getName() + '.' + keyName); 199 } 200 } 201 } 202 if (map != null) { 203 map = Collections.unmodifiableMap(map); 204 } 205 return map; 206 } 207 208 private String getElementClass(Field field) { 209 Class cls = field.getType(); 210 if (cls.isArray()) { 211 return cls.getComponentType().getName(); 212 } 213 if (java.util.Collection .class.isAssignableFrom(cls)) { 214 Type [] typeArgs = ((ParameterizedType ) field.getGenericType()). 215 getActualTypeArguments(); 216 if (typeArgs == null || 217 typeArgs.length != 1 || 218 !(typeArgs[0] instanceof Class )) { 219 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 220 ("Collection typed secondary key field must have a" + 221 " single generic type argument: " + 222 field.getDeclaringClass().getName() + '.' + 223 field.getName()); 224 } 225 return ((Class ) typeArgs[0]).getName(); 226 } 227 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 228 ("ONE_TO_MANY or MANY_TO_MANY secondary key field must have" + 229 " an array or Collection type: " + 230 field.getDeclaringClass().getName() + '.' + field.getName()); 231 } 232 233 private List <FieldMetadata> getCompositeKeyFields(Class <?> type, 234 List <Field > fields) { 235 List <FieldMetadata> list = null; 236 for (Field field : fields) { 237 KeyField keyField = field.getAnnotation(KeyField.class); 238 if (keyField != null) { 239 int value = keyField.value(); 240 if (value < 1 || value > fields.size()) { 241 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 242 ("Unreasonable @KeyField index value " + value + 243 ": " + type.getName()); 244 } 245 if (list == null) { 246 list = new ArrayList <FieldMetadata>(fields.size()); 247 } 248 if (value <= list.size() && list.get(value - 1) != null) { 249 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 250 ("@KeyField index value " + value + 251 " is used more than once: " + type.getName()); 252 } 253 while (value > list.size()) { 254 list.add(null); 255 } 256 FieldMetadata metadata = new FieldMetadata 257 (field.getName(), field.getType().getName(), 258 type.getName()); 259 list.set(value - 1, metadata); 260 } 261 } 262 if (list != null) { 263 if (list.size() < fields.size()) { 264 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 265 ("@KeyField is missing on one or more instance fields: " + 266 type.getName()); 267 } 268 for (int i = 0; i < list.size(); i += 1) { 269 if (list.get(i) == null) { 270 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 271 ("@KeyField is missing for index value " + (i + 1) + 272 ": " + type.getName()); 273 } 274 } 275 } 276 if (list != null) { 277 list = Collections.unmodifiableList(list); 278 } 279 return list; 280 } 281 282 287 private void updateEntityInfo(ClassMetadata metadata) { 288 289 294 String entityClass = null; 295 PrimaryKeyMetadata priKey = null; 296 Map <String ,SecondaryKeyMetadata> secKeys = 297 new HashMap <String ,SecondaryKeyMetadata>(); 298 for (ClassMetadata data = metadata; data != null;) { 299 if (data.isEntityClass()) { 300 if (entityClass != null) { 301 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 302 ("An entity class may not derived from another" + 303 " entity class: " + entityClass + 304 ' ' + data.getClassName()); 305 } 306 entityClass = data.getClassName(); 307 } 308 309 if (priKey == null) { 310 priKey = data.getPrimaryKey(); 311 } 312 313 Map <String ,SecondaryKeyMetadata> classSecKeys = 314 data.getSecondaryKeys(); 315 if (classSecKeys != null) { 316 for (SecondaryKeyMetadata secKey : classSecKeys.values()) { 317 secKeys.put(secKey.getKeyName(), secKey); 318 } 319 } 320 321 Class cls; 322 try { 323 cls = Class.forName(data.getClassName()); 324 } catch (ClassNotFoundException e) { 325 throw new IllegalStateException (e); 326 } 327 cls = cls.getSuperclass(); 328 if (cls != Object .class) { 329 data = getClassMetadata(cls.getName()); 330 if (data == null) { 331 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 332 ("Persistent class has non-persistent superclass: " + 333 cls.getName()); 334 } 335 } else { 336 data = null; 337 } 338 } 339 340 341 if (entityClass != null) { 342 EntityInfo info = entityMap.get(entityClass); 343 if (info == null) { 344 info = new EntityInfo(); 345 entityMap.put(entityClass, info); 346 } 347 if (priKey == null) { 348 throw new IllegalArgumentException ![JavaDoc](../../../../../cmn/javadoc.gif) 349 ("Entity class has no primary key: " + entityClass); 350 } 351 info.priKey = priKey; 352 info.secKeys.putAll(secKeys); 353 } 354 } 355 } 356 | Popular Tags |