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.Array; 12import java.lang.reflect.Modifier; 13import java.util.Collections; 14import java.util.HashMap; 15import java.util.List; 16import java.util.Map; 17 18/** 19 * Implements Accessor for a complex persistent class. 20 * 21 * @author Mark Hayes 22 */ 23public class EnhancedAccessor implements Accessor { 24 25 private static final Map<String,Enhanced> classRegistry = 26 Collections.synchronizedMap(new HashMap<String,Enhanced>()); 27 28 /* Is public for unit tests. */ 29 public static final boolean EXPECT_ENHANCED = 30 "true".equals(System.getProperty("expectEnhanced")); 31 32 private Enhanced prototype; 33 private Format priKeyFormat; 34 private Format[] compositeKeyFormats; 35 private Class type; 36 37 /** 38 * Registers a prototype instance, and should be called during 39 * initialization of the prototype class. The prototype may be null for 40 * an abstract class. 41 */ 42 public static void registerClass(String className, Enhanced prototype) { 43 classRegistry.put(className, prototype); 44 } 45 46 /** 47 * Returns whether a given class is a (registered) enhanced class. 48 */ 49 static boolean isEnhanced(Class type) { 50 boolean enhanced = classRegistry.containsKey(type.getName()); 51 if (!enhanced && EXPECT_ENHANCED) { 52 throw new IllegalStateException 53 ("Test was run with expectEnhanced=true but class " + 54 type.getName() + " is not enhanced"); 55 } 56 return enhanced; 57 } 58 59 private EnhancedAccessor(Class type) { 60 this.type = type; 61 prototype = classRegistry.get(type.getName()); 62 assert prototype != null || Modifier.isAbstract(type.getModifiers()); 63 } 64 65 /** 66 * Creates an accessor for a complex type. 67 */ 68 EnhancedAccessor(Catalog catalog, Class type, ComplexFormat format) { 69 this(type); 70 71 /* 72 * Find the primary key format for this format or one of its superclass 73 * formats. 74 */ 75 ComplexFormat declaringFormat = format; 76 while (declaringFormat != null) { 77 FieldInfo priKeyField = declaringFormat.getPriKeyFieldInfo(); 78 if (priKeyField != null) { 79 priKeyFormat = catalog.getFormat(priKeyField.getClassName()); 80 break; 81 } else { 82 declaringFormat = declaringFormat.getComplexSuper(); 83 } 84 } 85 } 86 87 /** 88 * Creates an accessor for a composite key type. 89 */ 90 EnhancedAccessor(Catalog catalog, Class type, List<FieldInfo> fieldInfos) { 91 this(type); 92 final int nFields = fieldInfos.size(); 93 compositeKeyFormats = new Format[nFields]; 94 for (int i = 0; i < nFields; i += 1) { 95 compositeKeyFormats[i] = 96 catalog.getFormat(fieldInfos.get(i).getClassName()); 97 } 98 } 99 100 public Object newInstance() { 101 if (prototype == null) { 102 /* Abstract class -- internal error. */ 103 throw new IllegalStateException(); 104 } 105 return prototype.bdbNewInstance(); 106 } 107 108 public Object newArray(int len) { 109 if (prototype == null) { 110 /* Abstract class -- use reflection for now. */ 111 return Array.newInstance(type, len); 112 } 113 return prototype.bdbNewArray(len); 114 } 115 116 public boolean isPriKeyFieldNullOrZero(Object o) { 117 if (priKeyFormat == null) { 118 throw new IllegalStateException 119 ("No primary key: " + o.getClass().getName()); 120 } 121 return ((Enhanced) o).bdbIsPriKeyFieldNullOrZero(); 122 } 123 124 public void writePriKeyField(Object o, EntityOutput output) { 125 if (priKeyFormat == null) { 126 throw new IllegalStateException 127 ("No primary key: " + o.getClass().getName()); 128 } 129 ((Enhanced) o).bdbWritePriKeyField(output, priKeyFormat); 130 } 131 132 public void readPriKeyField(Object o, EntityInput input) { 133 if (priKeyFormat == null) { 134 throw new IllegalStateException 135 ("No primary key: " + o.getClass().getName()); 136 } 137 ((Enhanced) o).bdbReadPriKeyField(input, priKeyFormat); 138 } 139 140 public void writeSecKeyFields(Object o, EntityOutput output) { 141 ((Enhanced) o).bdbWriteSecKeyFields(output); 142 } 143 144 public void readSecKeyFields(Object o, 145 EntityInput input, 146 int startField, 147 int endField, 148 int superLevel) { 149 ((Enhanced) o).bdbReadSecKeyFields 150 (input, startField, endField, superLevel); 151 } 152 153 public void writeNonKeyFields(Object o, EntityOutput output) { 154 ((Enhanced) o).bdbWriteNonKeyFields(output); 155 } 156 157 public void readNonKeyFields(Object o, 158 EntityInput input, 159 int startField, 160 int endField, 161 int superLevel) { 162 ((Enhanced) o).bdbReadNonKeyFields 163 (input, startField, endField, superLevel); 164 } 165 166 public void writeCompositeKeyFields(Object o, EntityOutput output) { 167 ((Enhanced) o).bdbWriteCompositeKeyFields(output, compositeKeyFormats); 168 } 169 170 public void readCompositeKeyFields(Object o, EntityInput input) { 171 ((Enhanced) o).bdbReadCompositeKeyFields(input, compositeKeyFormats); 172 } 173 174 public Object getField(Object o, 175 int field, 176 int superLevel, 177 boolean isSecField) { 178 return ((Enhanced) o).bdbGetField(o, field, superLevel, isSecField); 179 } 180 181 public void setField(Object o, 182 int field, 183 int superLevel, 184 boolean isSecField, 185 Object value) { 186 ((Enhanced) o).bdbSetField(o, field, superLevel, isSecField, value); 187 } 188} 189