/*
* RemoteTree.java
*
* Created on February 5, 2005, 5:43 PM
*/
package hep.aida.ref.remote;
import hep.aida.IAnnotation;
import hep.aida.IBaseHistogram;
import hep.aida.IDataPointSet;
import hep.aida.IFunction;
import hep.aida.IManagedObject;
import hep.aida.ITuple;
import hep.aida.dev.IDevMutableStore;
import hep.aida.dev.IDevTree;
import hep.aida.dev.IStore;
import hep.aida.dev.IStoreFactory;
import hep.aida.ref.AidaUtils;
import hep.aida.ref.Annotation;
import hep.aida.ref.ManagedObject;
import hep.aida.ref.event.AIDAObservable;
import hep.aida.ref.event.IsObservable;
import hep.aida.ref.remote.interfaces.AidaUpdateEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Vector;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import org.freehep.util.FreeHEPLookup;
import org.openide.util.Lookup;
/**
*
* @author serbo
*/
public class RemoteTree extends AIDAObservable implements IDevTree, IsObservable {
protected IStore aidaStore;
private String storeName;
private boolean readOnly;
private boolean readOnlyUserDefined;
private boolean appendAxisType;
private boolean createNew;
protected String storeType = null;
protected Map optionsMap;
protected boolean overwrite;
protected Vector updateBuffer;
protected Logger remoteLogger;
private Object lock;
protected TreeMap map = new java.util.TreeMap();
/** Creates a new instance of RemoteTree */
public RemoteTree() {
this("Tree");
}
public RemoteTree(String name) {
this(name, null);
}
public RemoteTree(String name, IDevMutableStore aidaStore) {
this(name, aidaStore, false);
}
public RemoteTree(String name, IDevMutableStore aidaStore, boolean overwrite) {
this(name, aidaStore, overwrite, false);
}
public RemoteTree(String name, IDevMutableStore aidaStore, boolean overwrite, boolean appendAxisType) {
super();
this.storeName = name;
this.aidaStore = aidaStore;
this.lock = new Object();
this.overwrite = overwrite;
this.remoteLogger = Logger.getLogger("hep.aida.ref.remote");
this.appendAxisType = appendAxisType;
this.updateBuffer = new Vector();
setIsValidAfterNotify(true);
addFolder("/");
}
// Service methods
public void submitEventToListeners(AidaUpdateEvent ev) {
remoteLogger.finest("RemoteTree.submitEventToListeners :: id="+ev.id()+", path="+ev.path());
if (ev instanceof RemoteUpdateEvent) fireStateChanged((EventObject) ev);
else {
int id = ev.id();
String path = ev.path();
String type = ev.nodeType();
RemoteUpdateEvent rev = new RemoteUpdateEvent(id, path, type);
fireStateChanged(rev);
}
}
public void init( String storeName, boolean readOnly, boolean createNew, String storeType, String options, boolean readOnlyUserDefined ) throws IOException {
this.storeName = storeName;
this.readOnly = readOnly;
this.readOnlyUserDefined = readOnlyUserDefined;
this.createNew = createNew;
this.storeType = storeType;
if (readOnly && createNew) throw new IllegalArgumentException("readOnly and createNew not allowed");
optionsMap = AidaUtils.parseOptions( options );
if (storeName!=null && storeName.length()>0 && ! createNew) {
if (getLock() != null) {
synchronized (getLock()) {
createStore().read(this,optionsMap, readOnly, createNew);
}
} else {
createStore().read(this,optionsMap, readOnly, createNew);
}
}
}
protected IStore createStore() throws IOException {
if (aidaStore == null) {
if (storeType == null || storeType.length()==0) storeType = "xml";
// Look for a handler for this storeType
Lookup.Template template = new Lookup.Template(IStoreFactory.class);
Lookup.Result result = FreeHEPLookup.instance().lookup(template);
for (Iterator i = result.allInstances().iterator(); i.hasNext(); ) {
IStoreFactory factory = (IStoreFactory) i.next();
if (factory.supportsType(storeType)) {
//System.out.println("Got item for type: "+storeType+", "+item.getClass()+", "+item);
aidaStore = factory.createStore();
//If the readOnly flag has not been set by the user AND the store is
//read-only, then we default to read-only=true.
//FIX for JAIDA-46
if ( ! readOnlyUserDefined && aidaStore.isReadOnly() )
this.readOnly = true;
if ( aidaStore.isReadOnly() && ( ! isReadOnly() ) )
throw new IllegalArgumentException("When opening a read-only file, the associated tree must be read-only. Please correct the options with which you created the tree.");
return aidaStore;
}
}
throw new IOException("Unknown store type: "+storeType);
} else return aidaStore;
}
public String correctPath(String path, boolean isDir) {
String tmpPath = path;
if (path == null || path.trim().equals("")) return path;
if (tmpPath.equals("/")) return tmpPath;
tmpPath.replaceAll("///", "/");
tmpPath.replaceAll("//", "/");
if (!tmpPath.startsWith("/")) tmpPath = "/"+tmpPath;
if (isDir && !tmpPath.endsWith("/")) tmpPath = tmpPath+"/";
if (!isDir && tmpPath.endsWith("/")) tmpPath = tmpPath.substring(0, tmpPath.length()-1);
return tmpPath;
}
protected String[] executeListObjectNames(String path, boolean recursive) {
String[] names = null;
remoteLogger.finest("RemoteTree.executeListObjectNames for recursive="+recursive+", Path: "+ path);
Map tailMap = map.tailMap(path);
ArrayList list = new ArrayList(tailMap.size());
Iterator tailIt = tailMap.keySet().iterator();
while (tailIt.hasNext()) {
String key = (String) tailIt.next();
if (path.equals(key)) {
continue;
} else if (recursive && path.equals("/")) {
list.add(key);
} else if (key.startsWith(path)) {
if (recursive) {
list.add(key);
} else {
String folder = AidaUtils.parseDirName(key);
String name = AidaUtils.parseName(key);
if (path.equals(folder)) {
list.add(key);
} else if (name == null || name.equals("")) {
int index1 = path.length();
int index2 = folder.length();
if (folder.endsWith("//")) index2 = index2 - 2;
else if (folder.endsWith("/")) index2 = index2 - 1;
String tmp = folder.substring(index1, index2);
if (tmp.indexOf("/") < 0) list.add(key);
}
}
}
}
list.trimToSize();
names = new String[list.size()];
list.toArray(names);
return names;
}
protected String[] executeListObjectTypes(String path, boolean recursive) {
String[] types = null;
remoteLogger.finest("RemoteTree.executeListObjectTypes for recursive="+recursive+", Path: "+ path);
Map tailMap = map.tailMap(path);
ArrayList list = new ArrayList(tailMap.size());
Iterator tailIt = tailMap.keySet().iterator();
while (tailIt.hasNext()) {
String key = (String) tailIt.next();
String type = null;
if (path.equals(key)) continue;
else if (key.startsWith(path)) {
boolean acceptKey = false;
if (recursive) {
acceptKey = true;
} else {
String folder = AidaUtils.parseDirName(key);
String name = AidaUtils.parseName(key);
if (path.equals(folder)) {
acceptKey = true;
} else if (name == null || name.equals("")) {
int index1 = path.length();
int index2 = folder.length();
if (folder.endsWith("//")) index2 = index2 - 2;
else if (folder.endsWith("/")) index2 = index2 - 1;
String tmp = folder.substring(index1, index2);
if (tmp.indexOf("/") < 0) acceptKey = true;
}
}
if (acceptKey) {
Object obj = map.get(key);
if (obj instanceof IManagedObject) type = ((IManagedObject) obj).type();
else type = obj.getClass().getName();
if (appendAxisType && !type.equalsIgnoreCase("dir")) {
String xType = "double";
String tmp = null;
if (obj instanceof ManagedObject) {
synchronized (obj) {
boolean isFillable = false;
boolean isAnnotationFillable = false;
Annotation an = null;
isFillable = ((ManagedObject) obj).isFillable();
if (!isFillable) ((ManagedObject) obj).setFillable(true);
if (obj instanceof IBaseHistogram) an = (Annotation) ((IBaseHistogram) obj).annotation();
else if (obj instanceof IDataPointSet) an = (Annotation) ((IDataPointSet) obj).annotation();
if (an != null) {
isAnnotationFillable = an.isFillable();
if (!isAnnotationFillable) an.setFillable(true);
try {
tmp = an.value("xAxisType");
} catch (IllegalArgumentException e) {}
an.setFillable(isAnnotationFillable);
}
((ManagedObject) obj).setFillable(isFillable);
}
} else if (obj != null) {
IAnnotation an = null;
if (obj instanceof IBaseHistogram) an = (IAnnotation) ((IBaseHistogram) obj).annotation();
else if (obj instanceof IDataPointSet) an = (IAnnotation) ((IDataPointSet) obj).annotation();
try {
tmp = an.value("xAxisType");
} catch (Exception e) {}
}
if (tmp != null && !tmp.trim().equals("")) {
xType = tmp;
type = type + ":" + xType;
}
}
list.add(type);
}
}
}
list.trimToSize();
types = new String[list.size()];
list.toArray(types);
return types;
}
public IManagedObject executeFind(String path) {
String p = correctPath(path, false);
if (!map.containsKey(p)) throw new IllegalArgumentException("Object does not exist for path: "+p);
IManagedObject obj = (IManagedObject) map.get(p);
return obj;
}
protected void executeClose() {
if (aidaStore != null) {
try {
aidaStore.close();
} catch (IOException ioe) { ioe.printStackTrace(); }
}
RemoteUpdateEvent rev = new RemoteUpdateEvent(AidaUpdateEvent.TREE_CLOSED, "/", "dir");
submitEventToListeners(rev);
map.clear();
}
// Next four methods are used by Store to change Tree structure
// Store must provide correct path String
// Those methods must not be called by anybody except the Store
public void addObject(String path, IManagedObject object) throws IllegalArgumentException {
String p = correctPath(path, true);
String fullPath = p + AidaUtils.modifyName(object.name());
String tmpName = storeName;
if (tmpName == null || tmpName.trim().equals("")) tmpName = this.storeName();
String jas3FullPath = "/"+tmpName+fullPath;
remoteLogger.finest("RemoteTree.addObject path="+path+", correctedPath="+p+", fullPath="+fullPath+", object="+object);
if (map.containsKey(fullPath) && !overwrite) throw new IllegalArgumentException("Object already exists for path: "+fullPath);
map.put(fullPath, object);
/*
try {
if (object != null) {
IAnnotation an = null;
if (object instanceof IBaseHistogram) {
an = ((IBaseHistogram) object).annotation();
} else if (object instanceof IDataPointSet) {
an = ((IDataPointSet) object).annotation();
} else if (object instanceof IFunction) {
an = ((IFunction) object).annotation();
} else if (object instanceof ITuple) {
an = ((ITuple) object).annotation();
}
if (an == null) return;
try {
if (an.hasKey(Annotation.aidaPathKey)) {
an.setValue(Annotation.aidaPathKey, fullPath);
} else {
an.addItem(Annotation.aidaPathKey, fullPath, true);
}
} catch (Exception e) { e.printStackTrace(); }
try {
if (an.hasKey(Annotation.fullPathKey)) {
an.setValue(Annotation.fullPathKey, jas3FullPath);
} else {
an.addItem(Annotation.fullPathKey, jas3FullPath, true);
}
} catch (Exception e) { e.printStackTrace(); }
}
} catch (Exception e) {
remoteLogger.log(Level.INFO, "RemoteTree.addObject Exception for Path: "+path+", fullPath="+fullPath+", jas3FullPath="+jas3FullPath, e);
remoteLogger.log(Level.FINEST, "", e.getStackTrace());
}
*/
}
public void addFolder(String path) throws java.lang.IllegalArgumentException {
String p = correctPath(path, true);
//if (map.containsKey(path) && !overwrite) throw new IllegalArgumentException("Folder already exists for path: "+path);
Object obj = map.get(p);
if (obj != null) return;
String objectName = AidaUtils.parseName(p);
String folderName = AidaUtils.parseDirName(p);
RemoteFolder f = new RemoteFolder(objectName);
f.setTreeFolder(folderName);
map.put(p, f);
}
void removeObject(String path) throws java.lang.IllegalArgumentException {
String p = correctPath(path, false);
if (!map.containsKey(p)) throw new IllegalArgumentException("Object does not exist for path: "+p);
Object obj = map.remove(p);
remoteLogger.finest("RemoteTree.removeObject path="+path+", correctedPath="+p+", object="+obj);
//updateBuffer.remove(path);
}
void removeFolder(String path) throws java.lang.IllegalArgumentException {
String p = correctPath(path, true);
if (!map.containsKey(p)) throw new IllegalArgumentException("Folder does not exist for path: "+p);
remoteLogger.finest("RemoteTree.removeFolder path="+path+", correctedPath="+p);
Map tailMap = map.tailMap(p);
Set keySet = tailMap.keySet();
int size = keySet.size();
Object[] a = new Object[size];
keySet.toArray(a);
for (int i=0; i<size; i++) {
String key = (String) a[i];
if (key.startsWith(p)) {
Object obj = map.remove(key);
//updateBuffer.remove(key);
}
}
}
String executeFindPath(IManagedObject iManagedObject) {
String path = null;
String key = null;
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
key = (String) it.next();
if (map.get(key).equals(iManagedObject)) {
path = key;
break;
}
}
return path;
}
int executeUpdate(String updatePath) {
if (updateBuffer.isEmpty()) return 0;
Object[] paths = null;
if (lock != null) {
synchronized (lock) {
paths = updateBuffer.toArray();
updateBuffer.clear();
}
} else {
paths = updateBuffer.toArray();
updateBuffer.clear();
}
int nObjects = paths.length;
for (int i=0; i<paths.length; i++) {
String path = (String) paths[i];
if (updatePath == null || updatePath.equals("/") || path.startsWith(updatePath)) {
try {
Object obj = (IManagedObject) map.get(path);
remoteLogger.finest("RemoteTree.executeUpdate: Path="+path+", object="+obj);
//System.out.println("RemoteTree.executeUpdate: Path="+path+", object="+obj);
if (obj == null) continue;
if (obj instanceof RemoteManagedObject) {
RemoteManagedObject rmo = (RemoteManagedObject) obj;
if (rmo.isDataValid()) {
//rmo.setValidForAll();
rmo.setDataValid(false);
}
} else if (obj instanceof ManagedObject) {
ManagedObject mo = (ManagedObject) obj;
// don't do anything here for now
}
} catch (Exception e) {
remoteLogger.log(Level.INFO, "RemoteTree.executeUpdate Exception for Path: "+path, e);
remoteLogger.log(Level.FINEST, "", e.getStackTrace());
}
}
}
return nObjects;
}
public int doUpdate(String updatePath) {
if (lock != null) {
//synchronized (lock) {
return executeUpdate(updatePath);
//}
} else {
return executeUpdate(updatePath);
}
}
// IDevTree methods
public Object getLock() { return lock; }
public void setLock(Object lock) { this.lock = lock; }
public void close() throws java.io.IOException {
if (lock != null) {
synchronized (lock) {
executeClose();
}
} else {
executeClose();
}
removeAllListeners();
}
public hep.aida.IManagedObject find(String path) throws java.lang.IllegalArgumentException {
String p = correctPath(path, false);
IManagedObject mo = null;
if (lock != null) {
synchronized (lock) {
mo = executeFind(p);
if (!updateBuffer.contains(p)) updateBuffer.add(p);
}
} else {
mo = executeFind(p);
if (!updateBuffer.contains(p)) updateBuffer.add(p);
}
return mo;
}
public void hasBeenFilled(String path) throws IllegalArgumentException {
return;
}
public String[] listObjectNames(String path) throws java.lang.IllegalArgumentException {
return listObjectNames(path, false);
}
public String[] listObjectNames(String path, boolean param) throws java.lang.IllegalArgumentException {
String p = correctPath(path, true);
if (lock != null) {
synchronized (lock) {
return executeListObjectNames(p, param);
}
} else {
return executeListObjectNames(p, param);
}
}
public String[] listObjectTypes(String path) throws java.lang.IllegalArgumentException {
return listObjectTypes(path, false);
}
public String[] listObjectTypes(String path, boolean param) throws java.lang.IllegalArgumentException {
String p = correctPath(path, true);
if (lock != null) {
synchronized (lock) {
return executeListObjectTypes(p, param);
}
} else {
return executeListObjectTypes(p, param);
}
}
public String findPath(hep.aida.IManagedObject iManagedObject) throws java.lang.IllegalArgumentException {
if (lock != null) {
synchronized (lock) {
return executeFindPath(iManagedObject);
}
} else {
return executeFindPath(iManagedObject);
}
}
public void setOverwrite() {
overwrite = true;
}
public void setOverwrite(boolean param) {
overwrite = param;
}
public String storeName() {
return storeName;
}
//FIXME
public String name() {
throw new UnsupportedOperationException();
}
public String storeType() {
return storeType;
}
public boolean isReadOnly() {
return readOnly;
}
// Unsupported IDevTree methods below
public void add(String path, IManagedObject object) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void mkdir(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void mkdirs(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void rm(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void rmdir(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void symlink(String str, String str1) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void unmount(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void mount(String str, hep.aida.ITree iTree, String str2) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void mv(String str, String str1) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public String pwd() {
throw new UnsupportedOperationException();
}
public void ls() throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void ls(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void ls(String str, boolean param) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void ls(String str, boolean param, java.io.OutputStream outputStream) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void cd(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void commit() throws java.io.IOException {
throw new UnsupportedOperationException();
}
public void cp(String str, String str1) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public void cp(String str, String str1, boolean param) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public hep.aida.ITree findTree(String str) throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public String[] listObjectNames() throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
public String[] listObjectTypes() throws java.lang.IllegalArgumentException {
throw new UnsupportedOperationException();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
java.util.logging.Logger remoteLogger = java.util.logging.Logger.getLogger("hep.aida.ref.remote");
Level level = Level.FINEST;
remoteLogger.setLevel(level);
Handler[] handlers = remoteLogger.getHandlers();
for (int i=0; i<handlers.length; i++) {
handlers[i].setLevel(level);
handlers[i].setFormatter( new SimpleFormatter() {
public String format(LogRecord record) {
String tmp = super.format(record);
String result = tmp.replaceFirst("\n", " :: \t");
return result;
}
} );
}
RemoteTree tree = new RemoteTree();
tree.addObject("/", new RemoteHistogram1D("h00"));
tree.addFolder("/hist/");
tree.addObject("/hist/", new RemoteHistogram1D("h0111"));
tree.addFolder("/hist/dir0/");
tree.addObject("/hist/dir0/", new RemoteHistogram1D("h01"));
tree.addObject("/hist/dir0/", new RemoteHistogram1D("h02"));
tree.addObject("/hist/dir0/", new RemoteHistogram1D("h03"));
tree.addFolder("/hist/dir1/");
tree.addObject("/hist/dir1/", new RemoteHistogram1D("h11"));
tree.addObject("/hist/dir1/", new RemoteHistogram1D("h12"));
tree.addObject("/hist/dir1/", new RemoteHistogram1D("h13"));
tree.addFolder("/hist/dir1/subdir/");
tree.addObject("/hist/dir1/subdir/", new RemoteHistogram1D("h13"));
tree.addFolder("/hist/dir2/");
tree.addObject("/hist/dir2/", new RemoteHistogram1D("h21"));
tree.addObject("/hist/dir2/", new RemoteHistogram1D("h22"));
tree.addObject("/hist/dir2/", new RemoteHistogram1D("h23"));
String path = "/hist/dir1/h12";
Object obj = tree.find(path);
System.out.println("PATH="+path+", FOUND="+obj);
path = "/hist/dir2/h22";
obj = tree.find(path);
System.out.println("PATH="+path+", FOUND="+obj);
path = "/hist/dir2/h23";
obj = tree.find(path);
System.out.println("PATH="+path+", FOUND="+obj);
//hep.aida.ref.tree.TreeUpdater updater = new hep.aida.ref.tree.TreeUpdater(tree);
//updater.startUpdating();
path = "/JasServerInfo/Free\\/Used Memory";
String name = AidaUtils.parseName(path);
String objDir = AidaUtils.parseDirName(path);
IManagedObject h = new RemoteHistogram1D(name);
// Make sure all directories in the path exist.
if(tree instanceof RemoteTree) ((RemoteTree) tree).addFolder(objDir);
else tree.mkdirs(objDir);
if(tree instanceof RemoteTree) ((RemoteTree) tree).addObject(objDir, h);
else tree.add(objDir, h);
if (h instanceof RemoteManagedObject) {
((RemoteManagedObject) h).setTreeFolder(objDir);
if (h instanceof RemoteUnavailableObject) ((RemoteManagedObject) h).setDataValid(true);
else ((RemoteManagedObject) h).setDataValid(false);
}
String pathS = "/";
boolean recursiveS = false;
String[] names = tree.listObjectNames(pathS, recursiveS);
String[] types = tree.listObjectTypes(pathS, recursiveS);
System.out.println("\nFor path=\""+pathS+"\", recursive="+recursiveS+", N_names="+names.length+" N_types="+types.length);
for (int i=0; i<names.length; i++) {
System.out.println("\t"+i+" name="+names[i]+" type="+types[i]);
}
pathS = "/";
recursiveS = true;
names = tree.listObjectNames(pathS, recursiveS);
types = tree.listObjectTypes(pathS, recursiveS);
System.out.println("\nFor path=\""+pathS+"\", recursive="+recursiveS+", N_names="+names.length+" N_types="+types.length);
for (int i=0; i<names.length; i++) {
System.out.println("\t"+i+" name="+names[i]+" type="+types[i]);
}
pathS = "/hist/";
recursiveS = false;
names = tree.listObjectNames(pathS, recursiveS);
types = tree.listObjectTypes(pathS, recursiveS);
System.out.println("\nFor path=\""+pathS+"\", recursive="+recursiveS+", N_names="+names.length+" N_types="+types.length);
for (int i=0; i<names.length; i++) {
System.out.println("\t"+i+" name="+names[i]+" type="+types[i]);
//System.out.println("\t"+i+" name="+names[i]);
}
pathS = "/hist/";
recursiveS = true;
names = tree.listObjectNames(pathS, recursiveS);
types = tree.listObjectTypes(pathS, recursiveS);
System.out.println("\nFor path=\""+pathS+"\", recursive="+recursiveS+", N_names="+names.length+" N_types="+types.length);
for (int i=0; i<names.length; i++) {
System.out.println("\t"+i+" name="+names[i]+" type="+types[i]);
//System.out.println("\t"+i+" name="+names[i]);
}
pathS = "/hist/dir1";
recursiveS = false;
names = tree.listObjectNames(pathS, recursiveS);
types = tree.listObjectTypes(pathS, recursiveS);
System.out.println("\nFor path=\""+pathS+"\", recursive="+recursiveS+", N_names="+names.length+" N_types="+types.length);
for (int i=0; i<names.length; i++) {
System.out.println("\t"+i+" name="+names[i]+" type="+types[i]);
//System.out.println("\t"+i+" name="+names[i]);
}
pathS = "/hist/dir1";
recursiveS = true;
names = tree.listObjectNames(pathS, recursiveS);
types = tree.listObjectTypes(pathS, recursiveS);
System.out.println("\nFor path=\""+pathS+"\", recursive="+recursiveS+", N_names="+names.length+" N_types="+types.length);
for (int i=0; i<names.length; i++) {
System.out.println("\t"+i+" name="+names[i]+" type="+types[i]);
//System.out.println("\t"+i+" name="+names[i]);
}
}
}