/* * Copyright (C) 2010 Google Inc. * * Licensed 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. */ package org.clearsilver.jni; import org.clearsilver.CSFileLoader; import org.clearsilver.HDF; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; /** * This class is a wrapper around the HDF C API. Many features of the C API * are not yet exposed through this wrapper. */ public class JniHdf implements HDF { long hdfptr; // stores the C HDF* pointer JniHdf root; // If this is a child HDF node, points at the root node of // the tree. For root nodes this is null. A child node needs // to hold a reference on the root to prevent the root from // being GC-ed. static { JNI.loadLibrary(); } static JniHdf cast(HDF hdf) { if (!(hdf instanceof JniHdf)) { throw new IllegalArgumentException("HDF object not of type JniHdf. " + "Make sure you use the same ClearsilverFactory to construct all " + "related HDF and CS objects."); } return (JniHdf)hdf; } /** * Default public constructor. */ public JniHdf() { hdfptr = _init(); root = null; } protected JniHdf(long hdfptr, JniHdf parent) { this.hdfptr = hdfptr; this.root = (parent.root != null) ? parent.root : parent; } /** Constructs an HDF child node. Used by other methods in this class when * a child node needs to be constructed. */ protected JniHdf newHdf(long hdfptr, HDF parent) { return new JniHdf(hdfptr, cast(parent)); } /** Clean up allocated memory if neccesary. close() allows application * to force clean up. */ public void close() { // Only root nodes have ownership of the C HDF pointer, so only a root // node needs to dealloc hdfptr.dir if (root == null) { if (hdfptr != 0) { _dealloc(hdfptr); hdfptr = 0; } } } /** Call close() just in case when deallocating Java object. */ protected void finalize() throws Throwable { close(); super.finalize(); } /** Loads the contents of the specified HDF file from disk into the current * HDF object. The loaded contents are merged with the existing contents. * @param filename the name of file to read in and parse. * @throws java.io.FileNotFoundException if the specified file does not * exist. * @throws IOException other problems reading the file. */ public boolean readFile(String filename) throws IOException { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _readFile(hdfptr, filename, fileLoader != null); } protected String fileLoad(String filename) throws IOException { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } CSFileLoader aFileLoader = fileLoader; if (aFileLoader == null) { throw new NullPointerException("No fileLoader specified."); } else { String result = aFileLoader.load(this, filename); if (result == null) { throw new NullPointerException("CSFileLoader.load() returned null"); } return result; } } // The optional CS file loader to use to read in files private CSFileLoader fileLoader = null; /** * Get the file loader in use, if any. * @return the file loader in use. */ public CSFileLoader getFileLoader() { return fileLoader; } /** * Set the CS file loader to use * @param fileLoader the file loader that should be used. */ public void setFileLoader(CSFileLoader fileLoader) { this.fileLoader = fileLoader; } /** Serializes HDF contents to a file (readable by readFile) */ public boolean writeFile(String filename) throws IOException { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _writeFile(hdfptr, filename); } /** Parses/loads the contents of the given string as HDF into the current * HDF object. The loaded contents are merged with the existing contents. */ public boolean readString(String data) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _readString(hdfptr, data); } /** Serializes HDF contents to a string (readable by readString) */ public String writeString() { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _writeString(hdfptr); } /** Retrieves the integer value at the specified path in this HDF node's * subtree. If the value does not exist, or cannot be converted to an * integer, default_value will be returned. */ public int getIntValue(String hdfname, int default_value) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _getIntValue(hdfptr,hdfname,default_value); } /** Retrieves the value at the specified path in this HDF node's subtree. */ public String getValue(String hdfname, String default_value) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _getValue(hdfptr,hdfname,default_value); } /** Sets the value at the specified path in this HDF node's subtree. */ public void setValue(String hdfname, String value) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } _setValue(hdfptr,hdfname,value); } /** Remove the specified subtree. */ public void removeTree(String hdfname) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } _removeTree(hdfptr,hdfname); } /** Links the src hdf name to the dest. */ public void setSymLink(String hdf_name_src, String hdf_name_dest) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } _setSymLink(hdfptr,hdf_name_src,hdf_name_dest); } /** Export a date to a clearsilver tree using a specified timezone */ public void exportDate(String hdfname, TimeZone timeZone, Date date) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } Calendar cal = Calendar.getInstance(timeZone); cal.setTime(date); String sec = Integer.toString(cal.get(Calendar.SECOND)); setValue(hdfname + ".sec", sec.length() == 1 ? "0" + sec : sec); String min = Integer.toString(cal.get(Calendar.MINUTE)); setValue(hdfname + ".min", min.length() == 1 ? "0" + min : min); setValue(hdfname + ".24hour", Integer.toString(cal.get(Calendar.HOUR_OF_DAY))); // java.util.Calendar uses represents 12 o'clock as 0 setValue(hdfname + ".hour", Integer.toString( cal.get(Calendar.HOUR) == 0 ? 12 : cal.get(Calendar.HOUR))); setValue(hdfname + ".am", cal.get(Calendar.AM_PM) == Calendar.AM ? "1" : "0"); setValue(hdfname + ".mday", Integer.toString(cal.get(Calendar.DAY_OF_MONTH))); setValue(hdfname + ".mon", Integer.toString(cal.get(Calendar.MONTH)+1)); setValue(hdfname + ".year", Integer.toString(cal.get(Calendar.YEAR))); setValue(hdfname + ".2yr", Integer.toString(cal.get(Calendar.YEAR)).substring(2)); // Java DAY_OF_WEEK puts Sunday .. Saturday as 1 .. 7 respectively // See http://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html#DAY_OF_WEEK // However, C and Python export Sun .. Sat as 0 .. 6, because // POSIX localtime_r produces wday 0 .. 6. So, adjust. setValue(hdfname + ".wday", Integer.toString(cal.get(Calendar.DAY_OF_WEEK) - 1)); boolean tzNegative = timeZone.getRawOffset() < 0; int tzAbsolute = java.lang.Math.abs(timeZone.getRawOffset()/1000); String tzHour = Integer.toString(tzAbsolute/3600); String tzMin = Integer.toString(tzAbsolute/60 - (tzAbsolute/3600)*60); String tzString = (tzNegative ? "-" : "+") + (tzHour.length() == 1 ? "0" + tzHour : tzHour) + (tzMin.length() == 1 ? "0" + tzMin : tzMin); setValue(hdfname + ".tzoffset", tzString); } /** Export a date to a clearsilver tree using a specified timezone */ public void exportDate(String hdfname, String tz, int tt) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } TimeZone timeZone = TimeZone.getTimeZone(tz); if (timeZone == null) { throw new RuntimeException("Unknown timezone: " + tz); } Date date = new Date((long)tt * 1000); exportDate(hdfname, timeZone, date); } /** Retrieves the HDF object that is the root of the subtree at hdfpath, or * null if no object exists at that path. */ public JniHdf getObj(String hdfpath) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } long obj_ptr = _getObj(hdfptr, hdfpath); if ( obj_ptr == 0 ) { return null; } return newHdf(obj_ptr, this); } /** Retrieves the HDF for the first child of the root of the subtree * at hdfpath, or null if no child exists of that path or if the * path doesn't exist. */ public JniHdf getChild(String hdfpath) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } long obj_ptr = _getChild(hdfptr, hdfpath); if ( obj_ptr == 0 ) { return null; } return newHdf(obj_ptr, this); } /** Return the root of the tree where the current node lies. If the * current node is the root, return this. */ public JniHdf getRootObj() { return root != null ? root : this; } public boolean belongsToSameRoot(HDF hdf) { JniHdf jniHdf = cast(hdf); return this.getRootObj() == jniHdf.getRootObj(); } /** Retrieves the HDF object that is the root of the subtree at * hdfpath, create the subtree if it doesn't exist */ public JniHdf getOrCreateObj(String hdfpath) { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } long obj_ptr = _getObj(hdfptr, hdfpath); if ( obj_ptr == 0 ) { // Create a node _setValue(hdfptr, hdfpath, ""); obj_ptr = _getObj( hdfptr, hdfpath ); if ( obj_ptr == 0 ) { return null; } } return newHdf(obj_ptr, this); } /** Returns the name of this HDF node. The root node has no name, so * calling this on the root node will return null. */ public String objName() { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _objName(hdfptr); } /** Returns the value of this HDF node, or null if this node has no value. * Every node in the tree can have a value, a child, and a next peer. */ public String objValue() { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _objValue(hdfptr); } /** Returns the child of this HDF node, or null if there is no child. * Use this in conjunction with objNext to walk the HDF tree. Every node * in the tree can have a value, a child, and a next peer. */ public JniHdf objChild() { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } long child_ptr = _objChild(hdfptr); if ( child_ptr == 0 ) { return null; } return newHdf(child_ptr, this); } /** Returns the next sibling of this HDF node, or null if there is no next * sibling. Use this in conjunction with objChild to walk the HDF tree. * Every node in the tree can have a value, a child, and a next peer. */ public JniHdf objNext() { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } long next_ptr = _objNext(hdfptr); if ( next_ptr == 0 ) { return null; } return newHdf(next_ptr, this); } public void copy(String hdfpath, HDF src) { JniHdf source = cast(src); if (hdfptr == 0 || source.hdfptr == 0) { throw new NullPointerException("HDF is closed."); } _copy(hdfptr, hdfpath, source.hdfptr); } /** * Generates a string representing the content of the HDF tree rooted at * this node. */ public String dump() { if (hdfptr == 0) { throw new NullPointerException("HDF is closed."); } return _dump(hdfptr); } private static native long _init(); private static native void _dealloc(long ptr); private native boolean _readFile(long ptr, String filename, boolean use_cb) throws IOException; private static native boolean _writeFile(long ptr, String filename); private static native boolean _readString(long ptr, String data); private static native String _writeString(long ptr); private static native int _getIntValue(long ptr, String hdfname, int default_value); private static native String _getValue(long ptr, String hdfname, String default_value); private static native void _setValue(long ptr, String hdfname, String hdf_value); private static native void _removeTree(long ptr, String hdfname); private static native void _setSymLink(long ptr, String hdf_name_src, String hdf_name_dest); private static native long _getObj(long ptr, String hdfpath); private static native long _getChild(long ptr, String hdfpath); private static native long _objChild(long ptr); private static native long _objNext(long ptr); private static native String _objName(long ptr); private static native String _objValue(long ptr); private static native void _copy(long destptr, String hdfpath, long srcptr); private static native String _dump(long ptr); }