1 package org.clearsilver;
2 
3 import java.io.FileNotFoundException;
4 import java.io.IOException;
5 
6 import java.util.Calendar;
7 import java.util.Date;
8 import java.util.TimeZone;
9 
10 /** This class is a wrapper around the HDF C API.  Many features of the C API
11  *  are not yet exposed through this wrapper.
12  */
13 public class HDF {
14   int hdfptr;  // stores the C HDF* pointer
15   HDF root;    // If this is a child HDF node, points at the root node of
16                // the tree.  For root nodes this is null.  A child node needs
17                // to hold a reference on the root to prevent the root from
18                // being GC-ed.
19   static {
JNI.loadLibrary()20     JNI.loadLibrary();
21   }
22 
23   /** Constructs an empty HDF dataset */
HDF()24   public HDF() {
25     hdfptr = _init();
26     root = null;
27   }
28 
29   /** Constructs an HDF child node.  Used by other methods in this class when
30    * a child node needs to be constructed.
31    */
HDF(int hdfptr, HDF parent)32   private HDF(int hdfptr, HDF parent) {
33     this.hdfptr = hdfptr;
34     this.root = (parent.root != null) ? parent.root : parent;
35   }
36 
37   /** Clean up allocated memory if neccesary. close() allows application
38    *  to force clean up.
39    */
close()40   public void close() {
41     // Only root nodes have ownership of the C HDF pointer, so only a root
42     // node needs to dealloc hdfptr.dir
43     if ( root == null) {
44       if (hdfptr != 0) {
45         _dealloc(hdfptr);
46         hdfptr = 0;
47       }
48     }
49   }
50 
51   /** Call close() just in case when deallocating Java object.
52    */
53   // Should be protected access (like Object).
finalize()54   protected void finalize() throws Throwable {
55     close();
56     super.finalize();
57   }
58 
59   /** Loads the contents of the specified HDF file from disk into the current
60    *  HDF object.  The loaded contents are merged with the existing contents.
61    */
readFile(String filename)62   public boolean readFile(String filename) throws IOException,
63          FileNotFoundException {
64     if (hdfptr == 0) {
65       throw new NullPointerException("HDF is closed.");
66     }
67     return _readFile(hdfptr, filename, fileLoader != null);
68   }
69 
fileLoad(String filename)70   protected String fileLoad(String filename) throws IOException,
71             FileNotFoundException {
72     if (hdfptr == 0) {
73       throw new NullPointerException("HDF is closed.");
74     }
75     CSFileLoader aFileLoader = fileLoader;
76     if (aFileLoader == null) {
77       throw new NullPointerException("No fileLoader specified.");
78     } else {
79       String result = aFileLoader.load(this, filename);
80       if (result == null) {
81         throw new NullPointerException("CSFileLoader.load() returned null");
82       }
83       return result;
84     }
85   }
86 
87   // The optional CS file loader to use to read in files
88   private CSFileLoader fileLoader = null;
89 
90   /**
91    * Get the file loader in use, if any.
92    * @return the file loader in use.
93    */
getFileLoader()94   public CSFileLoader getFileLoader() {
95     return fileLoader;
96   }
97 
98   /**
99    * Set the CS file loader to use
100    * @param fileLoader the file loader that should be used.
101    */
setFileLoader(CSFileLoader fileLoader)102   public void setFileLoader(CSFileLoader fileLoader) {
103     this.fileLoader = fileLoader;
104   }
105 
106   /** Serializes HDF contents to a file (readable by readFile)
107    */
writeFile(String filename)108   public boolean writeFile(String filename) throws IOException {
109     if (hdfptr == 0) {
110       throw new NullPointerException("HDF is closed.");
111     }
112     return _writeFile(hdfptr, filename);
113   }
114 
115   /** Serializes HDF contents to a file (readable by readFile), but
116    *  writes the file atomically by writing to a temp file then doing a
117    *  rename(2) on it.
118    */
writeFileAtomic(String filename)119   public boolean writeFileAtomic(String filename) throws IOException {
120     if (hdfptr == 0) {
121       throw new NullPointerException("HDF is closed.");
122     }
123     return _writeFileAtomic(hdfptr, filename);
124   }
125 
126   /** Parses/loads the contents of the given string as HDF into the current
127    *  HDF object.  The loaded contents are merged with the existing contents.
128    */
readString(String data)129   public boolean readString(String data) {
130     if (hdfptr == 0) {
131       throw new NullPointerException("HDF is closed.");
132     }
133     return _readString(hdfptr, data);
134   }
135 
136   /** Serializes HDF contents to a string (readable by readString)
137    */
writeString()138   public String writeString() {
139     if (hdfptr == 0) {
140       throw new NullPointerException("HDF is closed.");
141     }
142     return _writeString(hdfptr);
143   }
144 
145   /** Retrieves the integer value at the specified path in this HDF node's
146    *  subtree.  If the value does not exist, or cannot be converted to an
147    *  integer, default_value will be returned. */
getIntValue(String hdfname, int default_value)148   public int getIntValue(String hdfname, int default_value) {
149     if (hdfptr == 0) {
150       throw new NullPointerException("HDF is closed.");
151     }
152     return _getIntValue(hdfptr,hdfname,default_value);
153   }
154 
155   /** Retrieves the value at the specified path in this HDF node's subtree.
156   */
getValue(String hdfname, String default_value)157   public String getValue(String hdfname, String default_value) {
158     if (hdfptr == 0) {
159       throw new NullPointerException("HDF is closed.");
160     }
161     return _getValue(hdfptr,hdfname,default_value);
162   }
163 
164   /** Sets the value at the specified path in this HDF node's subtree. */
setValue(String hdfname, String value)165   public void setValue(String hdfname, String value) {
166     if (hdfptr == 0) {
167       throw new NullPointerException("HDF is closed.");
168     }
169     _setValue(hdfptr,hdfname,value);
170   }
171 
172   /** Remove the specified subtree. */
removeTree(String hdfname)173   public void removeTree(String hdfname) {
174     if (hdfptr == 0) {
175       throw new NullPointerException("HDF is closed.");
176     }
177     _removeTree(hdfptr,hdfname);
178   }
179 
180   /** Links the src hdf name to the dest. */
setSymLink(String hdf_name_src, String hdf_name_dest)181   public void setSymLink(String hdf_name_src, String hdf_name_dest) {
182     if (hdfptr == 0) {
183       throw new NullPointerException("HDF is closed.");
184     }
185     _setSymLink(hdfptr,hdf_name_src,hdf_name_dest);
186   }
187 
188   /** Export a date to a clearsilver tree using a specified timezone */
exportDate(String hdfname, TimeZone timeZone, Date date)189   public void exportDate(String hdfname, TimeZone timeZone, Date date) {
190     if (hdfptr == 0) {
191       throw new NullPointerException("HDF is closed.");
192     }
193 
194     Calendar cal = Calendar.getInstance(timeZone);
195     cal.setTime(date);
196 
197     String sec = Integer.toString(cal.get(Calendar.SECOND));
198     setValue(hdfname + ".sec", sec.length() == 1 ? "0" + sec : sec);
199 
200     String min = Integer.toString(cal.get(Calendar.MINUTE));
201     setValue(hdfname + ".min", min.length() == 1 ? "0" + min : min);
202 
203     setValue(hdfname + ".24hour",
204              Integer.toString(cal.get(Calendar.HOUR_OF_DAY)));
205     // java.util.Calendar uses represents 12 o'clock as 0
206     setValue(hdfname + ".hour",
207              Integer.toString(
208                  cal.get(Calendar.HOUR) == 0 ? 12 : cal.get(Calendar.HOUR)));
209     setValue(hdfname + ".am",
210              cal.get(Calendar.AM_PM) == Calendar.AM ? "1" : "0");
211     setValue(hdfname + ".mday",
212              Integer.toString(cal.get(Calendar.DAY_OF_MONTH)));
213     setValue(hdfname + ".mon",
214              Integer.toString(cal.get(Calendar.MONTH)+1));
215     setValue(hdfname + ".year",
216              Integer.toString(cal.get(Calendar.YEAR)));
217     setValue(hdfname + ".2yr",
218              Integer.toString(cal.get(Calendar.YEAR)).substring(2));
219     setValue(hdfname + ".wday",
220              Integer.toString(cal.get(Calendar.DAY_OF_WEEK)));
221 
222     boolean tzNegative = timeZone.getRawOffset() < 0;
223     int tzAbsolute = java.lang.Math.abs(timeZone.getRawOffset()/1000);
224     String tzHour = Integer.toString(tzAbsolute/3600);
225     String tzMin = Integer.toString(tzAbsolute/60 - (tzAbsolute/3600)*60);
226     String tzString = (tzNegative ? "-" : "+")
227                       + (tzHour.length() == 1 ? "0" + tzHour : tzHour)
228                       + (tzMin.length() == 1 ? "0" + tzMin : tzMin);
229     setValue(hdfname + ".tzoffset", tzString);
230   }
231 
232   /** Export a date to a clearsilver tree using a specified timezone */
233   public void exportDate(String hdfname, String tz, int tt) {
234     if (hdfptr == 0) {
235       throw new NullPointerException("HDF is closed.");
236     }
237 
238     TimeZone timeZone = TimeZone.getTimeZone(tz);
239 
240     if (timeZone == null) {
241       throw new RuntimeException("Unknown timezone: " + tz);
242     }
243 
244     Date date = new Date((long)tt * 1000);
245 
246     exportDate(hdfname, timeZone, date);
247   }
248 
249   /** Retrieves the HDF object that is the root of the subtree at hdfpath, or
250    *  null if no object exists at that path. */
251   public HDF getObj(String hdfpath) {
252     if (hdfptr == 0) {
253       throw new NullPointerException("HDF is closed.");
254     }
255     int obj_ptr = _getObj(hdfptr, hdfpath);
256     if ( obj_ptr == 0 ) {
257       return null;
258     }
259     return new HDF(obj_ptr, this);
260   }
261 
262   /** Retrieves the HDF for the first child of the root of the subtree
263    *  at hdfpath, or null if no child exists of that path or if the
264    *  path doesn't exist. */
265   public HDF getChild(String hdfpath) {
266     if (hdfptr == 0) {
267       throw new NullPointerException("HDF is closed.");
268     }
269     int obj_ptr = _getChild(hdfptr, hdfpath);
270     if ( obj_ptr == 0 ) {
271       return null;
272     }
273     return new HDF(obj_ptr, this);
274   }
275 
276   /** Return the root of the tree where the current node lies.  If the
277    *  current node is the root, return this. */
278   public HDF getRootObj() {
279     return root != null ? root : this;
280   }
281 
282   /** Retrieves the HDF object that is the root of the subtree at
283    *  hdfpath, create the subtree if it doesn't exist */
284   public HDF getOrCreateObj(String hdfpath) {
285     if (hdfptr == 0) {
286       throw new NullPointerException("HDF is closed.");
287     }
288     int obj_ptr = _getObj(hdfptr, hdfpath);
289     if ( obj_ptr == 0 ) {
290       // Create a node
291       _setValue(hdfptr, hdfpath, "");
292       obj_ptr = _getObj( hdfptr, hdfpath );
293       if ( obj_ptr == 0 ) {
294         return null;
295       }
296     }
297     return new HDF(obj_ptr, this);
298   }
299 
300   /** Returns the name of this HDF node.   The root node has no name, so
301    *  calling this on the root node will return null. */
302   public String objName() {
303     if (hdfptr == 0) {
304       throw new NullPointerException("HDF is closed.");
305     }
306     return _objName(hdfptr);
307   }
308 
309   /** Returns the value of this HDF node, or null if this node has no value.
310    *  Every node in the tree can have a value, a child, and a next peer. */
311   public String objValue() {
312     if (hdfptr == 0) {
313       throw new NullPointerException("HDF is closed.");
314     }
315     return _objValue(hdfptr);
316   }
317 
318   /** Returns the child of this HDF node, or null if there is no child.
319    *  Use this in conjunction with objNext to walk the HDF tree.  Every node
320    *  in the tree can have a value, a child, and a next peer. */
321   public HDF objChild() {
322     if (hdfptr == 0) {
323       throw new NullPointerException("HDF is closed.");
324     }
325     int child_ptr = _objChild(hdfptr);
326     if ( child_ptr == 0 ) {
327       return null;
328     }
329     return new HDF(child_ptr, this);
330   }
331 
332   /** Returns the next sibling of this HDF node, or null if there is no next
333    *  sibling.  Use this in conjunction with objChild to walk the HDF tree.
334    *  Every node in the tree can have a value, a child, and a next peer. */
335   public HDF objNext() {
336     if (hdfptr == 0) {
337       throw new NullPointerException("HDF is closed.");
338     }
339     int next_ptr = _objNext(hdfptr);
340     if ( next_ptr == 0 ) {
341       return null;
342     }
343     return new HDF(next_ptr, this);
344   }
345 
346   public void copy(String hdfpath, HDF src) {
347     if (hdfptr == 0 || src.hdfptr == 0) {
348       throw new NullPointerException("HDF is closed.");
349     }
350     _copy(hdfptr, hdfpath, src.hdfptr);
351   }
352 
353   /**
354    * Generates a string representing the content of the HDF tree rooted at
355    * this node.
356    */
357   public String dump() {
358     if (hdfptr == 0) {
359       throw new NullPointerException("HDF is closed.");
360     }
361     return _dump(hdfptr);
362   }
363 
364   private static native int _init();
365   private static native void _dealloc(int ptr);
366   private native boolean _readFile(int ptr, String filename, boolean use_cb);
367   private static native boolean _writeFile(int ptr, String filename);
368   private static native boolean _writeFileAtomic(int ptr, String filename);
369   private static native boolean _readString(int ptr, String data);
370   private static native String _writeString(int ptr);
371   private static native int _getIntValue(int ptr, String hdfname,
372                                          int default_value);
373   private static native String _getValue(int ptr, String hdfname,
374                                          String default_value);
375   private static native void _setValue(int ptr, String hdfname,
376                                        String hdf_value);
377   private static native void _removeTree(int ptr, String hdfname);
378   private static native void _setSymLink(int ptr, String hdf_name_src,
379                                        String hdf_name_dest);
380   private static native int _getObj(int ptr, String hdfpath);
381   private static native int _getChild(int ptr, String hdfpath);
382   private static native int _objChild(int ptr);
383   private static native int _objNext(int ptr);
384   private static native String _objName(int ptr);
385   private static native String _objValue(int ptr);
386   private static native void _copy(int destptr, String hdfpath, int srcptr);
387 
388   private static native String _dump(int ptr);
389 }
390