001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.record;
025:
026: import jacareto.system.Environment;
027:
028: import java.util.Iterator;
029: import java.util.Vector;
030:
031: /**
032: * This class stores record elements in an object of type <code>java.util.Vector</code>.
033: *
034: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
035: * @version 1.01
036: */
037: public class VectorRecord extends RandomAccessRecord {
038: /** The internal vector. */
039: private Vector vector;
040:
041: /** Indicates whether or not the vector is opened. */
042: private boolean isOpen;
043:
044: /** The name of the record. */
045: private String recordName;
046:
047: /**
048: * The constructor. The name of the record is an empty string.
049: *
050: * @param env the environment
051: * @param recordName the name of the record
052: */
053: public VectorRecord(Environment env, String recordName) {
054: super (env);
055: this .vector = new Vector(50, 50);
056: this .recordName = recordName;
057: this .isOpen = false;
058: }
059:
060: /**
061: * The constructor. The name of the record is an empty string.
062: *
063: * @param env the environment
064: */
065: public VectorRecord(Environment env) {
066: this (env, "");
067: }
068:
069: public Vector getVector() {
070: return this .vector;
071: }
072:
073: /**
074: * Makes this record get ready for recording. Should throw a {@link RecordException} if the
075: * record is already open, for example.
076: *
077: * @throws RecordException if an error has occurred
078: */
079: public void open() throws RecordException {
080: if (isOpen()) {
081: throw new RecordException(language
082: .getString("Record.Error.AlreadyOpen"));
083: }
084:
085: isOpen = true;
086: fireRecordChange(new RecordChangeEvent(
087: RecordChangeEvent.RECORD_OPENED, null, null));
088: }
089:
090: /**
091: * Finishes recording. Should throw a {@link RecordException} if the record is not open, for
092: * example.
093: *
094: * @throws RecordException if an error has occurred
095: */
096: public void close() throws RecordException {
097: if (!isOpen()) {
098: throw new RecordException(language
099: .getString("Record.Error.CloseNotOpen"));
100: }
101:
102: isOpen = false;
103: fireRecordChange(new RecordChangeEvent(
104: RecordChangeEvent.RECORD_CLOSED, null, null));
105: }
106:
107: /**
108: * Returns <code>true</code> if the record is open, otherwise false.
109: *
110: * @return DOCUMENT ME!
111: */
112: public boolean isOpen() {
113: return isOpen;
114: }
115:
116: /**
117: * Returns the name of the record.
118: *
119: * @return the name as String
120: */
121: public String getRecordName() {
122: return recordName;
123: }
124:
125: /**
126: * Sets the name of the record.
127: *
128: * @param recordName DOCUMENT ME!
129: */
130: public void setRecordName(String recordName) {
131: this .recordName = recordName;
132: fireRecordChange(new RecordChangeEvent(
133: RecordChangeEvent.RECORD_NAME_CHANGED, null, null));
134: }
135:
136: /**
137: * Returns the number of elements stored in the record.
138: *
139: * @return DOCUMENT ME!
140: *
141: * @throws RecordException if an error has occurred
142: */
143: public int size() throws RecordException {
144: if (!isOpen()) {
145: throw new RecordException(language
146: .getString("Record.Error.SizeNotOpen"));
147: }
148:
149: return vector.size();
150: }
151:
152: /**
153: * Returns whether this record has at least one element or not. Should throw a {@link
154: * RecordException} if the record is not open, for example.
155: *
156: * @return <code>true</code> if this record is empty, otherwise <code>false</code>
157: *
158: * @throws RecordException if an error has occurred
159: */
160: public boolean isEmpty() throws RecordException {
161: return size() == 0;
162: }
163:
164: /**
165: * Records an object. The object will be added to the end of the record. Should throw a {@link
166: * RecordException} if the record is not open, for example.
167: *
168: * @param recordable the recordable to be recorded
169: *
170: * @throws RecordException if an error has occurred
171: */
172: public void record(Recordable recordable) throws RecordException {
173: if (!isOpen()) {
174: throw new RecordException(language
175: .getString("Record.Error.RecordNotOpen"));
176: }
177:
178: vector.add(recordable);
179: recordable.addStructureElementListener(this );
180:
181: Recordable[] addedRecordables = new Recordable[1];
182: addedRecordables[0] = recordable;
183:
184: int[] addedIndices = new int[1];
185: addedIndices[0] = size() - 1;
186: fireRecordChange(new RecordChangeEvent(
187: RecordChangeEvent.RECORDABLES_ADDED, addedRecordables,
188: addedIndices));
189:
190: //System.out.println ("RECORDABLE ADDED: " + recordable.getClass().getName());
191: }
192:
193: /**
194: * Records all elements contained in the array
195: *
196: * @param recordables the recordables to be added
197: *
198: * @throws RecordException if an error has occurred
199: */
200: public void record(Recordable[] recordables) throws RecordException {
201: if (!isOpen()) {
202: throw new RecordException(language
203: .getString("Record.Error.RecordNotOpen"));
204: }
205:
206: int[] addedIndices = new int[recordables.length];
207:
208: for (int i = 0; i < recordables.length; i++) {
209: vector.add(recordables[i]);
210: addedIndices[i] = size() - 1;
211: recordables[i].addStructureElementListener(this );
212: }
213:
214: fireRecordChange(new RecordChangeEvent(
215: RecordChangeEvent.RECORDABLES_ADDED, recordables,
216: addedIndices));
217: }
218:
219: /**
220: * Returns the record element at position <code>i</code>.
221: *
222: * @param i the index
223: *
224: * @return the recordable at index <code>i</code>
225: *
226: * @throws RecordException if <code>i</code> is out of range, or the record is not opened
227: */
228: public Recordable get(int i) throws RecordException {
229: if (!isOpen()) {
230: throw new RecordException(language
231: .getString("Record.Error.GetNotOpen"));
232: }
233:
234: try {
235: return (Recordable) vector.get(i);
236: } catch (ArrayIndexOutOfBoundsException e) {
237: throw new RecordException(language
238: .getString("Record.Error.InvalidIndex"));
239: }
240: }
241:
242: /**
243: * <p>
244: * Inserts a record element at the position with index <code>i</code>. Each recordable in this
245: * record with an index greater or equal to the specified index is shifted upward to have an
246: * index one greater than the value it had previously.
247: * </p>
248: *
249: * <p>
250: * The index must be greater than or equal to zero and less than or equal to the size of the
251: * record. If it is equal to the current size of the record, it will be appended to it.
252: * </p>
253: *
254: * <p>
255: * Should throw a {@link RecordException} if the record is not open or the index is invalid,
256: * for example.
257: * </p>
258: *
259: * @param recordable the recordable to add
260: * @param index the index to insert at
261: *
262: * @throws RecordException if an error has occurred
263: */
264: public void insert(Recordable recordable, int index)
265: throws RecordException {
266: if (!isOpen()) {
267: throw new RecordException(language
268: .getString("Record.Error.InsertNotOpen"));
269: }
270:
271: try {
272: vector.add(index, recordable);
273: recordable.addStructureElementListener(this );
274:
275: Recordable[] addedRecordables = new Recordable[1];
276: addedRecordables[0] = recordable;
277:
278: int[] addedIndices = new int[1];
279: addedIndices[0] = index;
280: fireRecordChange(new RecordChangeEvent(
281: RecordChangeEvent.RECORDABLES_INSERTED,
282: addedRecordables, addedIndices));
283: } catch (ArrayIndexOutOfBoundsException e) {
284: throw new RecordException(language
285: .getString("Record.Error.InvalidIndex"));
286: }
287: }
288:
289: /**
290: * <p>
291: * Inserts the given records element at the position with index <code>i</code>. Each recordable
292: * in this record with an index greater or equal to the specified index is shifted upward to
293: * have an index one greater than the value it had previously.
294: * </p>
295: *
296: * <p>
297: * The index must be greater than or equal to zero and less than or equal to the size of the
298: * record. If it is equal to the current size of the record, it will be appended to it.
299: * </p>
300: *
301: * <p>
302: * Should throw a {@link RecordException} if the record is not open or the index is invalid,
303: * for example.
304: * </p>
305: *
306: * @param recordables the recordable to add
307: * @param index the index to insert at
308: *
309: * @throws RecordException if an error has occurred
310: */
311: public void insert(Recordable[] recordables, int index)
312: throws RecordException {
313: if (!isOpen()) {
314: throw new RecordException(language
315: .getString("Record.Error.InsertNotOpen"));
316: }
317:
318: try {
319: int indexToAdd = index;
320: int[] addedIndices = new int[recordables.length];
321:
322: for (int i = 0; i < recordables.length; i++) {
323: vector.add(indexToAdd, recordables[i]);
324: recordables[i].addStructureElementListener(this );
325: addedIndices[i] = indexToAdd;
326: indexToAdd++;
327: }
328:
329: fireRecordChange(new RecordChangeEvent(
330: RecordChangeEvent.RECORDABLES_INSERTED,
331: recordables, addedIndices));
332: } catch (ArrayIndexOutOfBoundsException e) {
333: throw new RecordException(language
334: .getString("Record.Error.InvalidIndex"));
335: }
336: }
337:
338: /**
339: * <p>
340: * Removes a record element at the position with index <code>i</code>. Each recordable in this
341: * record with an index greater than or equal to the specified index is shifted downward to
342: * have an index one smaller than the value it had previously.
343: * </p>
344: *
345: * <p>
346: * The index must be greater or equal zero and less than the size of the record.
347: * </p>
348: *
349: * <p>
350: * Should throw a {@link RecordException} if the record is not open or the index is invalid,
351: * for example.
352: * </p>
353: *
354: * @param index the index of the recordable to remove
355: *
356: * @throws RecordException if an error has occurred
357: */
358: public void remove(int index) throws RecordException {
359: if (!isOpen()) {
360: throw new RecordException(language
361: .getString("Record.Error.RemoveNotOpen"));
362: }
363:
364: try {
365: Recordable recordable = get(index);
366: recordable.removeStructureElementListener(this );
367: vector.remove(index);
368:
369: Recordable[] remRecordables = new Recordable[1];
370: remRecordables[0] = recordable;
371:
372: int[] remIndices = new int[1];
373: remIndices[0] = index;
374: fireRecordChange(new RecordChangeEvent(
375: RecordChangeEvent.RECORDABLES_REMOVED,
376: remRecordables, remIndices));
377: } catch (ArrayIndexOutOfBoundsException e) {
378: throw new RecordException(language
379: .getString("Record.Error.InvalidIndex"));
380: }
381: }
382:
383: /**
384: * <p>
385: * Removes a specified record element.
386: * </p>
387: *
388: * @param recordable the element to remove
389: *
390: * @return index of removed element or -1 if not successful
391: *
392: * @throws RecordException if an error has occurred
393: */
394: public int remove(Recordable recordable) throws RecordException {
395: if (!isOpen()) {
396: throw new RecordException(language
397: .getString("Record.Error.RemoveNotOpen"));
398: }
399:
400: if (vector.contains(recordable)) {
401: Recordable[] remRecordables = new Recordable[1];
402: remRecordables[0] = recordable;
403:
404: int[] remIndices = new int[1];
405: remIndices[0] = vector.indexOf(recordable);
406:
407: recordable.removeStructureElementListener(this );
408: vector.removeElement(recordable);
409: fireRecordChange(new RecordChangeEvent(
410: RecordChangeEvent.RECORDABLES_REMOVED,
411: remRecordables, remIndices));
412:
413: return remIndices[0];
414: }
415:
416: return -1;
417: }
418:
419: /**
420: * <p>
421: * Removes a specified record elements.
422: * </p>
423: *
424: * @param recordables the elements to remove
425: *
426: * @throws RecordException if an error has occurred
427: */
428: public void remove(Recordable[] recordables) throws RecordException {
429: if (!isOpen()) {
430: throw new RecordException(language
431: .getString("Record.Error.RemoveNotOpen"));
432: }
433:
434: int[] remIndices = new int[recordables.length];
435:
436: for (int i = recordables.length - 1; i >= 0; i--) {
437: Recordable recordable = recordables[i];
438:
439: if (vector.contains(recordable)) {
440: remIndices[i] = vector.indexOf(recordable);
441: recordable.removeStructureElementListener(this );
442: vector.removeElement(recordable);
443: }
444: }
445:
446: fireRecordChange(new RecordChangeEvent(
447: RecordChangeEvent.RECORDABLES_REMOVED, recordables,
448: remIndices));
449: }
450:
451: /**
452: * Returns an iterator on the recorded elements. Should throw a {@link RecordException} if the
453: * record is not open, for example.
454: *
455: * @return an iterator
456: *
457: * @throws RecordException if an error has occurred
458: */
459: public Iterator iterator() throws RecordException {
460: if (!isOpen()) {
461: throw new RecordException(language
462: .getString("Record.Error.IteratorNotOpen"));
463: }
464:
465: return vector.iterator();
466: }
467:
468: /**
469: * Removes all elements from the record. After calling this method the record is empty. Should
470: * throw a RecordException if the record is not open, for example.
471: *
472: * @throws RecordException if an error has occurred
473: */
474: public void clear() throws RecordException {
475: if (!isOpen()) {
476: throw new RecordException(language
477: .getString("Record.Error.ClearNotOpen"));
478: }
479:
480: Iterator it = vector.iterator();
481:
482: while (it.hasNext()) {
483: ((Recordable) it.next())
484: .removeStructureElementListener(this );
485: }
486:
487: vector.clear();
488: fireRecordChange(new RecordChangeEvent(
489: RecordChangeEvent.RECORD_CLEARED, null, null));
490: }
491:
492: /**
493: * Returns an array with all recordables.
494: *
495: * @return DOCUMENT ME!
496: *
497: * @throws RecordException if an error has occured
498: */
499: public Recordable[] toArray() throws RecordException {
500: if (!isOpen()) {
501: throw new RecordException(language
502: .getString("Record.Error.ToArrayNotOpen"));
503: }
504:
505: Object[] tmp = vector.toArray();
506: Recordable[] result = new Recordable[tmp.length];
507:
508: for (int i = 0; i < tmp.length; i++) {
509: result[i] = (Recordable) tmp[i];
510: }
511:
512: return result;
513: }
514:
515: /**
516: * Returns the index of a specified recordable.
517: *
518: * @param recordable the recordable
519: *
520: * @return the index of the recordable, or -1 if it is not contained
521: *
522: * @throws RecordException if an error has occured
523: */
524: public int getIndex(Recordable recordable) throws RecordException {
525: if (!isOpen()) {
526: throw new RecordException(language
527: .getString("Record.Error.GetIndexNotOpen"));
528: }
529:
530: return vector.indexOf(recordable);
531: }
532: }
|