Source code: org/vrspace/server/db/DBCache.java
1 package org.vrspace.server.db;
2
3 import java.lang.reflect.*;
4 import java.util.*;
5 import java.io.*;
6
7 import org.vrspace.server.*;
8 import org.vrspace.util.*;
9
10 /**
11 * Database class
12 *
13 */
14 public class DBCache extends DB {
15 private TreeMap tables = new TreeMap();
16 private DB db;
17
18 public DBCache( DB db ) {
19 db.cache = this;
20 this.db = db;
21 }
22
23 public String create( String name ) throws Exception {
24 return db.create( name );
25 }
26 /**
27 Returns references to cached tables
28 */
29 TreeMap getTables() {
30 return tables;
31 }
32 /**
33 Connect to database.
34 Calls underlying DB connect().
35 **/
36 public void connect( String name ) throws Exception
37 {
38 db.connect( name );
39 }
40
41 /** Disconnect **/
42 public void disconnect()
43 {
44 db.disconnect();
45 }
46
47 /**
48 Commit. Just calls underlying commit
49 */
50 public void commit() {
51 db.commit();
52 }
53
54 /**
55 Get an object.
56 */
57 public Object get ( Object obj ) throws Exception
58 {
59 return get( getClassName(obj), obj.getClass().getField( "db_id" ).getLong(obj) );
60 }
61
62 /** From the table <b>obj</b>.getClass().getName() deletes the row having
63 ** db_id == <b>obj</b>.db_id, from both cache and the underlying db.
64 */
65 public void delete( Object obj ) throws Exception
66 {
67 TreeMap table = (TreeMap) tables.get( getClassName(obj) );
68 if ( table != null ) {
69 long id = obj.getClass().getField("db_id").getLong( obj );
70 table.remove( new Long( id ) );
71 }
72 db.delete( obj );
73 }
74 /**
75 Returns the object having id == <b>obj</b>.db_id
76 */
77 public Object get( String className, long id ) throws Exception
78 {
79 Object ret;
80 if ( className == null ) {
81 throw new DBException( "Null className" );
82 }
83 if ( tables == null ) {
84 throw new DBException( "Null tables" );
85 }
86 TreeMap table = (TreeMap) tables.get( className );
87 if ( table == null ) {
88 ret = db.get( className, id );
89 if ( ret == null ) {
90 /*
91 // let's just ignore this - it's not important for the cache
92 DBException tabe = new DBException( "Table " + className + " does not exist" );
93 Logger.logError( tabe );
94 throw tabe;
95 */
96 } else {
97 _put( ret );
98 }
99 } else {
100 ret = table.get( new Long(id) );
101 //Logger.logDebug( "DB.get("+className+","+id+")->"+ret );
102 if ( ret == null ) {
103 ret = db.get( className, id );
104 }
105 if ( ret != null ) {
106 _put( ret );
107 }
108 }
109 return ret;
110 }
111
112 /** Returns the object of <b>className</b> class having <b>field</b> == <b>value</b> */
113 public Object get( String className, String field, Object value ) throws Exception
114 {
115 if ( className == null ) {
116 throw new DBException( "Null className" );
117 }
118 if ( tables == null ) {
119 throw new DBException( "Null tables" );
120 }
121 Object ret = null;
122 TreeMap table = (TreeMap) tables.get( className );
123 if ( table == null ) {
124 throw new DBException( "Table " + className + " does not exist" );
125 } else {
126 Object[] rows = table.values().toArray();
127 try {
128 for ( int i = 0; i < rows.length; i++ ){
129 Field f = rows[i].getClass().getField( field );
130 try {
131 Object val=f.get(rows[i]);
132 //Logger.logDebug( "TextDB.get("+className+","+field+","+value+")="+val );
133 if ( val != null && val.equals( value ) ) {
134 ret = rows[i];
135 //Logger.logDebug( "TextDB.get("+className+","+field+","+value+")="+ret );
136 break;
137 }
138 } catch ( NullPointerException nulle ) {
139 throw new DBException( "Field not found: "+className+"."+field+"=="+value );
140 } catch ( IllegalAccessException acce ) {
141 throw new DBException( "Field not found: "+className+"."+field+"=="+value );
142 }
143 }
144 if ( ret == null ) {
145 ret = db.get( className, field, value );
146 if ( ret != null ) {
147 _put( ret );
148 } else {
149 throw new DBException( "Object not found: "+className+"."+field+"=="+value );
150 }
151 }
152 } catch ( NoSuchFieldException e ) {
153 throw new DBException( e.getMessage() );
154 }
155 }
156 return ret;
157 }
158
159 /**
160 Returns all members of the class
161 */
162 public Object[] getAll( String className ) throws Exception {
163 Object[] ret = null;
164 TreeMap table = (TreeMap) tables.get( className );
165 if ( table == null ) {
166 throw new DBException( "Table " + className + " does not exist" );
167 } else {
168 ret = table.values().toArray();
169 }
170 return ret;
171 }
172
173 /**
174 Returns Object[] of <b>className</b> class having <b>field</b> == <b>value</b> <br>
175 TODO: map calls on underlying DB
176 */
177 public Object[] getRange( String className, String field, Object value )
178 throws Exception
179 {
180 Object[] ret = new Object[0];
181 TreeMap table = (TreeMap) tables.get( className );
182 if ( table == null ) {
183 throw new DBException( "Table " + className + " does not exist" );
184 } else {
185 Object[] rows = table.values().toArray();
186 try {
187 //Vector v = new Vector();
188 LinkedList v = new LinkedList();
189 for ( int i = 0; i < rows.length; i++ ){
190 if ( rows[i].getClass().getField( field ).get( rows[i] ).equals( value ) ) {
191 v.add( rows[i] );
192 }
193 }
194 ret = v.toArray();
195 } catch ( NoSuchFieldException e ) {
196 throw new DBException( e.getMessage() );
197 } catch ( IllegalAccessException e ) {
198 throw new DBException( e.getMessage() );
199 } catch ( NullPointerException e ) {
200 }
201 }
202 return ret;
203 }
204 /**
205 Returns Object[] between o1 and o2
206 Class must have comparator() method to be searchable.<br>
207 TODO: map calls to underlying DB!
208 */
209 public Object[] getRange( Object o1, Object o2 )
210 throws Exception
211 {
212 Object[] ret = null;
213 try {
214 TreeMap table = (TreeMap) tables.get( getClassName(o1) );
215 VRObjectComparator comparator = (VRObjectComparator) o1.getClass().getMethod( "comparator", null ).invoke( o1, null );
216 Iterator it = table.values().iterator();
217 //Vector res = new Vector();
218 LinkedList res = new LinkedList();
219 while ( it.hasNext() ) {
220 Object element = it.next();
221 if ( comparator.compare( o1, element ) < 0 && comparator.compare( element, o2 ) < 0 ) {
222 res.add( element );
223 }
224 }
225 ret = res.toArray();
226 } catch ( NoSuchMethodException e ) {
227 throw new DBException( "Class "+o1.getClass().getName()+" needs a VRObjectComparator to be indexed" );
228 } catch ( IllegalAccessException e ) {
229 throw new DBException( "Could not access comparator()" );
230 } catch ( InvocationTargetException e ) {
231 throw new DBException( "InvocationTargetException while creating comparator()" );
232 }
233 return ret;
234 }
235
236 public String getClassName( Object obj ) {
237 String name = ((VRObject)obj).getClassName();
238 return name;
239 }
240
241 /**
242 Stores obj into cache
243 */
244 private synchronized void _put( Object obj ) throws Exception
245 {
246 TreeMap table = (TreeMap) tables.get( getClassName(obj) );
247 if ( table == null ) {
248 table = createTable( obj );
249 }
250 long id = obj.getClass().getField("db_id").getLong( obj );
251 if ( id == 0 ) {
252 // new object
253 if( table.size()>0 ) {
254 id = ((Long) table.lastKey()).longValue()+1;
255 } else {
256 id = 1;
257 }
258 obj.getClass().getField("db_id").setLong( obj, id );
259 }
260 //Logger.logDebug( "TextDB.put( "+getClassName(obj)+", "+obj.getClass().getName()+" "+id+")" );
261 table.put( new Long( id ), obj );
262 }
263 /**
264 Stores obj into database
265 */
266 public void put( Object obj ) throws Exception {
267 db.put( obj );
268 _put( obj );
269 }
270
271 /**
272 This method only passes request to underlying database.
273 */
274 public void update( Request r ) throws Exception {
275 db.update( r );
276 _put( r.object );
277 }
278
279 /** Does <b>table</b> exist? **/
280 public boolean tableExists( String table ) {
281 return ( tables.containsKey( table ) );
282 }
283
284 private TreeMap createTable( Object obj ) throws DBException
285 {
286 String table = getClassName( obj );
287 Logger.logDebug( "Creating table "+table+ " (package "+Util.getPackageName(obj)+")" ); // produces NPE without packages
288 TreeMap ret = new TreeMap();
289 if ( tables.containsKey( table ) ) {
290 throw new DBException ( "Table " + table + " already exists" );
291 } else {
292 tables.put( table, ret );
293 }
294 return ret;
295 }
296 }