package org.dbxml.client.xmldb.resources;

/*
 * dbXML License, Version 1.0
 *
 *
 * Copyright (c) 1999-2001 The dbXML Group, L.L.C.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by
 *        The dbXML Group (http://www.dbxml.com/)."
 *    Alternately, this acknowledgment may appear in the software
 *    itself, if and wherever such third-party acknowledgments normally
 *    appear.
 *
 * 4. The names "dbXML" and "The dbXML Group" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    info@dbxml.com.
 *
 * 5. Products derived from this software may not be called "dbXML",
 *    nor may "dbXML" appear in their name, without prior written
 *    permission of The dbXML Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE DBXML GROUP OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: XMLResourceImpl.java,v 1.16 2001/08/08 04:57:22 kstaken Exp $
 */

import org.xmldb.api.base.*;
import org.xmldb.api.sdk.modules.*;

import org.dbxml.core.FaultCodes;
import org.dbxml.xml.*;
import org.dbxml.xml.dom.*;
import org.dbxml.xml.sax.*;

import org.w3c.dom.*;
import org.xml.sax.*;

import org.apache.xerces.parsers.SAXParser;

import java.io.*;

/**
 * XMLResourceImpl provides an implementation to handle XML resources and
 * convert easily between Text, DOM or SAX presentations.
 * <p />
 * Note: SAX is not yet implemented.
 */
public class XMLResourceImpl
       implements org.xmldb.api.modules.XMLResource {
   protected String id = null; 
   protected String documentId = null;
   protected org.xmldb.api.base.Collection collection = null;
   protected String content = null;

   private SymbolTable symbols = null;
   private byte[] bytes = null;
          
   /**
    * Constructor for the XMLResourceImpl object
    *
    * @param id The unique id associated with this resource
    * @param collection the parent collection for the resource
    */
   public XMLResourceImpl(String id, org.xmldb.api.base.Collection collection) {
      this(id, id, collection, null);
   }

   /**
    * Constructor for the XMLResourceImpl object
    *
    * @param id The unique id associated with this resource
    * @param documentId The parent document id associated with this resource
    * @param collection the parent collection for the resource
    */
   public XMLResourceImpl(String id, String documentId, 
         org.xmldb.api.base.Collection collection) {      
      this(id, documentId, collection, null);      
   }

   /**
    * Constructor for the XMLResourceImpl object
    *
    * @param id The unique id associated with this resource    
    * @param collection the parent collection for the resource
    * @param content the content to associate with the resource
    */
   public XMLResourceImpl(String id, org.xmldb.api.base.Collection collection, 
         String content) {      
      this(id, id, collection, content);      
   }
   
   /**
    * Constructor for the XMLResourceImpl object
    *
    * @param id The unique id associated with this resource
    * @param documentId The parent document id associated with this resource
    * @param collection the parent collection for the resource
    * @param content the content to associate with the resource
    */
   public XMLResourceImpl(String id, String documentId, 
         org.xmldb.api.base.Collection collection, String content) {
      this.collection = collection;
      this.id = id;
      this.documentId = documentId;
      this.content = content;
   }

      /**
    * Constructor for the XMLResourceImpl object used in conjunction with
    * Wire Compression
    *
    * @param id The unique id associated with this resource
    * @param collection the parent collection for the resource
    * @param bytes the content to associate with the resource
    */
   public XMLResourceImpl(String id, String documentId, 
         org.xmldb.api.base.Collection collection, SymbolTable syms, byte[] bytes) {
      this.collection = collection;
      this.id = id;
      this.documentId = documentId;
      this.symbols = syms;
      this.bytes = bytes;
   }

   /**
    * Constructor for the XMLResourceImpl object used in conjunction with
    * Wire Compression
    *
    * @param id The unique id associated with this resource
    * @param collection the parent collection for the resource
    * @param bytes the content to associate with the resource
    */
   public XMLResourceImpl(String id, org.xmldb.api.base.Collection collection, 
         SymbolTable syms, byte[] bytes) {
      this(id, id, collection, syms, bytes);
   }

   /**
    * Returns the unique id for the parent document to this <code>Resource</code>
    * or null if the <code>Resource</code> does not have a parent document. 
    *
    * @return the id for the parent document of this <code>Resource</code> or 
    *  null if there is no parent document for this <code>Resource</code>.
    * @exception XMLDBException 
    */
   public String getDocumentId() throws XMLDBException {
      return documentId;
   }
          
   /**
    * Sets the Content attribute of the XMLResourceImpl object. The value being
    * set must be well formed XML text.
    *
    * @param value The new Content value
    * @exception XMLDBException
    */
   public void setContent(Object value) throws XMLDBException {
      if (value == null) {
         throw new XMLDBException(ErrorCodes.INVALID_RESOURCE);
      }
      else if (value instanceof String) {
         this.content = (String) value;
         this.bytes = null;
      }
      else {
         throw new XMLDBException(ErrorCodes.WRONG_CONTENT_TYPE);
      }
   }

   /**
    * Sets the content of the resource from a DOM Node.
    *
    * @param content Node containing the new content.
    * @exception XMLDBException
    */
   public void setContentAsDOM(Node content) throws XMLDBException {
      if (content != null) {
         this.content = new TextWriter(content).toString();
         this.bytes = null;
      }
      else {
         throw new XMLDBException(ErrorCodes.INVALID_RESOURCE);
      }
   }

   /**
    * setContentAsSAX returns a SAX ContentHandler that can be used to set the
    * content of the resource.
    *
    * @return The ContentHandler that is used to insert data into the database.
    * @exception XMLDBException
    */
   public ContentHandler setContentAsSAX() throws XMLDBException {
      return new SetContentHandler(this);
   }

   /**
    * Gets the parent Collection instance for this resource
    *
    * @return The ParentCollection value
    * @exception XMLDBException
    */
   public org.xmldb.api.base.Collection getParentCollection() throws XMLDBException {
      return collection;
   }

   /**
    * Returns the resource type for this Resource.
    * <p />
    * XML:DB defined resource types are: <p />
    * XMLResource - all XML data stored in the database<br />
    * BinaryResource - Binary blob data stored in the database<br />
    *
    * @return the resource type for the Resource.
    * @exception XMLDBException
    */
   public String getResourceType() throws XMLDBException {
      return RESOURCE_TYPE;
   }

   /**
    * Gets the Id attribute of the XMLResourceImpl object
    *
    * @return The Id value
    * @exception XMLDBException
    */
   public String getId() throws XMLDBException {
      return id;
   }

   /**
    * Gets the content of the XMLResourceImpl object
    *
    * @return The Content value
    * @exception XMLDBException
    */
   public Object getContent() throws XMLDBException {
      if ( bytes != null ) {
         DocumentImpl doc = new DocumentImpl(bytes, symbols, null);
         return TextWriter.toString(doc);
      }
      else
         return content;
   }

   /**
    * Returns the content of the resource as a DOM Node.
    *
    * @return The content as a DOM node
    * @exception XMLDBException
    */
   public Node getContentAsDOM() throws XMLDBException {
      try {
         if ( bytes != null )
            return new DocumentImpl(bytes, symbols, null);
         else
            return DOMParser.toDocument(content);
      }
      catch (Exception e) {
         throw FaultCodes.createXMLDBException(e);
      }
   }

   /**
    * getContentAsSAX enables retrieving of the content via the use of a SAX
    * ContentHandler.
    *
    * @param handler The ContentHandler to use.
    * @exception XMLDBException
    */
   public void getContentAsSAX(ContentHandler handler) throws XMLDBException {
      // TODO: should probably use JAXP
      try {
         if ( bytes != null ) {
            SAXEventGenerator events = new SAXEventGenerator(symbols, bytes);
            events.setContentHandler(handler);
            
            if (handler instanceof ErrorHandler) {
               events.setErrorHandler((ErrorHandler)handler);
            } 
            
            events.start();
         }
         else {
            XMLReader xr = new SAXParser();
            xr.setContentHandler(handler);
            
            if (handler instanceof ErrorHandler) {
               xr.setErrorHandler((ErrorHandler) handler);
            }
            
            if (content != null) {
               xr.parse(new InputSource(new StringReader(content)));
            }
         }
      }
      catch (Exception e) {
         throw FaultCodes.createXMLDBException(e);
      }
   }
}

