| /* |
| * 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); |
| } |