Source code: javax/microedition/rms/RecordStore.java
1 /*
2 * MicroEmulator
3 * Copyright (C) 2001 Bartek Teodorczyk <barteo@it.pl>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 package javax.microedition.rms;
21
22 import java.util.Enumeration;
23 import java.util.Hashtable;
24 import java.util.Vector;
25
26
27 public class RecordStore
28 {
29 /**
30 * @associates RecordStore
31 */
32 private static Hashtable recordStores = new Hashtable();
33
34 private String name;
35 private boolean open = false;
36 private int version = 0;
37 private long lastModified = 0;
38 private int nextRecordID = 1;
39
40 /**
41 * @associates RecordListener
42 */
43 private Vector recordListeners = new Vector();
44 private Hashtable records = new Hashtable();
45
46
47 private RecordStore(String name)
48 {
49 this.name = name;
50 }
51
52
53 public static void deleteRecordStore(String recordStoreName)
54 throws RecordStoreException, RecordStoreNotFoundException
55 {
56 RecordStore recordStore = (RecordStore) recordStores.get(recordStoreName);
57 if (recordStore == null) {
58 throw new RecordStoreNotFoundException();
59 }
60 if (recordStore.open) {
61 throw new RecordStoreException();
62 }
63
64 recordStores.remove(recordStoreName);
65 }
66
67
68 public static RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary)
69 throws RecordStoreException, RecordStoreFullException, RecordStoreNotFoundException
70 {
71 RecordStore recordStore = (RecordStore) recordStores.get(recordStoreName);
72 if (recordStore == null) {
73 if (!createIfNecessary) {
74 throw new RecordStoreNotFoundException();
75 }
76 recordStore = new RecordStore(recordStoreName);
77 recordStores.put(recordStoreName, recordStore);
78 }
79 recordStore.open = true;
80
81 return recordStore;
82 }
83
84
85 public void closeRecordStore()
86 throws RecordStoreNotOpenException, RecordStoreException
87 {
88 if (!open) {
89 throw new RecordStoreNotOpenException();
90 }
91
92 recordListeners.removeAllElements();
93 open = false;
94 }
95
96
97 public static String[] listRecordStores()
98 {
99 String[] result = new String[recordStores.size()];
100
101 int i = 0;
102 for (Enumeration e = recordStores.keys(); e.hasMoreElements(); ) {
103 result[i] = (String) e.nextElement();
104 i++;
105 }
106
107 return result;
108 }
109
110
111 public String getName()
112 {
113 return name;
114 }
115
116
117 public int getVersion()
118 throws RecordStoreNotOpenException
119 {
120 if (!open) {
121 throw new RecordStoreNotOpenException();
122 }
123
124 synchronized (this) {
125 return version;
126 }
127 }
128
129
130 public int getNumRecords()
131 throws RecordStoreNotOpenException
132 {
133 if (!open) {
134 throw new RecordStoreNotOpenException();
135 }
136
137 synchronized (this) {
138 return records.size();
139 }
140 }
141
142
143 public int getSizeAvailable()
144 {
145 return (int) Runtime.getRuntime().freeMemory();
146 }
147
148
149 public long getLastModified()
150 throws RecordStoreNotOpenException
151 {
152 if (!open) {
153 throw new RecordStoreNotOpenException();
154 }
155
156 synchronized (this) {
157 return lastModified;
158 }
159 }
160
161
162 public void addRecordListener(RecordListener listener)
163 {
164 if (!recordListeners.contains(listener)) {
165 recordListeners.addElement(listener);
166 }
167 }
168
169
170 public void removeRecordListener(RecordListener listener)
171 {
172 recordListeners.removeElement(listener);
173 }
174
175
176 public int getNextRecordID()
177 throws RecordStoreNotOpenException, RecordStoreException
178 {
179 if (!open) {
180 throw new RecordStoreNotOpenException();
181 }
182
183 synchronized (this) {
184 return nextRecordID;
185 }
186 }
187
188
189 public int addRecord(byte[] data, int offset, int numBytes)
190 throws RecordStoreNotOpenException, RecordStoreException, RecordStoreFullException
191 {
192 if (!open) {
193 throw new RecordStoreNotOpenException();
194 }
195 if (data == null && numBytes > 0) {
196 throw new NullPointerException();
197 }
198
199 byte[] recordData = new byte[numBytes];
200 if (data != null) {
201 System.arraycopy(data, offset, recordData, 0, numBytes);
202 }
203
204 int curRecordID;
205 synchronized (this) {
206 records.put(new Integer(nextRecordID), recordData);
207 version++;
208 curRecordID = nextRecordID;
209 nextRecordID++;
210 lastModified = System.currentTimeMillis();
211 }
212
213 fireAddedRecordListener(curRecordID);
214
215 return curRecordID;
216 }
217
218
219 public void deleteRecord(int recordId)
220 throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
221 {
222 if (!open) {
223 throw new RecordStoreNotOpenException();
224 }
225
226 synchronized (this) {
227 if (records.remove(new Integer(recordId)) == null) {
228 throw new InvalidRecordIDException();
229 }
230 version++;
231 lastModified = System.currentTimeMillis();
232 }
233
234 fireDeletedRecordListener(recordId);
235 }
236
237
238 public int getRecordSize(int recordId)
239 throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
240 {
241 if (!open) {
242 throw new RecordStoreNotOpenException();
243 }
244
245 synchronized (this) {
246 byte[] data = (byte[]) records.get(new Integer(recordId));
247 if (data == null) {
248 throw new InvalidRecordIDException();
249 }
250
251 return data.length;
252 }
253 }
254
255
256 public int getRecord(int recordId, byte[] buffer, int offset)
257 throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
258 {
259 int recordSize;
260 synchronized (this) {
261 recordSize = getRecordSize(recordId);
262 System.arraycopy(records.get(new Integer(recordId)), 0, buffer, offset, recordSize);
263 }
264
265 return recordSize;
266 }
267
268
269 public byte[] getRecord(int recordId)
270 throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
271 {
272 byte[] data;
273
274 synchronized (this) {
275 data = new byte[getRecordSize(recordId)];
276 getRecord(recordId, data, 0);
277 }
278
279 return data;
280 }
281
282
283 public void setRecord(int recordId, byte[] newData, int offset, int numBytes)
284 throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException, RecordStoreFullException
285 {
286 if (!open) {
287 throw new RecordStoreNotOpenException();
288 }
289
290 byte[] recordData = new byte[numBytes];
291 System.arraycopy(newData, offset, recordData, 0, numBytes);
292
293 synchronized (this) {
294 Integer id = new Integer(recordId);
295 if (records.remove(id) == null) {
296 throw new InvalidRecordIDException();
297 }
298 records.put(id, recordData);
299 version++;
300 lastModified = System.currentTimeMillis();
301 }
302
303 fireChangedRecordListener(recordId);
304 }
305
306
307
308 public RecordEnumeration enumerateRecords(RecordFilter filter, RecordComparator comparator, boolean keepUpdated)
309 throws RecordStoreNotOpenException
310 {
311 if (!open) {
312 throw new RecordStoreNotOpenException();
313 }
314
315 return new RecordEnumerationImpl(filter, comparator, keepUpdated);
316 }
317
318
319 private void fireAddedRecordListener(int recordId)
320 {
321 for (Enumeration e = recordListeners.elements(); e.hasMoreElements(); ) {
322 ((RecordListener) e.nextElement()).recordAdded(this, recordId);
323 }
324 }
325
326
327 private void fireChangedRecordListener(int recordId)
328 {
329 for (Enumeration e = recordListeners.elements(); e.hasMoreElements(); ) {
330 ((RecordListener) e.nextElement()).recordChanged(this, recordId);
331 }
332 }
333
334
335 private void fireDeletedRecordListener(int recordId)
336 {
337 for (Enumeration e = recordListeners.elements(); e.hasMoreElements(); ) {
338 ((RecordListener) e.nextElement()).recordDeleted(this, recordId);
339 }
340 }
341
342
343 class RecordEnumerationImpl implements RecordEnumeration
344 {
345
346 RecordFilter filter;
347 RecordComparator comparator;
348 boolean keepUpdated;
349
350 /**
351 * @associates EnumerationRecord
352 */
353 Vector enumerationRecords = new Vector();
354 int currentRecord;
355
356
357 RecordListener recordListener = new RecordListener()
358 {
359
360 public void recordAdded(RecordStore recordStore, int recordId)
361 {
362 rebuild();
363 }
364
365
366 public void recordChanged(RecordStore recordStore, int recordId)
367 {
368 rebuild();
369 }
370
371
372 public void recordDeleted(RecordStore recordStore, int recordId)
373 {
374 rebuild();
375 }
376
377 };
378
379
380 RecordEnumerationImpl(RecordFilter filter, RecordComparator comparator, boolean keepUpdated)
381 {
382 this.filter = filter;
383 this.comparator = comparator;
384 this.keepUpdated = keepUpdated;
385
386 rebuild();
387
388 if (keepUpdated) {
389 addRecordListener(recordListener);
390 }
391 }
392
393
394 public int numRecords()
395 {
396 return enumerationRecords.size();
397 }
398
399
400 public byte[] nextRecord()
401 throws InvalidRecordIDException, RecordStoreNotOpenException, RecordStoreException
402 {
403 if (!open) {
404 throw new RecordStoreNotOpenException();
405 }
406
407 if (currentRecord >= numRecords()) {
408 throw new InvalidRecordIDException();
409 }
410
411 byte[] result = ((EnumerationRecord) enumerationRecords.elementAt(currentRecord)).value;
412 currentRecord++;
413
414 return result;
415 }
416
417
418 public int nextRecordId()
419 throws InvalidRecordIDException
420 {
421 if (currentRecord >= numRecords()) {
422 throw new InvalidRecordIDException();
423 }
424
425 int result = ((EnumerationRecord) enumerationRecords.elementAt(currentRecord)).recordId;
426 currentRecord++;
427
428 return result;
429 }
430
431
432
433 public byte[] previousRecord()
434 throws InvalidRecordIDException, RecordStoreNotOpenException, RecordStoreException
435 {
436 if (!open) {
437 throw new RecordStoreNotOpenException();
438 }
439 if (currentRecord < 0) {
440 throw new InvalidRecordIDException();
441 }
442
443 byte[] result = ((EnumerationRecord) enumerationRecords.elementAt(currentRecord)).value;
444 currentRecord--;
445
446 return result;
447 }
448
449
450 public int previousRecordId()
451 throws InvalidRecordIDException
452 {
453 if (currentRecord < 0) {
454 throw new InvalidRecordIDException();
455 }
456
457 int result = ((EnumerationRecord) enumerationRecords.elementAt(currentRecord)).recordId;
458 currentRecord--;
459
460 return result;
461 }
462
463
464 public boolean hasNextElement()
465 {
466 if (currentRecord == numRecords()) {
467 return false;
468 } else {
469 return true;
470 }
471 }
472
473
474 public boolean hasPreviousElement()
475 {
476 if (currentRecord == 0) {
477 return false;
478 } else {
479 return true;
480 }
481 }
482
483
484 public void reset()
485 {
486 currentRecord = 0;
487 }
488
489
490 public void rebuild()
491 {
492 enumerationRecords.removeAllElements();
493
494 int position;
495 for (Enumeration e = records.keys(); e.hasMoreElements(); ) {
496 Object key = e.nextElement();
497 if (filter != null && !filter.matches((byte[]) records.get(key))) {
498 continue;
499 }
500 byte[] tmp_data = (byte[]) records.get(key);
501 // here should be better sorting
502 if (comparator != null) {
503 for (position = 0; position < enumerationRecords.size(); position++) {
504 if (comparator.compare(tmp_data, (byte[]) enumerationRecords.elementAt(position))
505 == RecordComparator.FOLLOWS) {
506 break;
507 }
508 }
509 } else {
510 position = enumerationRecords.size();
511 }
512 enumerationRecords.insertElementAt(
513 new EnumerationRecord(((Integer) key).intValue(), tmp_data), position);
514 }
515 currentRecord = 0;
516 }
517
518
519 public void keepUpdated(boolean keepUpdated)
520 {
521 if (keepUpdated) {
522 if (!this.keepUpdated) {
523 rebuild();
524 addRecordListener(recordListener);
525 }
526 } else {
527 removeRecordListener(recordListener);
528 }
529
530 this.keepUpdated = keepUpdated;
531 }
532
533
534 public boolean isKeptUpdated()
535 {
536 return keepUpdated;
537 }
538
539
540 public void destroy()
541 {
542 }
543
544
545 class EnumerationRecord
546 {
547
548 int recordId;
549 byte[] value;
550
551
552 EnumerationRecord(int recordId, byte[] value)
553 {
554 this.recordId = recordId;
555 this.value = value;
556 }
557
558 }
559
560 }
561
562 }
563