/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ import java.io.OutputStream; import java.io.InputStream; import java.io.DataOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; /** *

This class contains data for a single Palm database for use during * a conversion process.

* *

It contains zero or more Record objects stored in an * array. The index of the Record object in the array is * the record id or number for that specific Record object. * Note that this class does not check for maximum number of records * allowable in an actual pdb.

* *

This class also contains the pdb name associated with the Palm database * it represents. A pdb name consists of 32 bytes of a certain encoding * (extended ASCII in this case).

* *

The non default constructors take in a name parameter which may not * be the exact pdb name to be used. The name parameter in * String or byte[] are converted to an exact * NAME_LENGTH byte array. If the length of the name is less * than NAME_LENGTH, it is padded with '\0' characters. If it * is more, it gets truncated. The last character in the resulting byte * array is always a '\0' character. The resulting byte array is stored in * bName, and a corresponding String object sName * that contains characters without the '\0' characters.

* *

The {@link #write write} method is called within the * {@link zensync.util.palm.PalmDBSet#write PalmDBSet.write} method * for writing out its data to the OutputStream object.

* *

The {@link #read read} method is called within the * {@link zensync.util.palm.PalmDBSet#read PalmDBSet.read} method * for reading in its data from the InputStream object.

* * @author Akhil Arora, Herbie Ong * @see PalmDBSet * @see Record */ public final class PalmDB { /** number of bytes for the name field in the pdb */ public final static int NAME_LENGTH = 32; /** list of Record objects */ private Record[] records; /** pdb name in bytes */ private byte[] bName = null; /** pdb name in String */ private String sName = null; /** * Default constructor for use after a read(). */ public PalmDB() { records = new Record[0]; } /** * Constructor to create object with Record objects. * recs.length can be zero for an empty pdb. * * @param name suggested pdb name in String * @param recs array of Record objects * @throws NullPointerException if recs is null */ public PalmDB(String name, Record[] recs) throws UnsupportedEncodingException { this(name.getBytes(PDBUtil.ENCODING), recs); } /** * Constructor to create object with Record objects. * recs.length can be zero for an empty pdb. * * @param name suggested pdb name in byte array * @param recs array of Record objects * @throws NullPointerException if recs is null */ public PalmDB(byte[] name, Record[] recs) throws UnsupportedEncodingException { store(name); records = new Record[recs.length]; System.arraycopy(recs, 0, records, 0, recs.length); } /** * This private method is mainly used by the constructors above. * to store bytes into name and also create a String representation. * and also by the read method. * * TODO: Note that this method assumes that the byte array parameter * contains one character per byte, else it would truncate * improperly. * * @param bytes pdb name in byte array * @throws UnsupportedEncodingException if ENCODING is not supported */ private void store(byte[] bytes) throws UnsupportedEncodingException { // note that this will initialize all bytes in name to 0. bName = new byte[NAME_LENGTH]; // determine minimum length to copy over from bytes to bName. // Note that the last byte in bName has to be '\0'. int lastIndex = NAME_LENGTH - 1; int len = (bytes.length < lastIndex)? bytes.length: lastIndex; int i; for (i = 0; i < len; i++) { if (bytes[i] == 0) { break; } bName[i] = bytes[i]; } // set sName, no need to include the '\0' character. sName = new String(bName, 0, i, PDBUtil.ENCODING); } /** * Return the number of records contained in this * pdb PalmDB object. * * @return int number of Record objects */ public int getRecordCount() { return records.length; } /** * Return the specific Record object associated * with the record number. * * @param index record index number * @return Record the Record object in the specified index * @throws ArrayIndexOutOfBoundsException if index is out of bounds */ public Record getRecord(int index) { return records[index]; } /** * Return the list of Record objects * * @return Record[] the list of Record objects */ public Record[] getRecords() { return records; } /** * Return the PDBName associated with this object in String * * @return String pdb name in String */ public String getPDBNameString() { return sName; } /** * Return the PDBName associated with this object * in byte array of exact length of 32 bytes. * * @return byte[] pdb name in byte[] of length 32. */ public byte[] getPDBNameBytes() { return bName; } /** * Write out the number of records followed by what * will be written out by each Record object. * * @param os the stream to write the object to * @throws IOException if any I/O error occurs */ public void write(OutputStream os) throws IOException { DataOutputStream out = new DataOutputStream(os); // write out pdb name out.write(bName); // write out 2 bytes for number of records out.writeShort(records.length); // let each Record object write out its own info. for (int i = 0; i < records.length; i++) records[i].write(out); } /** * Read the necessary data to create a pdb from * the input stream. * * @param is the stream to read data from in order * to restore the object * @throws IOException if any I/O error occurs */ public void read(InputStream is) throws IOException { DataInputStream in = new DataInputStream(is); // read in the pdb name. byte[] bytes = new byte[NAME_LENGTH]; in.readFully(bytes); store(bytes); // read in number of records int nrec = in.readUnsignedShort(); records = new Record[nrec]; // read in the Record infos for (int i = 0; i < nrec; i++) { records[i] = new Record(); records[i].read(in); } } /** * Override equals method of Object. * * 2 PalmDB objects are equal if they contain the same information, * i.e. pdb name and records. * * This is used primarily for testing purposes only for now. * * @param obj a PalmDB object to compare with * @return boolean true if obj is equal to this, else false. */ public boolean equals(Object obj) { boolean bool = false; if (obj instanceof PalmDB) { PalmDB pdb = (PalmDB) obj; checkLabel: { // compare sName if (!sName.equals(pdb.sName)) { break checkLabel; } // compare bName if (bName.length != pdb.bName.length) { break checkLabel; } for (int i = 0; i < bName.length; i++) { if (bName[i] != pdb.bName[i]) { break checkLabel; } } // compare each Record if (records.length != pdb.records.length) { break checkLabel; } for (int i = 0; i < records.length; i++) { if (!records[i].equals(pdb.records[i])) { break checkLabel; } } // all checks done bool = true; } } return bool; } }