1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9package com.sleepycat.persist.impl; 10 11import java.lang.reflect.AccessibleObject; 12import java.lang.reflect.Array; 13import java.lang.reflect.Constructor; 14import java.lang.reflect.Field; 15import java.lang.reflect.InvocationTargetException; 16import java.lang.reflect.Modifier; 17import java.util.List; 18 19/** 20 * Implements Accessor using reflection. 21 * 22 * @author Mark Hayes 23 */ 24class ReflectionAccessor implements Accessor { 25 26 private static final FieldAccess[] EMPTY_KEYS = {}; 27 28 private Class type; 29 private Accessor superAccessor; 30 private Constructor constructor; 31 private FieldAccess priKey; 32 private FieldAccess[] secKeys; 33 private FieldAccess[] nonKeys; 34 35 private ReflectionAccessor(Class type, Accessor superAccessor) { 36 this.type = type; 37 this.superAccessor = superAccessor; 38 try { 39 constructor = type.getDeclaredConstructor(); 40 } catch (NoSuchMethodException e) { 41 throw new IllegalStateException(type.getName()); 42 } 43 if (!Modifier.isPublic(constructor.getModifiers())) { 44 setAccessible(constructor, type.getName() + "()"); 45 } 46 } 47 48 /** 49 * Creates an accessor for a complex type. 50 */ 51 ReflectionAccessor(Catalog catalog, 52 Class type, 53 Accessor superAccessor, 54 FieldInfo priKeyField, 55 List<FieldInfo> secKeyFields, 56 List<FieldInfo> nonKeyFields) { 57 this(type, superAccessor); 58 if (priKeyField != null) { 59 priKey = getField(catalog, priKeyField, 60 true /*isRequiredKeyField*/, 61 false /*isCompositeKey*/); 62 } else { 63 priKey = null; 64 } 65 if (secKeyFields.size() > 0) { 66 secKeys = getFields(catalog, secKeyFields, 67 false /*isRequiredKeyField*/, 68 false /*isCompositeKey*/); 69 } else { 70 secKeys = EMPTY_KEYS; 71 } 72 if (nonKeyFields.size() > 0) { 73 nonKeys = getFields(catalog, nonKeyFields, 74 false /*isRequiredKeyField*/, 75 false /*isCompositeKey*/); 76 } else { 77 nonKeys = EMPTY_KEYS; 78 } 79 } 80 81 /** 82 * Creates an accessor for a composite key type. 83 */ 84 ReflectionAccessor(Catalog catalog, 85 Class type, 86 List<FieldInfo> fieldInfos) { 87 this(type, null); 88 priKey = null; 89 secKeys = EMPTY_KEYS; 90 nonKeys = getFields(catalog, fieldInfos, 91 true /*isRequiredKeyField*/, 92 true /*isCompositeKey*/); 93 } 94 95 private FieldAccess[] getFields(Catalog catalog, 96 List<FieldInfo> fieldInfos, 97 boolean isRequiredKeyField, 98 boolean isCompositeKey) { 99 int index = 0; 100 FieldAccess[] fields = new FieldAccess[fieldInfos.size()]; 101 for (FieldInfo info : fieldInfos) { 102 fields[index] = getField 103 (catalog, info, isRequiredKeyField, isCompositeKey); 104 index += 1; 105 } 106 return fields; 107 } 108 109 private FieldAccess getField(Catalog catalog, 110 FieldInfo fieldInfo, 111 boolean isRequiredKeyField, 112 boolean isCompositeKey) { 113 Field field; 114 try { 115 field = type.getDeclaredField(fieldInfo.getName()); 116 } catch (NoSuchFieldException e) { 117 throw new IllegalStateException(e); 118 } 119 if (!Modifier.isPublic(field.getModifiers())) { 120 setAccessible(field, field.getName()); 121 } 122 Class fieldCls = field.getType(); 123 if (fieldCls.isPrimitive()) { 124 assert SimpleCatalog.isSimpleType(fieldCls); 125 return new PrimitiveAccess 126 (field, SimpleCatalog.getSimpleFormat(fieldCls)); 127 } else if (isRequiredKeyField) { 128 Format format = catalog.getFormat(fieldInfo.getClassName()); 129 assert format != null; 130 return new KeyObjectAccess(field, format); 131 } else { 132 return new ObjectAccess(field); 133 } 134 } 135 136 private void setAccessible(AccessibleObject object, String memberName) { 137 try { 138 object.setAccessible(true); 139 } catch (SecurityException e) { 140 throw new IllegalStateException 141 ("Unable to access non-public member: " + 142 type.getName() + '.' + memberName + 143 ". Please configure the Java Security Manager setting: " + 144 " ReflectPermission suppressAccessChecks", e); 145 } 146 } 147 148 public Object newInstance() { 149 try { 150 return constructor.newInstance(); 151 } catch (IllegalAccessException e) { 152 throw new IllegalStateException(e); 153 } catch (InstantiationException e) { 154 throw new IllegalStateException(e); 155 } catch (InvocationTargetException e) { 156 throw new IllegalStateException(e); 157 } 158 } 159 160 public Object newArray(int len) { 161 return Array.newInstance(type, len); 162 } 163 164 public boolean isPriKeyFieldNullOrZero(Object o) { 165 try { 166 if (priKey != null) { 167 return priKey.isNullOrZero(o); 168 } else if (superAccessor != null) { 169 return superAccessor.isPriKeyFieldNullOrZero(o); 170 } else { 171 throw new IllegalStateException("No primary key field"); 172 } 173 } catch (IllegalAccessException e) { 174 throw new IllegalStateException(e); 175 } 176 } 177 178 public void writePriKeyField(Object o, EntityOutput output) { 179 try { 180 if (priKey != null) { 181 priKey.write(o, output); 182 } else if (superAccessor != null) { 183 superAccessor.writePriKeyField(o, output); 184 } else { 185 throw new IllegalStateException("No primary key field"); 186 } 187 } catch (IllegalAccessException e) { 188 throw new IllegalStateException(e); 189 } 190 } 191 192 public void readPriKeyField(Object o, EntityInput input) { 193 try { 194 if (priKey != null) { 195 priKey.read(o, input); 196 } else if (superAccessor != null) { 197 superAccessor.readPriKeyField(o, input); 198 } else { 199 throw new IllegalStateException("No primary key field"); 200 } 201 } catch (IllegalAccessException e) { 202 throw new IllegalStateException(e); 203 } 204 } 205 206 public void writeSecKeyFields(Object o, EntityOutput output) { 207 try { 208 if (priKey != null && !priKey.isPrimitive) { 209 output.registerPriKeyObject(priKey.field.get(o)); 210 } 211 if (superAccessor != null) { 212 superAccessor.writeSecKeyFields(o, output); 213 } 214 for (int i = 0; i < secKeys.length; i += 1) { 215 secKeys[i].write(o, output); 216 } 217 } catch (IllegalAccessException e) { 218 throw new IllegalStateException(e); 219 } 220 } 221 222 public void readSecKeyFields(Object o, 223 EntityInput input, 224 int startField, 225 int endField, 226 int superLevel) { 227 try { 228 if (priKey != null && !priKey.isPrimitive) { 229 input.registerPriKeyObject(priKey.field.get(o)); 230 } 231 if (superLevel != 0 && superAccessor != null) { 232 superAccessor.readSecKeyFields 233 (o, input, startField, endField, superLevel - 1); 234 } else { 235 if (superLevel > 0) { 236 throw new IllegalStateException 237 ("Superclass does not exist"); 238 } 239 } 240 if (superLevel <= 0) { 241 for (int i = startField; 242 i <= endField && i < secKeys.length; 243 i += 1) { 244 secKeys[i].read(o, input); 245 } 246 } 247 } catch (IllegalAccessException e) { 248 throw new IllegalStateException(e); 249 } 250 } 251 252 public void writeNonKeyFields(Object o, EntityOutput output) { 253 try { 254 if (superAccessor != null) { 255 superAccessor.writeNonKeyFields(o, output); 256 } 257 for (int i = 0; i < nonKeys.length; i += 1) { 258 nonKeys[i].write(o, output); 259 } 260 } catch (IllegalAccessException e) { 261 throw new IllegalStateException(e); 262 } 263 } 264 265 public void readNonKeyFields(Object o, 266 EntityInput input, 267 int startField, 268 int endField, 269 int superLevel) { 270 try { 271 if (superLevel != 0 && superAccessor != null) { 272 superAccessor.readNonKeyFields 273 (o, input, startField, endField, superLevel - 1); 274 } else { 275 if (superLevel > 0) { 276 throw new IllegalStateException 277 ("Superclass does not exist"); 278 } 279 } 280 if (superLevel <= 0) { 281 for (int i = startField; 282 i <= endField && i < nonKeys.length; 283 i += 1) { 284 nonKeys[i].read(o, input); 285 } 286 } 287 } catch (IllegalAccessException e) { 288 throw new IllegalStateException(e); 289 } 290 } 291 292 public void writeCompositeKeyFields(Object o, EntityOutput output) { 293 try { 294 for (int i = 0; i < nonKeys.length; i += 1) { 295 nonKeys[i].write(o, output); 296 } 297 } catch (IllegalAccessException e) { 298 throw new IllegalStateException(e); 299 } 300 } 301 302 public void readCompositeKeyFields(Object o, EntityInput input) { 303 try { 304 for (int i = 0; i < nonKeys.length; i += 1) { 305 nonKeys[i].read(o, input); 306 } 307 } catch (IllegalAccessException e) { 308 throw new IllegalStateException(e); 309 } 310 } 311 312 public Object getField(Object o, 313 int field, 314 int superLevel, 315 boolean isSecField) { 316 if (superLevel > 0) { 317 return superAccessor.getField 318 (o, field, superLevel - 1, isSecField); 319 } 320 try { 321 Field fld = 322 isSecField ? secKeys[field].field : nonKeys[field].field; 323 return fld.get(o); 324 } catch (IllegalAccessException e) { 325 throw new IllegalStateException(e); 326 } 327 } 328 329 public void setField(Object o, 330 int field, 331 int superLevel, 332 boolean isSecField, 333 Object value) { 334 if (superLevel > 0) { 335 superAccessor.setField 336 (o, field, superLevel - 1, isSecField, value); 337 return; 338 } 339 try { 340 Field fld = 341 isSecField ? secKeys[field].field : nonKeys[field].field; 342 fld.set(o, value); 343 } catch (IllegalAccessException e) { 344 throw new IllegalStateException(e); 345 } 346 } 347 348 /** 349 * Abstract base class for field access classes. 350 */ 351 private static abstract class FieldAccess { 352 353 Field field; 354 boolean isPrimitive; 355 356 FieldAccess(Field field) { 357 this.field = field; 358 isPrimitive = field.getType().isPrimitive(); 359 } 360 361 /** 362 * Writes a field. 363 */ 364 abstract void write(Object o, EntityOutput out) 365 throws IllegalAccessException; 366 367 /** 368 * Reads a field. 369 */ 370 abstract void read(Object o, EntityInput in) 371 throws IllegalAccessException; 372 373 /** 374 * Returns whether a field is null (for reference types) or zero (for 375 * primitive integer types). This implementation handles the reference 376 * types. 377 */ 378 boolean isNullOrZero(Object o) 379 throws IllegalAccessException { 380 381 return field.get(o) == null; 382 } 383 } 384 385 /** 386 * Access for fields with object types. 387 */ 388 private static class ObjectAccess extends FieldAccess { 389 390 ObjectAccess(Field field) { 391 super(field); 392 } 393 394 @Override 395 void write(Object o, EntityOutput out) 396 throws IllegalAccessException { 397 398 out.writeObject(field.get(o), null); 399 } 400 401 @Override 402 void read(Object o, EntityInput in) 403 throws IllegalAccessException { 404 405 field.set(o, in.readObject()); 406 } 407 } 408 409 /** 410 * Access for primary key fields and composite key fields with object 411 * types. 412 */ 413 private static class KeyObjectAccess extends FieldAccess { 414 415 private Format format; 416 417 KeyObjectAccess(Field field, Format format) { 418 super(field); 419 this.format = format; 420 } 421 422 @Override 423 void write(Object o, EntityOutput out) 424 throws IllegalAccessException { 425 426 out.writeKeyObject(field.get(o), format); 427 } 428 429 @Override 430 void read(Object o, EntityInput in) 431 throws IllegalAccessException { 432 433 field.set(o, in.readKeyObject(format)); 434 } 435 } 436 437 /** 438 * Access for fields with primitive types. 439 */ 440 private static class PrimitiveAccess extends FieldAccess { 441 442 private SimpleFormat format; 443 444 PrimitiveAccess(Field field, SimpleFormat format) { 445 super(field); 446 this.format = format; 447 } 448 449 @Override 450 void write(Object o, EntityOutput out) 451 throws IllegalAccessException { 452 453 format.writePrimitiveField(o, out, field); 454 } 455 456 @Override 457 void read(Object o, EntityInput in) 458 throws IllegalAccessException { 459 460 format.readPrimitiveField(o, in, field); 461 } 462 463 @Override 464 boolean isNullOrZero(Object o) 465 throws IllegalAccessException { 466 467 return field.getLong(o) == 0; 468 } 469 } 470} 471