Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » mq » xml » [javadoc | source]
    1   /*
    2   * JBoss, Home of Professional Open Source
    3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4   * by the @authors tag. See the copyright.txt in the distribution for a
    5   * full listing of individual contributors.
    6   *
    7   * This is free software; you can redistribute it and/or modify it
    8   * under the terms of the GNU Lesser General Public License as
    9   * published by the Free Software Foundation; either version 2.1 of
   10   * the License, or (at your option) any later version.
   11   *
   12   * This software is distributed in the hope that it will be useful,
   13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15   * Lesser General Public License for more details.
   16   *
   17   * You should have received a copy of the GNU Lesser General Public
   18   * License along with this software; if not, write to the Free
   19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21   */
   22   package org.jboss.mq.xml;
   23   
   24   import java.util.Enumeration;
   25   import java.util.Hashtable;
   26   import java.util.Vector;
   27   
   28   import org.xml.sax.Attributes;
   29   
   30   /**
   31    *  XElement provides an interface to an XML element. An XElement represents an
   32    *  XML element which contains: <br>
   33    *
   34    *  <ul>
   35    *    <li> Name (required)
   36    *    <li> Attributes (optional)
   37    *    <li> character data (optional)
   38    *    <li> other elements (optional)
   39    *  </ul>
   40    *  <p>
   41    *
   42    *  It is important to understand the diffrence between an "field" XElement and
   43    *  a non "field" XElement. If an XElement does not contain any sub elements, it
   44    *  is considered a "field" XElement. The <code>getField(String)</code> and
   45    *  <code>getValue()</code> functions will throw an XElementException if they
   46    *  are used on non "attribute" objects. This give you a little bit type
   47    *  checking (You'll get an exception if you try to access the character data of
   48    *  an element that has sub elements). <p>
   49    *
   50    *  If XElement is not an field, then it contains other XElements and optionaly
   51    *  some text. The text data can be accessed with the <code>getText()</code>
   52    *  method and the sub elements with the <code>iterator()</code> or with <code>
   53    *  getElementXXX()</code> fuctions. Since XML and thus XElements provide a tree
   54    *  type data structure, traversing the tree to access leaf data can be
   55    *  cumbersom if you have a 'deep' tree. For example, you may have to do: <code>
   56    *  element.getElement("tree").getElement("branch").getElement("leaf")</code>
   57    *  access a XElement 3 levels deep in the tree. To access deep elements easier,
   58    *  XElements lets you use 'reletive' names to access deep elements. Using
   59    *  reletive names, you could access the same element in previous example doing:
   60    *  <code>element.getElement("tree/branch/leaf")</code> When using relative
   61    *  names, keep in mind that "." will get the current XElement, and ".." will
   62    *  get parent XElement. Very similar to how URLs work.
   63    *
   64    * @author     Hiram Chirino (Cojonudo14@hotmail.com)
   65    * @created    August 16, 2001
   66    * @version    $Revision: 55382 $
   67    */
   68   public class XElement {
   69   
   70      private XElement parent = null;
   71      private String   name = null;
   72      private Hashtable metadata = new Hashtable();
   73      private Vector   contents = new Vector();
   74      private final static String nl = System.getProperty( "line.separator" );
   75   
   76      /**
   77       *  Constructs an empty object.
   78       *
   79       * @param  objectName  the tag or element name that this object represents.
   80       */
   81      public XElement( String objectName ) {
   82         if ( objectName == null ) {
   83            throw new NullPointerException();
   84         }
   85         name = objectName;
   86         contents.addElement( new StringBuffer() );
   87      }
   88   
   89      /**
   90       *  Constructs an XElement with it's parent and metatags set.
   91       *
   92       * @param  objectName  the tag or element name that this object represents.
   93       * @param  atts        Description of Parameter
   94       */
   95      public XElement( String objectName, Attributes atts ) {
   96         if ( objectName == null ) {
   97            throw new NullPointerException();
   98         }
   99         if ( atts == null ) {
  100            throw new NullPointerException();
  101         }
  102         name = objectName;
  103         contents.addElement( new StringBuffer() );
  104         for ( int i = 0; i < atts.getLength(); i++ ) {
  105            metadata.put( atts.getQName( i ), atts.getValue( i ) );
  106            //metadata.put( atts.getLocalName( i ), atts.getValue( i ) );
  107         }
  108      }
  109   
  110      /**
  111       *  Sets/Adds a metatag value Only metatags whose value is not empty will
  112       *  display when the <code>toString()</code> methods is called.
  113       *
  114       * @param  key    the name of the metatag
  115       * @param  value  the value to set the metatag to.
  116       */
  117      public void setAttribute( String key, String value ) {
  118         metadata.put( key, value );
  119      }
  120   
  121      /**
  122       *  Sets the object name
  123       *
  124       * @param  newName
  125       */
  126      public void setName( String newName ) {
  127         name = newName;
  128      }
  129   
  130      /**
  131       *  Gets the character data that was within this object. This fuction can
  132       *  only be used on objects that are attributes.
  133       *
  134       * @param  value               The new Value value
  135       * @returns                    the character data contained within this
  136       *      object.
  137       * @throws  XElementException  if the object was not an attribute object
  138       */
  139      public void setValue( String value )
  140         throws XElementException {
  141         if ( !isField() ) {
  142            throw new XElementException( "" + getName() + " is not an attribute object" );
  143         }
  144         contents.setElementAt( new StringBuffer( value ), 0 );
  145      }
  146   
  147   
  148      /**
  149       *  Sets/Adds a attribute
  150       *
  151       * @param  key                    the name of the attribute element
  152       * @param  value                  the value to set the attribute to.
  153       * @exception  XElementException  Description of Exception
  154       */
  155      public void setField( String key, String value )
  156         throws XElementException {
  157         getElement( key ).setValue( value );
  158      }
  159   
  160      /**
  161       *  Returns the value of a meta data value.
  162       *
  163       * @param  key  Description of Parameter
  164       * @return      The Attribute value
  165       * @returns     the value of the metadata item, or "" if the item has not
  166       *      been set.
  167       */
  168      public String getAttribute( String key ) {
  169         String t = ( String )metadata.get( key );
  170         if ( t == null ) {
  171            return "";
  172         }
  173         return t;
  174      }
  175   
  176      /**
  177       *  Returns the element name (tag name) of this XElement
  178       *
  179       * @return     The Name value
  180       * @returns
  181       */
  182      public java.lang.String getName() {
  183         return name;
  184      }
  185   
  186      /**
  187       *  Get the parent of this object, or the object the contains this one.
  188       *
  189       * @return     The Parent value
  190       * @returns    null if this object is not contained by any other XElement.
  191       */
  192      public XElement getParent() {
  193         return parent;
  194      }
  195   
  196      /**
  197       *  Gets the TRIMMED character data that was within this object. This differs
  198       *  from getValue() in that:
  199       *  <UL>
  200       *    <LI> this fuction will work on attribute and non attribute XElements
  201       *
  202       *    <LI> it will trim both ends of the character data before returning it.
  203       *
  204       *  </UL>
  205       *
  206       *
  207       * @return     The Text value
  208       * @returns    the character data contained within this object.
  209       */
  210      public String getText() {
  211         return contents.elementAt( 0 ).toString().trim();
  212      }
  213   
  214      /**
  215       *  Gets the character data that was within this object. This fuction can
  216       *  only be used on objects that are attributes.
  217       *
  218       * @return                     The Value value
  219       * @returns                    the character data contained within this
  220       *      object.
  221       * @throws  XElementException  if the object was not an attribute object
  222       */
  223      public String getValue()
  224         throws XElementException {
  225         if ( !isField() ) {
  226            throw new XElementException( "" + getName() + " is not an attribute object" );
  227         }
  228         return contents.elementAt( 0 ).toString();
  229      }
  230   
  231      /**
  232       *  Returns the first object contained in this object named relativeName.
  233       *
  234       * @param  relativeName        The name of the object to find
  235       * @return                     The Element value
  236       * @returns                    the XElement named relativeName
  237       * @throws  XElementException  if the object could not be found.
  238       */
  239      public XElement getElement( String relativeName )
  240         throws XElementException {
  241         if ( relativeName == null ) {
  242            throw new NullPointerException();
  243         }
  244   
  245         String names[] = {null, relativeName};
  246   
  247         // Does the name have a "/" in it?
  248         String split[] = splitFront( relativeName, "/" );
  249         if ( split != null ) {
  250   
  251            // was it an absolute name? (started with a '/')
  252            if ( split[0].length() == 0 ) {
  253               // we are the parent
  254               if ( parent == null ) {
  255                  split[0] = null;
  256               }
  257               // Let my parent handle the request.
  258               else {
  259                  return parent.getElement( relativeName );
  260               }
  261            }
  262   
  263            // did we have a trailing / in the name?
  264            if ( split[1].length() == 0 ) {
  265               // For the case of "/",
  266               if ( split[0].equals( null ) ) {
  267                  return this;
  268               }
  269   
  270               //otherwise it is an error
  271               // to leave a trailing /, for example tree/leaf/
  272               throw new XElementException( "Invalid name (trailing '/') : " + relativeName );
  273            }
  274   
  275            names = split;
  276         }
  277   
  278         if ( names[0] == null ) {
  279            for ( int i = 1; i < contents.size(); i++ ) {
  280               XElement o = ( XElement )contents.elementAt( i );
  281               if ( names[1].equals( o.getName() ) ) {
  282                  return o;
  283               }
  284            }
  285         } else {
  286            if ( names[0].equals( "." ) ) {
  287               return getElement( names[1] );
  288            } else if ( names[0].equals( ".." ) ) {
  289               if ( parent != null ) {
  290                  return parent.getElement( names[1] );
  291               } else {
  292                  throw new XElementException( "Invalid name (" + getName() + " has no parent) : " + relativeName );
  293               }
  294            } else {
  295               for ( int i = 1; i < contents.size(); i++ ) {
  296                  XElement o = ( XElement )contents.elementAt( i );
  297                  if ( names[0].equals( o.getName() ) ) {
  298                     return o.getElement( names[1] );
  299                  }
  300               }
  301            }
  302         }
  303   
  304         throw new XElementException( "Invalid name (" + getName() + " does not contain the name) : " + relativeName );
  305      }
  306   
  307   
  308      /**
  309       *  Gets the value of a contained attribute object.
  310       *
  311       * @param  objectName          The name of the attribute object.
  312       * @return                     The Field value
  313       * @returns                    the value of the attribute object.
  314       * @throws  XElementException  if the object does not exist or if its not an
  315       *      attribute object.
  316       */
  317      public String getField( String objectName )
  318         throws XElementException {
  319         return getElement( objectName ).getValue();
  320      }
  321   
  322      /**
  323       *  Returns true if the object is an attribute object. An object is an
  324       *  attribute object if it does not contain any other objects.
  325       *
  326       * @return     The Field value
  327       * @returns    true if the object is an attribute object.
  328       */
  329      public boolean isField() {
  330         return contents.size() == 1;
  331      }
  332   
  333      /**
  334       *  Returns all the contained objects with the specified name.
  335       *
  336       * @param  relativeName  The name of the objects
  337       * @return               The ElementsNamed value
  338       * @returns              whose name is relativeName;
  339       */
  340      public java.util.Enumeration getElementsNamed( String relativeName ) {
  341   
  342         Vector t = new Vector();
  343         addElementsToVector( t, relativeName );
  344         return t.elements();
  345      }
  346   
  347      /**
  348       *  Adds and appends string data to the objects text.
  349       *
  350       * @param  data  Description of Parameter
  351       */
  352      public void add( String data ) {
  353         ( ( StringBuffer )contents.elementAt( 0 ) ).append( data );
  354      }
  355   
  356      /**
  357       *  Serializes this object into a string.
  358       *
  359       * @return    Description of the Returned Value
  360       */
  361      public String toString() {
  362         return toString( 0, true );
  363      }
  364   
  365      /**
  366       *  Adds an XElement to the set of XElements that are contained by this
  367       *  object.
  368       *
  369       * @param  subObject
  370       */
  371      public void addElement( XElement subObject ) {
  372         contents.addElement( subObject );
  373         subObject.parent = this;
  374      }
  375   
  376      /**
  377       *  Adds an XElement to the set of XElements that are contained by this
  378       *  object.
  379       *
  380       * @param  key    The feature to be added to the Field attribute
  381       * @param  value  The feature to be added to the Field attribute
  382       */
  383      public void addField( String key, String value ) {
  384         XElement subObject = new XElement( key );
  385         subObject.add( value );
  386         addElement( subObject );
  387      }
  388   
  389      /**
  390       *  Tests to see if this object contains the specified object.
  391       *
  392       * @param  objectName  The name of the object.
  393       * @return             Description of the Returned Value
  394       * @returns            true if the object exits.
  395       */
  396      public boolean containsElement( String objectName ) {
  397         try {
  398            getElement( objectName );
  399            return true;
  400         } catch ( XElementException e ) {
  401            return false;
  402         }
  403      }
  404   
  405      /**
  406       *  Tests to see if this object contains the specified attribute object.
  407       *
  408       * @param  objectName  The name of the attribute object.
  409       * @return             Description of the Returned Value
  410       * @returns            true if the attribute exits.
  411       */
  412      public boolean containsField( String objectName ) {
  413         try {
  414            XElement obj = getElement( objectName );
  415            return obj.isField();
  416         } catch ( XElementException e ) {
  417            return false;
  418         }
  419      }
  420   
  421      /**
  422       *  Serializes this object into a string.
  423       *
  424       * @param  nestingLevel  how many tabs to prepend to output
  425       * @param  indent        Description of Parameter
  426       * @return               Description of the Returned Value
  427       */
  428      public String toString( int nestingLevel, boolean indent ) {
  429         try {
  430            StringBuffer indentation = new StringBuffer();
  431            StringBuffer rc = new StringBuffer();
  432            if ( indent ) {
  433               for ( int i = 0; i < nestingLevel; i++ ) {
  434                  indentation.append( '\t' );
  435               }
  436            }
  437            rc.append( indentation.toString() );
  438            rc.append( "<" );
  439            rc.append( getName() );
  440            Enumeration enumeration = metadata.keys();
  441            while ( enumeration.hasMoreElements() ) {
  442               String key = ( String )enumeration.nextElement();
  443               String value = ( String )metadata.get( key );
  444               rc.append( ' ' );
  445               rc.append( key );
  446               rc.append( "=\"" );
  447               rc.append( metaValueEncode( value ) );
  448               rc.append( '"' );
  449            }
  450            if ( isField() ) {
  451               if ( getValue().length() == 0 ) {
  452                  rc.append( "/>" );
  453                  rc.append( nl );
  454               } else {
  455                  rc.append( '>' );
  456                  rc.append( valueEncode( getValue() ) );
  457                  rc.append( "</" );
  458                  rc.append( getName() );
  459                  rc.append( '>' );
  460                  rc.append( nl );
  461               }
  462            } else {
  463               rc.append( '>' );
  464               rc.append( nl );
  465               String text = getText();
  466               if ( text.length() > 0 ) {
  467                  rc.append( indentation.toString() + "\t" );
  468                  rc.append( getText() );
  469                  rc.append( nl );
  470               }
  471               for ( int i = 1; i < contents.size(); i++ ) {
  472                  Object o = contents.elementAt( i );
  473                  rc.append( ( ( XElement )o ).toString( nestingLevel + 1, indent ) );
  474               }
  475               rc.append( indentation.toString() );
  476               rc.append( "</" );
  477               rc.append( getName() );
  478               rc.append( '>' );
  479               rc.append( nl );
  480            }
  481            return rc.toString();
  482         } catch ( XElementException e ) {
  483            // This should not occur!
  484            e.printStackTrace();
  485            System.exit( 1 );
  486            return "";
  487         }
  488      }
  489   
  490      /**
  491       *  Serializes this object into a XML document String.
  492       *
  493       * @param  indent  Description of Parameter
  494       * @return         Description of the Returned Value
  495       */
  496      public String toXML( boolean indent ) {
  497         return
  498               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + nl +
  499               toString( 0, indent );
  500      }
  501   
  502      /**
  503       *  Removes this XElement from the parent.
  504       *
  505       * @throws  XElementException  if the object did not have a parent
  506       */
  507      public void removeFromParent()
  508         throws XElementException {
  509         if ( parent == null ) {
  510            throw new XElementException( "" + getName() + " does not have a parent" );
  511         }
  512   
  513         parent.contents.remove( this );
  514         parent = null;
  515      }
  516   
  517      /**
  518       * @return     Description of the Returned Value
  519       * @returns    an Enumeration of all the XElement conatained within this
  520       *      object.
  521       */
  522      public Enumeration elements() {
  523         return getElementsNamed( "*" );
  524      }
  525   
  526      /**
  527       *  adds all the contains elements to the vector that match the relative
  528       *  name.
  529       *
  530       * @param  t             The feature to be added to the ElementsToVector
  531       *      attribute
  532       * @param  relativeName  The feature to be added to the ElementsToVector
  533       *      attribute
  534       */
  535      private void addElementsToVector( Vector t, String relativeName ) {
  536   
  537         String names[] = {null, relativeName};
  538   
  539         // Does the name have a "/" in it?
  540         String split[] = splitFront( relativeName, "/" );
  541         if ( split != null ) {
  542   
  543            // was it an absolute name? (started with a '/')
  544            if ( split[0].length() == 0 ) {
  545               // we are the parent
  546               if ( parent == null ) {
  547                  split[0] = null;
  548               } else {
  549                  // Let my parent handle the request.
  550                  parent.addElementsToVector( t, relativeName );
  551                  return;
  552               }
  553            }
  554   
  555            // did we have a trailing / in the name?
  556            if ( split[1].length() == 0 ) {
  557               return;
  558            }
  559            names = split;
  560         }
  561   
  562         if ( names[0] == null ) {
  563            if ( names[1].equals( "*" ) ) {
  564               for ( int i = 1; i < contents.size(); i++ ) {
  565                  t.addElement( contents.elementAt( i ) );
  566               }
  567            } else {
  568               for ( int i = 1; i < contents.size(); i++ ) {
  569                  XElement o = ( XElement )contents.elementAt( i );
  570                  if ( names[1].equals( o.getName() ) ) {
  571                     t.addElement( o );
  572                  }
  573               }
  574            }
  575         } else {
  576            if ( names[0].equals( "." ) ) {
  577               addElementsToVector( t, names[1] );
  578               return;
  579            } else if ( names[0].equals( ".." ) ) {
  580               if ( parent != null ) {
  581                  parent.addElementsToVector( t, names[1] );
  582               }
  583               return;
  584            } else {
  585               for ( int i = 1; i < contents.size(); i++ ) {
  586                  XElement o = ( XElement )contents.elementAt( i );
  587                  if ( names[0].equals( o.getName() ) ) {
  588                     o.addElementsToVector( t, names[1] );
  589                  }
  590               }
  591            }
  592         }
  593      }
  594   
  595      /**
  596       *  Constructs an empty object.
  597       *
  598       * @param  is                       Description of Parameter
  599       * @return                          Description of the Returned Value
  600       * @exception  XElementException    Description of Exception
  601       * @exception  java.io.IOException  Description of Exception
  602       */
  603      public static XElement createFrom( java.io.InputStream is )
  604         throws XElementException, java.io.IOException {
  605   class MyRecordConsumer implements XElementConsumer {
  606   
  607            XElement   root = null;
  608   
  609            public void documentEndEvent() {
  610            }
  611   
  612            public void documentStartEvent() {
  613            }
  614   
  615            public void recordReadEvent( XElement o ) {
  616               root = o;
  617            }
  618         }
  619   
  620         MyRecordConsumer consumer = new MyRecordConsumer();
  621         XElementProducer producer = new XElementProducer( consumer );
  622   
  623         try {
  624            producer.parse( is );
  625            if ( consumer.root == null ) {
  626               throw new XElementException( "No root element" );
  627            }
  628            return consumer.root;
  629         } catch ( java.io.IOException e ) {
  630            throw e;
  631         } catch ( Exception e ) {
  632            throw new XElementException( "Parse Error: " + e );
  633         }
  634      }
  635   
  636      /**
  637       *  Constructs an empty object.
  638       *
  639       * @param  url                      Description of Parameter
  640       * @return                          Description of the Returned Value
  641       * @exception  XElementException    Description of Exception
  642       * @exception  java.io.IOException  Description of Exception
  643       */
  644      public static XElement createFrom( java.net.URL url )
  645         throws XElementException, java.io.IOException {
  646   class MyRecordConsumer implements XElementConsumer {
  647   
  648            XElement   root = null;
  649   
  650            public void documentEndEvent() {
  651            }
  652   
  653            public void documentStartEvent() {
  654            }
  655   
  656            public void recordReadEvent( XElement o ) {
  657               root = o;
  658            }
  659         }
  660   
  661         MyRecordConsumer consumer = new MyRecordConsumer();
  662         XElementProducer producer = new XElementProducer( consumer );
  663   
  664         try {
  665            producer.parse( url );
  666            if ( consumer.root == null ) {
  667               throw new XElementException( "No root element" );
  668            }
  669            return consumer.root;
  670         } catch ( java.io.IOException e ) {
  671            throw e;
  672         } catch ( Exception e ) {
  673            throw new XElementException( "Parse Error: " + e );
  674         }
  675      }
  676   
  677   
  678      private static String findAndReplace( String value, String searchStr, String replaceStr ) {
  679         StringBuffer buffer = new StringBuffer( value.length() );
  680         while ( value.length() > 0 ) {
  681            int pos = value.indexOf( searchStr );
  682            if ( pos != -1 ) {
  683               buffer.append( value.substring( 0, pos ) );
  684               buffer.append( replaceStr );
  685               if ( pos + searchStr.length() < value.length() ) {
  686                  value = value.substring( pos + searchStr.length() );
  687               } else {
  688                  value = "";
  689               }
  690            } else {
  691               buffer.append( value );
  692               value = "";
  693            }
  694         }
  695         return buffer.toString();
  696      }
  697   
  698      private static String metaValueEncode( String value ) {
  699         value = findAndReplace( value, "&", "&amp;" );
  700         value = findAndReplace( value, "\"", "&quot;" );
  701         value = findAndReplace( value, "'", "&apos;" );
  702         return utf8Encode( value );
  703      }
  704   
  705   
  706      private static String utf8Encode( String value ) {
  707         try {
  708            //char buff[] = new char[value.length()];
  709            //value.getChars( 0, buff.length, buff, 0 );
  710            //sun.io.CharToByteUTF8 conv = new sun.io.CharToByteUTF8();
  711            //byte b[] = conv.convertAll( buff );
  712            return new String( value.getBytes("UTF-8") );
  713         } catch ( Exception e ) {
  714            return null;
  715         }
  716      }
  717   
  718      private static String valueEncode( String value ) {
  719         value = findAndReplace( value, "&", "&amp;" );
  720         value = findAndReplace( value, "<", "&lt;" );
  721         value = findAndReplace( value, ">", "&gt;" );
  722         return utf8Encode( value );
  723      }
  724   
  725   
  726      private static String[] splitFront( String string, String splitMarker ) {
  727   
  728         if ( string == null || splitMarker == null ) {
  729            throw new NullPointerException();
  730         }
  731   
  732         String front;
  733         String back;
  734   
  735         int pos = string.indexOf( splitMarker );
  736         if ( pos == -1 ) {
  737            return null;
  738         }
  739   
  740         int l = splitMarker.length();
  741         front = string.substring( 0, pos );
  742         if ( pos + l >= string.length() ) {
  743            back = "";
  744         } else {
  745            back = string.substring( pos + l );
  746         }
  747   
  748         String rc[] = {front, back};
  749         return rc;
  750      }
  751      
  752      public String getOptionalField( String field) throws XElementException {
  753         if ( !containsField(field) ) 
  754            return null;
  755         return getField(field);
  756      }
  757   
  758      public void setOptionalField( String field, String value) throws XElementException {
  759         if ( value == null ) {
  760            if( containsField(field) )
  761            	  getElement(field).removeFromParent();
  762            return;
  763         }
  764         if( containsField(field) )
  765         	setField(field, value);
  766         else
  767         	addField(field, value);
  768      }
  769      
  770   }

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » mq » xml » [javadoc | source]