001: package org.garret.perst.impl;
002:
003: import org.garret.perst.*;
004:
005: import java.lang.reflect.*;
006: import java.util.*;
007: import java.util.ArrayList;
008:
009: class RndBtreeMultiFieldIndex<T extends IPersistent> extends
010: RndBtree<T> implements FieldIndex<T> {
011: String className;
012: String[] fieldName;
013:
014: transient Class cls;
015: transient Field[] fld;
016:
017: RndBtreeMultiFieldIndex() {
018: }
019:
020: RndBtreeMultiFieldIndex(Class cls, String[] fieldName,
021: boolean unique) {
022: this .cls = cls;
023: this .unique = unique;
024: this .fieldName = fieldName;
025: this .className = ClassDescriptor.getClassName(cls);
026: locateFields();
027: type = ClassDescriptor.tpRaw;
028: }
029:
030: private final void locateFields() {
031: Class scope = cls;
032: fld = new Field[fieldName.length];
033: for (int i = 0; i < fieldName.length; i++) {
034: fld[i] = ClassDescriptor.locateField(cls, fieldName[i]);
035: if (fld[i] == null) {
036: throw new StorageError(
037: StorageError.INDEXED_FIELD_NOT_FOUND, className
038: + "." + fieldName[i]);
039: }
040: }
041: }
042:
043: public Class getIndexedClass() {
044: return cls;
045: }
046:
047: public Field[] getKeyFields() {
048: return fld;
049: }
050:
051: public void onLoad() {
052: cls = ClassDescriptor.loadClass(getStorage(), className);
053: locateFields();
054: }
055:
056: static class CompoundKey implements Comparable {
057: Object[] keys;
058:
059: public int compareTo(Object o) {
060: CompoundKey c = (CompoundKey) o;
061: int n = keys.length < c.keys.length ? keys.length
062: : c.keys.length;
063: for (int i = 0; i < n; i++) {
064: int diff = ((Comparable) keys[i]).compareTo(c.keys[i]);
065: if (diff != 0) {
066: return diff;
067: }
068: }
069: return 0; // allow to compare part of the compound key
070: }
071:
072: CompoundKey(Object[] keys) {
073: this .keys = keys;
074: }
075: }
076:
077: private Key convertKey(Key key) {
078: if (key == null) {
079: return null;
080: }
081: if (key.type != ClassDescriptor.tpArrayOfObject) {
082: throw new StorageError(StorageError.INCOMPATIBLE_KEY_TYPE);
083: }
084: return new Key(new CompoundKey((Object[]) key.oval),
085: key.inclusion != 0);
086: }
087:
088: private Key extractKey(IPersistent obj) {
089: Object[] keys = new Object[fld.length];
090: try {
091: for (int i = 0; i < keys.length; i++) {
092: keys[i] = fld[i].get(obj);
093: if (keys[i] instanceof IPersistent) {
094: IPersistent p = (IPersistent) keys[i];
095: if (!p.isPersistent()) {
096: getStorage().makePersistent(p);
097: }
098: }
099: }
100: } catch (Exception x) {
101: throw new StorageError(StorageError.ACCESS_VIOLATION, x);
102: }
103: return new Key(new CompoundKey(keys));
104: }
105:
106: public boolean put(T obj) {
107: return super .put(extractKey(obj), obj);
108: }
109:
110: public T set(T obj) {
111: return super .set(extractKey(obj), obj);
112: }
113:
114: public void remove(T obj) {
115: super .remove(extractKey(obj), obj);
116: }
117:
118: public T remove(Key key) {
119: return super .remove(convertKey(key));
120: }
121:
122: public boolean containsObject(T obj) {
123: Key key = extractKey(obj);
124: if (unique) {
125: return super .get(key) != null;
126: } else {
127: IPersistent[] mbrs = get(key, key);
128: for (int i = 0; i < mbrs.length; i++) {
129: if (mbrs[i] == obj) {
130: return true;
131: }
132: }
133: return false;
134: }
135: }
136:
137: public boolean contains(T obj) {
138: Key key = extractKey(obj);
139: if (unique) {
140: return super .get(key) != null;
141: } else {
142: IPersistent[] mbrs = get(key, key);
143: for (int i = 0; i < mbrs.length; i++) {
144: if (mbrs[i].equals(obj)) {
145: return true;
146: }
147: }
148: return false;
149: }
150: }
151:
152: public void append(T obj) {
153: throw new StorageError(StorageError.UNSUPPORTED_INDEX_TYPE);
154: }
155:
156: public T[] get(Key from, Key till) {
157: ArrayList list = new ArrayList();
158: if (root != null) {
159: root.find(convertKey(from), convertKey(till), height, list);
160: }
161: return (T[]) list.toArray((T[]) Array.newInstance(cls, list
162: .size()));
163: }
164:
165: public T[] getPrefix(String prefix) {
166: throw new StorageError(StorageError.INCOMPATIBLE_KEY_TYPE);
167: }
168:
169: public T[] prefixSearch(String key) {
170: throw new StorageError(StorageError.INCOMPATIBLE_KEY_TYPE);
171: }
172:
173: public T[] toPersistentArray() {
174: T[] arr = (T[]) Array.newInstance(cls, nElems);
175: if (root != null) {
176: root.traverseForward(height, arr, 0);
177: }
178: return arr;
179: }
180:
181: public T get(Key key) {
182: return super .get(convertKey(key));
183: }
184:
185: public IterableIterator<T> iterator(Key from, Key till, int order) {
186: return super
187: .iterator(convertKey(from), convertKey(till), order);
188: }
189:
190: public IterableIterator<Map.Entry<Object, T>> entryIterator(
191: Key from, Key till, int order) {
192: return super .entryIterator(convertKey(from), convertKey(till),
193: order);
194: }
195:
196: public IterableIterator<T> queryByExample(T obj) {
197: Key key = extractKey(obj);
198: return iterator(key, key, ASCENT_ORDER);
199: }
200:
201: public IterableIterator<T> select(String predicate) {
202: Query<T> query = new QueryImpl<T>(getStorage());
203: return query.select(cls, iterator(), predicate);
204: }
205:
206: public boolean isCaseInsensitive() {
207: return false;
208: }
209: }
210:
211: class RndBtreeCaseInsensitiveMultiFieldIndex<T extends IPersistent>
212: extends RndBtreeMultiFieldIndex<T> {
213: RndBtreeCaseInsensitiveMultiFieldIndex() {
214: }
215:
216: RndBtreeCaseInsensitiveMultiFieldIndex(Class cls,
217: String[] fieldNames, boolean unique) {
218: super (cls, fieldNames, unique);
219: }
220:
221: Key checkKey(Key key) {
222: if (key != null) {
223: CompoundKey ck = (CompoundKey) key.oval;
224: for (int i = 0; i < ck.keys.length; i++) {
225: if (ck.keys[i] instanceof String) {
226: ck.keys[i] = ((String) ck.keys[i]).toLowerCase();
227: }
228: }
229: }
230: return super .checkKey(key);
231: }
232:
233: public boolean isCaseInsensitive() {
234: return true;
235: }
236: }
|