1*04ea5bd4SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*04ea5bd4SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*04ea5bd4SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*04ea5bd4SAndrew Rist  * distributed with this work for additional information
6*04ea5bd4SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*04ea5bd4SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*04ea5bd4SAndrew Rist  * "License"); you may not use this file except in compliance
9*04ea5bd4SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*04ea5bd4SAndrew Rist  *
11*04ea5bd4SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*04ea5bd4SAndrew Rist  *
13*04ea5bd4SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*04ea5bd4SAndrew Rist  * software distributed under the License is distributed on an
15*04ea5bd4SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*04ea5bd4SAndrew Rist  * KIND, either express or implied.  See the License for the
17*04ea5bd4SAndrew Rist  * specific language governing permissions and limitations
18*04ea5bd4SAndrew Rist  * under the License.
19*04ea5bd4SAndrew Rist  *
20*04ea5bd4SAndrew Rist  *************************************************************/
21*04ea5bd4SAndrew Rist 
22*04ea5bd4SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir import java.io.OutputStream;
25cdf0e10cSrcweir import java.io.InputStream;
26cdf0e10cSrcweir import java.io.DataOutputStream;
27cdf0e10cSrcweir import java.io.DataInputStream;
28cdf0e10cSrcweir import java.io.IOException;
29cdf0e10cSrcweir import java.io.UnsupportedEncodingException;
30cdf0e10cSrcweir 
31cdf0e10cSrcweir /**
32cdf0e10cSrcweir  *  <p>This class contains data for a single Palm database for use during
33cdf0e10cSrcweir  *  a conversion process.</p>
34cdf0e10cSrcweir  *
35cdf0e10cSrcweir  *  <p>It contains zero or more <code>Record</code> objects stored in an
36cdf0e10cSrcweir  *  array. The index of the <code>Record</code> object in the array is
37cdf0e10cSrcweir  *  the record id or number for that specific <code>Record</code> object.
38cdf0e10cSrcweir  *  Note that this class does not check for maximum number of records
39cdf0e10cSrcweir  *  allowable in an actual pdb.</p>
40cdf0e10cSrcweir  *
41cdf0e10cSrcweir  *  <p>This class also contains the pdb name associated with the Palm database
42cdf0e10cSrcweir  *  it represents. A pdb name consists of 32 bytes of a certain encoding
43cdf0e10cSrcweir  *  (extended ASCII in this case).</p>
44cdf0e10cSrcweir  *
45cdf0e10cSrcweir  *  <p>The non default constructors take in a name parameter which may not
46cdf0e10cSrcweir  *  be the exact pdb name to be used.  The name parameter in
47cdf0e10cSrcweir  *  <code>String</code> or <code>byte[]</code> are converted to an exact
48cdf0e10cSrcweir  *  <code>NAME_LENGTH</code> byte array.  If the length of the name is less
49cdf0e10cSrcweir  *  than <code>NAME_LENGTH</code>, it is padded with '\0' characters.  If it
50cdf0e10cSrcweir  *  is more, it gets truncated.  The last character in the resulting byte
51cdf0e10cSrcweir  *  array is always a '\0' character.  The resulting byte array is stored in
52cdf0e10cSrcweir  *  <code>bName</code>, and a corresponding String object <code>sName</code>
53cdf0e10cSrcweir  *  that contains characters without the '\0' characters.</p>
54cdf0e10cSrcweir  *
55cdf0e10cSrcweir  *  <p>The {@link #write write} method is called within the
56cdf0e10cSrcweir  *  {@link zensync.util.palm.PalmDBSet#write PalmDBSet.write} method
57cdf0e10cSrcweir  *  for writing out its data to the <code>OutputStream</code> object.</p>
58cdf0e10cSrcweir  *
59cdf0e10cSrcweir  *  <p>The {@link #read read} method is called within the
60cdf0e10cSrcweir  *  {@link zensync.util.palm.PalmDBSet#read PalmDBSet.read} method
61cdf0e10cSrcweir  *  for reading in its data from the <code>InputStream</code> object.</p>
62cdf0e10cSrcweir  *
63cdf0e10cSrcweir  *  @author    Akhil Arora, Herbie Ong
64cdf0e10cSrcweir  *  @see    PalmDBSet
65cdf0e10cSrcweir  *  @see    Record
66cdf0e10cSrcweir  */
67cdf0e10cSrcweir 
68cdf0e10cSrcweir public final class PalmDB {
69cdf0e10cSrcweir 
70cdf0e10cSrcweir     /** number of bytes for the name field in the pdb */
71cdf0e10cSrcweir     public final static int NAME_LENGTH = 32;
72cdf0e10cSrcweir 
73cdf0e10cSrcweir     /** list of Record objects */
74cdf0e10cSrcweir     private Record[] records;
75cdf0e10cSrcweir 
76cdf0e10cSrcweir     /** pdb name in bytes */
77cdf0e10cSrcweir     private byte[] bName = null;
78cdf0e10cSrcweir 
79cdf0e10cSrcweir     /** pdb name in String */
80cdf0e10cSrcweir     private String sName = null;
81cdf0e10cSrcweir 
82cdf0e10cSrcweir 
83cdf0e10cSrcweir     /**
84cdf0e10cSrcweir      *  Default constructor for use after a read().
85cdf0e10cSrcweir      */
86cdf0e10cSrcweir 
PalmDB()87cdf0e10cSrcweir     public PalmDB() {
88cdf0e10cSrcweir 
89cdf0e10cSrcweir         records = new Record[0];
90cdf0e10cSrcweir     }
91cdf0e10cSrcweir 
92cdf0e10cSrcweir     /**
93cdf0e10cSrcweir      *  Constructor to create object with Record objects.
94cdf0e10cSrcweir      *  recs.length can be zero for an empty pdb.
95cdf0e10cSrcweir      *
96cdf0e10cSrcweir      *  @param   name    suggested pdb name in String
97cdf0e10cSrcweir      *  @param   recs    array of Record objects
98cdf0e10cSrcweir      *  @throws  NullPointerException    if recs is null
99cdf0e10cSrcweir      */
100cdf0e10cSrcweir 
PalmDB(String name, Record[] recs)101cdf0e10cSrcweir     public PalmDB(String name, Record[] recs)
102cdf0e10cSrcweir         throws UnsupportedEncodingException {
103cdf0e10cSrcweir 
104cdf0e10cSrcweir         this(name.getBytes(PDBUtil.ENCODING), recs);
105cdf0e10cSrcweir     }
106cdf0e10cSrcweir 
107cdf0e10cSrcweir     /**
108cdf0e10cSrcweir      *  Constructor to create object with Record objects.
109cdf0e10cSrcweir      *  recs.length can be zero for an empty pdb.
110cdf0e10cSrcweir      *
111cdf0e10cSrcweir      *  @param   name    suggested pdb name in byte array
112cdf0e10cSrcweir      *  @param   recs    array of Record objects
113cdf0e10cSrcweir      *  @throws  NullPointerException    if recs is null
114cdf0e10cSrcweir      */
115cdf0e10cSrcweir 
PalmDB(byte[] name, Record[] recs)116cdf0e10cSrcweir     public PalmDB(byte[] name, Record[] recs)
117cdf0e10cSrcweir         throws UnsupportedEncodingException {
118cdf0e10cSrcweir 
119cdf0e10cSrcweir         store(name);
120cdf0e10cSrcweir 
121cdf0e10cSrcweir         records = new Record[recs.length];
122cdf0e10cSrcweir         System.arraycopy(recs, 0, records, 0, recs.length);
123cdf0e10cSrcweir     }
124cdf0e10cSrcweir 
125cdf0e10cSrcweir     /**
126cdf0e10cSrcweir      *  This private method is mainly used by the constructors above.
127cdf0e10cSrcweir      *  to store bytes into name and also create a String representation.
128cdf0e10cSrcweir      *  and also by the read method.
129cdf0e10cSrcweir      *
130cdf0e10cSrcweir      *  TODO: Note that this method assumes that the byte array parameter
131cdf0e10cSrcweir      *  contains one character per byte, else it would truncate
132cdf0e10cSrcweir      *  improperly.
133cdf0e10cSrcweir      *
134cdf0e10cSrcweir      *  @param   bytes    pdb name in byte array
135cdf0e10cSrcweir      *  @throws   UnsupportedEncodingException    if ENCODING is not supported
136cdf0e10cSrcweir      */
137cdf0e10cSrcweir 
store(byte[] bytes)138cdf0e10cSrcweir     private void store(byte[] bytes) throws UnsupportedEncodingException {
139cdf0e10cSrcweir 
140cdf0e10cSrcweir         // note that this will initialize all bytes in name to 0.
141cdf0e10cSrcweir         bName = new byte[NAME_LENGTH];
142cdf0e10cSrcweir 
143cdf0e10cSrcweir         // determine minimum length to copy over from bytes to bName.
144cdf0e10cSrcweir         // Note that the last byte in bName has to be '\0'.
145cdf0e10cSrcweir 
146cdf0e10cSrcweir         int lastIndex = NAME_LENGTH - 1;
147cdf0e10cSrcweir 
148cdf0e10cSrcweir         int len = (bytes.length < lastIndex)? bytes.length: lastIndex;
149cdf0e10cSrcweir 
150cdf0e10cSrcweir         int i;
151cdf0e10cSrcweir 
152cdf0e10cSrcweir         for (i = 0; i < len; i++) {
153cdf0e10cSrcweir 
154cdf0e10cSrcweir             if (bytes[i] == 0) {
155cdf0e10cSrcweir                 break;
156cdf0e10cSrcweir             }
157cdf0e10cSrcweir 
158cdf0e10cSrcweir             bName[i] = bytes[i];
159cdf0e10cSrcweir         }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir         // set sName, no need to include the '\0' character.
162cdf0e10cSrcweir         sName = new String(bName, 0, i, PDBUtil.ENCODING);
163cdf0e10cSrcweir     }
164cdf0e10cSrcweir 
165cdf0e10cSrcweir     /**
166cdf0e10cSrcweir      *  Return the number of records contained in this
167cdf0e10cSrcweir      *  pdb PalmDB object.
168cdf0e10cSrcweir      *
169cdf0e10cSrcweir      *  @return  int    number of Record objects
170cdf0e10cSrcweir      */
171cdf0e10cSrcweir 
getRecordCount()172cdf0e10cSrcweir     public int getRecordCount() {
173cdf0e10cSrcweir 
174cdf0e10cSrcweir         return records.length;
175cdf0e10cSrcweir     }
176cdf0e10cSrcweir 
177cdf0e10cSrcweir     /**
178cdf0e10cSrcweir      *  Return the specific Record object associated
179cdf0e10cSrcweir      *  with the record number.
180cdf0e10cSrcweir      *
181cdf0e10cSrcweir      *  @param   index    record index number
182cdf0e10cSrcweir      *  @return  Record   the Record object in the specified index
183cdf0e10cSrcweir      *  @throws  ArrayIndexOutOfBoundsException    if index is out of bounds
184cdf0e10cSrcweir      */
185cdf0e10cSrcweir 
getRecord(int index)186cdf0e10cSrcweir     public Record getRecord(int index) {
187cdf0e10cSrcweir 
188cdf0e10cSrcweir         return records[index];
189cdf0e10cSrcweir     }
190cdf0e10cSrcweir 
191cdf0e10cSrcweir     /**
192cdf0e10cSrcweir      *  Return the list of Record objects
193cdf0e10cSrcweir      *
194cdf0e10cSrcweir      *  @return  Record[]   the list of Record objects
195cdf0e10cSrcweir      */
196cdf0e10cSrcweir 
getRecords()197cdf0e10cSrcweir     public Record[] getRecords() {
198cdf0e10cSrcweir 
199cdf0e10cSrcweir         return records;
200cdf0e10cSrcweir     }
201cdf0e10cSrcweir 
202cdf0e10cSrcweir     /**
203cdf0e10cSrcweir      *  Return the PDBName associated with this object in String
204cdf0e10cSrcweir      *
205cdf0e10cSrcweir      *  @return  String    pdb name in String
206cdf0e10cSrcweir      */
207cdf0e10cSrcweir 
getPDBNameString()208cdf0e10cSrcweir     public String getPDBNameString() {
209cdf0e10cSrcweir 
210cdf0e10cSrcweir         return sName;
211cdf0e10cSrcweir     }
212cdf0e10cSrcweir 
213cdf0e10cSrcweir     /**
214cdf0e10cSrcweir      *  Return the PDBName associated with this object
215cdf0e10cSrcweir      *  in byte array of exact length of 32 bytes.
216cdf0e10cSrcweir      *
217cdf0e10cSrcweir      *  @return  byte[]    pdb name in byte[] of length 32.
218cdf0e10cSrcweir      */
219cdf0e10cSrcweir 
getPDBNameBytes()220cdf0e10cSrcweir     public byte[] getPDBNameBytes() {
221cdf0e10cSrcweir 
222cdf0e10cSrcweir         return bName;
223cdf0e10cSrcweir     }
224cdf0e10cSrcweir 
225cdf0e10cSrcweir     /**
226cdf0e10cSrcweir      *  Write out the number of records followed by what
227cdf0e10cSrcweir      *  will be written out by each Record object.
228cdf0e10cSrcweir      *
229cdf0e10cSrcweir      *  @param   os    the stream to write the object to
230cdf0e10cSrcweir      *  @throws  IOException    if any I/O error occurs
231cdf0e10cSrcweir      */
232cdf0e10cSrcweir 
write(OutputStream os)233cdf0e10cSrcweir     public void write(OutputStream os) throws IOException {
234cdf0e10cSrcweir 
235cdf0e10cSrcweir         DataOutputStream out = new DataOutputStream(os);
236cdf0e10cSrcweir 
237cdf0e10cSrcweir         // write out pdb name
238cdf0e10cSrcweir         out.write(bName);
239cdf0e10cSrcweir 
240cdf0e10cSrcweir         // write out 2 bytes for number of records
241cdf0e10cSrcweir         out.writeShort(records.length);
242cdf0e10cSrcweir 
243cdf0e10cSrcweir         // let each Record object write out its own info.
244cdf0e10cSrcweir         for (int i = 0; i < records.length; i++)
245cdf0e10cSrcweir             records[i].write(out);
246cdf0e10cSrcweir     }
247cdf0e10cSrcweir 
248cdf0e10cSrcweir     /**
249cdf0e10cSrcweir      *  Read the necessary data to create a pdb from
250cdf0e10cSrcweir      *  the input stream.
251cdf0e10cSrcweir      *
252cdf0e10cSrcweir      *  @param   is    the stream to read data from in order
253cdf0e10cSrcweir      *                 to restore the object
254cdf0e10cSrcweir      *  @throws  IOException    if any I/O error occurs
255cdf0e10cSrcweir      */
256cdf0e10cSrcweir 
read(InputStream is)257cdf0e10cSrcweir     public void read(InputStream is) throws IOException {
258cdf0e10cSrcweir 
259cdf0e10cSrcweir         DataInputStream in = new DataInputStream(is);
260cdf0e10cSrcweir 
261cdf0e10cSrcweir         // read in the pdb name.
262cdf0e10cSrcweir         byte[] bytes = new byte[NAME_LENGTH];
263cdf0e10cSrcweir         in.readFully(bytes);
264cdf0e10cSrcweir         store(bytes);
265cdf0e10cSrcweir 
266cdf0e10cSrcweir         // read in number of records
267cdf0e10cSrcweir         int nrec = in.readUnsignedShort();
268cdf0e10cSrcweir         records = new Record[nrec];
269cdf0e10cSrcweir 
270cdf0e10cSrcweir         // read in the Record infos
271cdf0e10cSrcweir         for (int i = 0; i < nrec; i++) {
272cdf0e10cSrcweir 
273cdf0e10cSrcweir             records[i] = new Record();
274cdf0e10cSrcweir             records[i].read(in);
275cdf0e10cSrcweir         }
276cdf0e10cSrcweir     }
277cdf0e10cSrcweir 
278cdf0e10cSrcweir     /**
279cdf0e10cSrcweir      *  Override equals method of Object.
280cdf0e10cSrcweir      *
281cdf0e10cSrcweir      *  2 PalmDB objects are equal if they contain the same information,
282cdf0e10cSrcweir      *  i.e. pdb name and records.
283cdf0e10cSrcweir      *
284cdf0e10cSrcweir      *  This is used primarily for testing purposes only for now.
285cdf0e10cSrcweir      *
286cdf0e10cSrcweir      *  @param   obj    a PalmDB object to compare with
287cdf0e10cSrcweir      *  @return   boolean    true if obj is equal to this, else false.
288cdf0e10cSrcweir      */
289cdf0e10cSrcweir 
equals(Object obj)290cdf0e10cSrcweir     public boolean equals(Object obj) {
291cdf0e10cSrcweir 
292cdf0e10cSrcweir         boolean bool = false;
293cdf0e10cSrcweir 
294cdf0e10cSrcweir         if (obj instanceof PalmDB) {
295cdf0e10cSrcweir 
296cdf0e10cSrcweir             PalmDB pdb = (PalmDB) obj;
297cdf0e10cSrcweir 
298cdf0e10cSrcweir             checkLabel: {
299cdf0e10cSrcweir 
300cdf0e10cSrcweir                 // compare sName
301cdf0e10cSrcweir 
302cdf0e10cSrcweir                 if (!sName.equals(pdb.sName)) {
303cdf0e10cSrcweir 
304cdf0e10cSrcweir                     break checkLabel;
305cdf0e10cSrcweir                 }
306cdf0e10cSrcweir 
307cdf0e10cSrcweir                 // compare bName
308cdf0e10cSrcweir 
309cdf0e10cSrcweir                 if (bName.length != pdb.bName.length) {
310cdf0e10cSrcweir 
311cdf0e10cSrcweir                     break checkLabel;
312cdf0e10cSrcweir                 }
313cdf0e10cSrcweir 
314cdf0e10cSrcweir                 for (int i = 0; i < bName.length; i++) {
315cdf0e10cSrcweir 
316cdf0e10cSrcweir                     if (bName[i] != pdb.bName[i]) {
317cdf0e10cSrcweir 
318cdf0e10cSrcweir                         break checkLabel;
319cdf0e10cSrcweir                     }
320cdf0e10cSrcweir                 }
321cdf0e10cSrcweir 
322cdf0e10cSrcweir                 // compare each Record
323cdf0e10cSrcweir 
324cdf0e10cSrcweir                 if (records.length != pdb.records.length) {
325cdf0e10cSrcweir 
326cdf0e10cSrcweir                     break checkLabel;
327cdf0e10cSrcweir                 }
328cdf0e10cSrcweir 
329cdf0e10cSrcweir                 for (int i = 0; i < records.length; i++) {
330cdf0e10cSrcweir 
331cdf0e10cSrcweir                     if (!records[i].equals(pdb.records[i])) {
332cdf0e10cSrcweir 
333cdf0e10cSrcweir                         break checkLabel;
334cdf0e10cSrcweir                     }
335cdf0e10cSrcweir                 }
336cdf0e10cSrcweir 
337cdf0e10cSrcweir                 // all checks done
338cdf0e10cSrcweir                 bool = true;
339cdf0e10cSrcweir             }
340cdf0e10cSrcweir         }
341cdf0e10cSrcweir 
342cdf0e10cSrcweir         return bool;
343cdf0e10cSrcweir     }
344cdf0e10cSrcweir }
345