// Copyright 2002-2007, FreeHEP.
package hep.aida.ref.xml;

import hep.aida.ITree;
import hep.aida.dev.IDevTree;
import hep.aida.dev.IOnDemandStore;
import hep.aida.ref.AidaUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PushbackInputStream;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import de.schlichtherle.io.File;
import de.schlichtherle.io.FileInputStream;
import de.schlichtherle.io.FileOutputStream;
import hep.aida.IManagedObject;
import hep.aida.dev.IAddable;
import hep.aida.util.Addable;

/**
 * Store associated to XML file, directory structure or archive.
 * 
 * @author tonyj
 * @author Mark Donszelmann
 * @version $Id: AidaXMLStore.java 13360 2007-10-02 23:13:06Z serbo $
 */
public class AidaXMLStore implements IOnDemandStore {
	protected File root;
        protected boolean createNew = false;
        protected boolean useProxies = false;

	public boolean isReadOnly() {
		return false;
	}

	int n = 0;
	
	// IOnDemandStore methods
        // This method is only called for a root file with structure: "zip" or "dir"
	public void read(IDevTree tree, String path)
			throws IllegalArgumentException, IOException {
//	    System.err.println("--> "+root+" "+path);
		if (root == null)
			return;

		path = path.startsWith("/") ? path.substring(1) : path;

		File file = new File(root, path);
		//System.err.println("file dir="+file.isDirectory()+", path="+file.getInnerEntryName());
		if (file.isDirectory()) {
			tree.mkdirs("/"+path);
			File[] files = (File[]) file.listFiles();
			int rootLength = root.getPath().length()+1;
			for (int i = 0; i < files.length; i++) {
				String tmpPath = files[i].getInnerEntryName();
				if (tmpPath == null) tmpPath = files[i].getPath().substring(rootLength);
//				System.err.println(i+"\t "+tmpPath);
				if (files[i].isDirectory()) {
					tree.mkdirs("/"+tmpPath);
					n++;
				} else {
					read(tree, "/"+tmpPath);
				}
			}
			tree.hasBeenFilled("/"+path);
                } else if (useProxies) {
                    String treePath = file.getInnerEntryName();
                    if (treePath == null) treePath = file.getPath();
                    
                    String type = "IManagedObject";
                    int index = treePath.lastIndexOf(".");
                    if (index >= 0) {
                        type = treePath.substring(index+1);
                        treePath = treePath.substring(0, index);
                    }
                    IManagedObject mo = AidaObjectProxy.createProxy(this, path, type);
                    
                    tree.add(AidaUtils.parseDirName(treePath), mo);
                } else {
			InputStream in = new FileInputStream(file);
			try {
				parse(tree, false, in, true);
				n++;
			} catch (Exception x) {
				IOException xx = new IOException("Error reading "
						+ tree.storeName() + " " + path);
				xx.initCause(x);
				throw xx;
			} finally {
				if (in != null) {
					in.close();
				}
			}
		}
//		System.err.println(n);
	}

	// IStore methds
	public void read(IDevTree tree, Map optionsMap, boolean readOnly,
			boolean createNew) throws IOException {

		File file = new File(tree.storeName());
		file.isDirectory();
                this.createNew = createNew;
		boolean exists = file.exists();
		if (!exists && (readOnly || !createNew)) {
			throw new IOException("File " + file + " does not exist.");
		}
		if (exists && !readOnly && !createNew && !file.canWrite()) {
			throw new IOException("File " + file + " is a read-only file.");
		}
                if (exists) {
			// FIXME ???
			readOnly |= file.canWrite();

			if (file.isFile()) {
				// we select a plain (xml) file 
				// (recognized archive files are NOT files)
				root = null;
				InputStream in = new FileInputStream(file);
				try {
					String validateString = (String) optionsMap.get("validate");
					boolean validate = (validateString == null)
							|| validateString.equalsIgnoreCase("true");
					parse(tree, true, in, validate);
				} catch (Exception x) {
					IOException xx = new IOException("Error reading "
							+ tree.storeName());
					xx.initCause(x);
					System.err.println(x);
					x.printStackTrace();
					throw xx;
				} finally {
					if (in != null) {
						in.close();
					}
				}
			} else {
				// archive and/or directory
				root = file;
                                useProxies = toBoolean(optionsMap,"useProxies", true);
				read(tree, "/");
			}
		}
	}

	public void commit(IDevTree tree, Map optionsMap) throws IOException {
		String createString = (String) optionsMap.get("createNew");
                if (createString != null &&  createString.equalsIgnoreCase("true"))
                    createNew = true;
                
		String cString = (String) optionsMap.get("compress");
		boolean zip = cString != null && cString.equalsIgnoreCase("zip");
		boolean compress = (cString == null) || cString.equalsIgnoreCase("yes")
				|| cString.equalsIgnoreCase("true")
				|| cString.equalsIgnoreCase("gzip");
		String bString = (String) optionsMap.get("binary");
		boolean binary = (bString != null)
				&& (bString.equalsIgnoreCase("yes") || bString
						.equalsIgnoreCase("true"));
		String[] skip = null;
		if (optionsMap.get("skip") != null)
			skip = AidaUtils.parseString((String) optionsMap.get("skip"));
                
                java.io.File f = new java.io.File(tree.storeName());
                if (createNew && f.exists() && !f.isDirectory()) f.delete();
		commit(tree, new File(tree.storeName()), skip, zip,
				compress, binary);
	}

	public void commit(ITree tree, File file, String[] skip, boolean zip,
			boolean compress, boolean binary) throws IOException {
		if (file.isDirectory() || zip) {
			AidaZipXMLWriter zw = new AidaZipXMLWriter(file, binary, skip);
			zw.toXML(tree);
			zw.close();
		} else {
			OutputStream os = new FileOutputStream(file);
			if (compress) {
				os = new GZIPOutputStream(os);
			}
			AidaXMLWriter out;
			if (binary) {
				out = new AidaXMLWriter(new DataOutputStream(
						new BufferedOutputStream(os)));
			} else {
				out = new AidaXMLWriter(new BufferedWriter(
						new OutputStreamWriter(os)));
			}
			out.toXML(tree);
			out.close();
		}
	}

	public void close() {
		root = null;
	}

        IManagedObject readManagedObject(String path) throws IOException {
            Addable addable = new Addable();
            File file = new File(root, path);
            InputStream in = new FileInputStream(file);
            try {
                parse(addable, false, in, true);
                n++;
            } catch (Exception x) {
                IOException xx = new IOException("Error creating managed object for "+ path);
                xx.initCause(x);
                throw xx;
            } finally {
                if (in != null) {
                    in.close();
                }
            }
             return addable.object();
        }
        
	// NOTE: we need to change this to handle partial reads...
	protected void parse(IAddable tree, boolean markAsFilled, InputStream in,
			boolean validate) throws SAXException,
			ParserConfigurationException, IOException {
		byte[] magic = new byte[4];

		// Check filetype
		PushbackInputStream pin = new PushbackInputStream(in, magic.length);

		// peek first four bytes
		int b = pin.read(magic);
		if (b != magic.length)
			throw new IOException("Unexpected EOF");
		pin.unread(magic);

		// gzipped stream ?
		if (((magic[0] & 0xff) == 0x1f) && ((magic[1] & 0xff) == 0x8b)) {
			pin = new PushbackInputStream(new GZIPInputStream(pin),
					magic.length);
			b = pin.read(magic);
			if (b != magic.length)
				throw new IOException("Unexpected EOF");
			pin.unread(magic);
		}
		in = pin;

		// WBXML ?
		boolean binary = ((magic[0] & 0xff) == 0x03)
				&& ((magic[1] & 0xff) == 0x00)
				&& ((magic[2] & 0xff) == 0x00)
				&& ((magic[3] & 0xff) == 0x6a);

		in = new BufferedInputStream(in);
		AidaHandlerImpl handler = new AidaHandlerImpl(tree, markAsFilled);
		if (binary) {
			// Binary XML
			AidaWBXMLParser parser = new AidaWBXMLParser(handler);
			parser.parse(in);
		} else {
			// Plain XML
			EntityResolver er = new AIDAEntityResolver(AidaParser.class,
					"http://aida.freehep.org/");
			AidaParser parser = new AidaParser(handler, er);
			parser.setValidate(validate);

			InputSource is = new InputSource(in);
                        String id = (tree instanceof ITree) ? ((ITree) tree).storeName() : "AidaXMLStore";
			is.setSystemId(id);
			parser.parse(is);
		}
	}

   private boolean toBoolean(Map options, String key) {
       return toBoolean(options, key, false);
   }
   private boolean toBoolean(Map options, String key, boolean def)
   {
      Object value = options.get(key);
      if (value == null) return def;
      return Boolean.valueOf(value.toString()).booleanValue();
   }
}

 

Ads help maintain this website.