Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » dom » [javadoc | source]
    1   /*
    2    * reserved comment block
    3    * DO NOT REMOVE OR ALTER!
    4    */
    5   /*
    6    * Copyright 1999-2002,2004 The Apache Software Foundation.
    7    *
    8    * Licensed under the Apache License, Version 2.0 (the "License");
    9    * you may not use this file except in compliance with the License.
   10    * You may obtain a copy of the License at
   11    *
   12    *      http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing, software
   15    * distributed under the License is distributed on an "AS IS" BASIS,
   16    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   17    * See the License for the specific language governing permissions and
   18    * limitations under the License.
   19    */
   20   
   21   package com.sun.org.apache.xerces.internal.dom;
   22   
   23   import com.sun.org.apache.xerces.internal.util.URI;
   24   import org.w3c.dom.DocumentType;
   25   import org.w3c.dom.EntityReference;
   26   import org.w3c.dom.NamedNodeMap;
   27   import org.w3c.dom.Node;
   28   
   29   /**
   30    * EntityReference models the XML &entityname; syntax, when used for
   31    * entities defined by the DOM. Entities hardcoded into XML, such as
   32    * character entities, should instead have been translated into text
   33    * by the code which generated the DOM tree.
   34    * <P>
   35    * An XML processor has the alternative of fully expanding Entities
   36    * into the normal document tree. If it does so, no EntityReference nodes
   37    * will appear.
   38    * <P>
   39    * Similarly, non-validating XML processors are not required to read
   40    * or process entity declarations made in the external subset or
   41    * declared in external parameter entities. Hence, some applications
   42    * may not make the replacement value available for Parsed Entities
   43    * of these types.
   44    * <P>
   45    * EntityReference behaves as a read-only node, and the children of
   46    * the EntityReference (which reflect those of the Entity, and should
   47    * also be read-only) give its replacement value, if any. They are
   48    * supposed to automagically stay in synch if the DocumentType is
   49    * updated with new values for the Entity.
   50    * <P>
   51    * The defined behavior makes efficient storage difficult for the DOM
   52    * implementor. We can't just look aside to the Entity's definition
   53    * in the DocumentType since those nodes have the wrong parent (unless
   54    * we can come up with a clever "imaginary parent" mechanism). We
   55    * must at least appear to clone those children... which raises the
   56    * issue of keeping the reference synchronized with its parent.
   57    * This leads me back to the "cached image of centrally defined data"
   58    * solution, much as I dislike it.
   59    * <P>
   60    * For now I have decided, since REC-DOM-Level-1-19980818 doesn't
   61    * cover this in much detail, that synchronization doesn't have to be
   62    * considered while the user is deep in the tree. That is, if you're
   63    * looking within one of the EntityReferennce's children and the Entity
   64    * changes, you won't be informed; instead, you will continue to access
   65    * the same object -- which may or may not still be part of the tree.
   66    * This is the same behavior that obtains elsewhere in the DOM if the
   67    * subtree you're looking at is deleted from its parent, so it's
   68    * acceptable here. (If it really bothers folks, we could set things
   69    * up so deleted subtrees are walked and marked invalid, but that's
   70    * not part of the DOM's defined behavior.)
   71    * <P>
   72    * As a result, only the EntityReference itself has to be aware of
   73    * changes in the Entity. And it can take advantage of the same
   74    * structure-change-monitoring code I implemented to support
   75    * DeepNodeList.
   76    *
   77    * @xerces.internal
   78    *
   79    * @author Arnaud  Le Hors, IBM
   80    * @author Joe Kesselman, IBM
   81    * @author Andy Clark, IBM
   82    * @author Ralf Pfeiffer, IBM
   83    * @since  PR-DOM-Level-1-19980818.
   84    */
   85   public class EntityReferenceImpl
   86   extends ParentNode
   87   implements EntityReference {
   88   
   89       //
   90       // Constants
   91       //
   92   
   93       /** Serialization version. */
   94       static final long serialVersionUID = -7381452955687102062L;
   95   
   96       //
   97       // Data
   98       //
   99   
  100       /** Name of Entity referenced */
  101       protected String name;
  102       /** Base URI*/
  103       protected String baseURI;
  104   
  105   
  106       /** Entity changes. */
  107       //protected int entityChanges = -1;
  108   
  109       /** Enable synchronize. */
  110       //protected boolean fEnableSynchronize = false;
  111   
  112       //
  113       // Constructors
  114       //
  115   
  116       /** Factory constructor. */
  117       public EntityReferenceImpl(CoreDocumentImpl ownerDoc, String name) {
  118           super(ownerDoc);
  119           this.name = name;
  120           isReadOnly(true);
  121           needsSyncChildren(true);
  122       }
  123   
  124       //
  125       // Node methods
  126       //
  127   
  128       /**
  129        * A short integer indicating what type of node this is. The named
  130        * constants for this value are defined in the org.w3c.dom.Node interface.
  131        */
  132       public short getNodeType() {
  133           return Node.ENTITY_REFERENCE_NODE;
  134       }
  135   
  136       /**
  137        * Returns the name of the entity referenced
  138        */
  139       public String getNodeName() {
  140           if (needsSyncData()) {
  141               synchronizeData();
  142           }
  143           return name;
  144       }
  145   
  146       /** Clone node. */
  147       public Node cloneNode(boolean deep) {
  148           EntityReferenceImpl er = (EntityReferenceImpl)super.cloneNode(deep);
  149           er.setReadOnly(true, deep);
  150           return er;
  151       }
  152   
  153       /**
  154        * Returns the absolute base URI of this node or null if the implementation
  155        * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a
  156        * null is returned.
  157        *
  158        * @return The absolute base URI of this node or null.
  159        * @since DOM Level 3
  160        */
  161       public String getBaseURI() {
  162           if (needsSyncData()) {
  163               synchronizeData();
  164           }
  165           if (baseURI == null) {
  166               DocumentType doctype;
  167               NamedNodeMap entities;
  168               EntityImpl entDef;
  169               if (null != (doctype = getOwnerDocument().getDoctype()) &&
  170                   null != (entities = doctype.getEntities())) {
  171   
  172                   entDef = (EntityImpl)entities.getNamedItem(getNodeName());
  173                   if (entDef !=null) {
  174                       return entDef.getBaseURI();
  175                   }
  176               }
  177           } else if (baseURI != null && baseURI.length() != 0 ) {// attribute value is always empty string
  178               try {
  179                   return new URI(baseURI).toString();
  180               }
  181               catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
  182                   // REVISIT: what should happen in this case?
  183                   return null;
  184               }
  185           }
  186           return baseURI;
  187       }
  188   
  189   
  190       /** NON-DOM: set base uri*/
  191       public void setBaseURI(String uri){
  192           if (needsSyncData()) {
  193               synchronizeData();
  194           }
  195           baseURI = uri;
  196       }
  197   
  198           /**
  199            * NON-DOM: compute string representation of the entity reference.
  200        * This method is used to retrieve a string value for an attribute node that has child nodes.
  201            * @return String representing a value of this entity ref. or
  202        *          null if any node other than EntityReference, Text is encountered
  203        *          during computation
  204            */
  205       protected String getEntityRefValue (){
  206           if (needsSyncChildren()){
  207               synchronizeChildren();
  208           }
  209   
  210           String value = "";
  211           if (firstChild != null){
  212             if (firstChild.getNodeType() == Node.ENTITY_REFERENCE_NODE){
  213                 value = ((EntityReferenceImpl)firstChild).getEntityRefValue();
  214             }
  215             else if (firstChild.getNodeType() == Node.TEXT_NODE){
  216               value = firstChild.getNodeValue();
  217             }
  218             else {
  219                // invalid to have other types of nodes in attr value
  220               return null;
  221             }
  222   
  223             if (firstChild.nextSibling == null){
  224               return value;
  225             }
  226             else {
  227               StringBuffer buff = new StringBuffer(value);
  228               ChildNode next = firstChild.nextSibling;
  229               while (next != null){
  230   
  231                   if (next.getNodeType() == Node.ENTITY_REFERENCE_NODE){
  232                      value = ((EntityReferenceImpl)next).getEntityRefValue();
  233                   }
  234                   else if (next.getNodeType() == Node.TEXT_NODE){
  235                     value = next.getNodeValue();
  236                   }
  237                   else {
  238                       // invalid to have other types of nodes in attr value
  239                       return null;
  240                   }
  241                   buff.append(value);
  242                   next = next.nextSibling;
  243   
  244               }
  245               return buff.toString();
  246             }
  247           }
  248           return "";
  249       }
  250   
  251       /**
  252        * EntityReference's children are a reflection of those defined in the
  253        * named Entity. This method creates them if they haven't been created yet.
  254        * This doesn't support editing the Entity though, since this only called
  255        * once for all.
  256        */
  257       protected void synchronizeChildren() {
  258           // no need to synchronize again
  259           needsSyncChildren(false);
  260   
  261           DocumentType doctype;
  262           NamedNodeMap entities;
  263           EntityImpl entDef;
  264           if (null != (doctype = getOwnerDocument().getDoctype()) &&
  265               null != (entities = doctype.getEntities())) {
  266   
  267               entDef = (EntityImpl)entities.getNamedItem(getNodeName());
  268   
  269               // No Entity by this name, stop here.
  270               if (entDef == null)
  271                   return;
  272   
  273               // If entity's definition exists, clone its kids
  274               isReadOnly(false);
  275               for (Node defkid = entDef.getFirstChild();
  276                   defkid != null;
  277                   defkid = defkid.getNextSibling()) {
  278                   Node newkid = defkid.cloneNode(true);
  279                   insertBefore(newkid, null);
  280               }
  281               setReadOnly(true, true);
  282           }
  283       }
  284   
  285   
  286       /**
  287        * NON-DOM: sets the node and its children value.
  288        * <P>
  289        * Note: make sure that entity reference and its kids could be set readonly.
  290        */
  291       public void setReadOnly(boolean readOnly, boolean deep) {
  292   
  293           if (needsSyncData()) {
  294               synchronizeData();
  295           }
  296           if (deep) {
  297   
  298               if (needsSyncChildren()) {
  299                   synchronizeChildren();
  300               }
  301               // Recursively set kids
  302               for (ChildNode mykid = firstChild;
  303                    mykid != null;
  304                    mykid = mykid.nextSibling) {
  305   
  306                   mykid.setReadOnly(readOnly,true);
  307   
  308               }
  309           }
  310           isReadOnly(readOnly);
  311       } // setReadOnly(boolean,boolean)
  312   
  313   
  314       /**
  315        * Enable the synchronize method which may do cloning. This method is enabled
  316        * when the parser is done with an EntityReference.
  317       /***
  318       // revisit: enable editing of Entity
  319       public void enableSynchronize(boolean enableSynchronize) {
  320           fEnableSynchronize= enableSynchronize;
  321       }
  322       /***/
  323   
  324       /**
  325        * EntityReference's children are a reflection of those defined in the
  326        * named Entity. This method updates them if the Entity is changed.
  327        * <P>
  328        * It is unclear what the least-cost resynch mechanism is.
  329        * If we expect the kids to be shallow, and/or expect changes
  330        * to the Entity contents to be rare, wiping them all out
  331        * and recloning is simplest.
  332        * <P>
  333        * If we expect them to be deep,
  334        * it might be better to first decide which kids (if any)
  335        * persist, and keep the ones (if any) that are unchanged
  336        * rather than doing all the work of cloning them again.
  337        * But that latter gets into having to convolve the two child lists,
  338        * insert new information in the right order (and possibly reorder
  339        * the existing kids), and a few other complexities that I really
  340        * don't want to deal with in this implementation.
  341        * <P>
  342        * Note that if we decide that we need to update the EntityReference's
  343        * contents, we have to turn off the readOnly flag temporarily to do so.
  344        * When we get around to adding multitasking support, this whole method
  345        * should probably be an atomic operation.
  346        *
  347        * @see DocumentTypeImpl
  348        * @see EntityImpl
  349        */
  350       // The Xerces parser invokes callbacks for startEnityReference
  351       // the parsed value of the entity EACH TIME, so it is actually
  352       // easier to create the nodes through the callbacks rather than
  353       // clone the Entity.
  354       /***
  355       // revisit: enable editing of Entity
  356       private void synchronize() {
  357           if (!fEnableSynchronize) {
  358               return;
  359           }
  360           DocumentType doctype;
  361           NamedNodeMap entities;
  362           EntityImpl entDef;
  363           if (null != (doctype = getOwnerDocument().getDoctype()) &&
  364               null != (entities = doctype.getEntities())) {
  365   
  366               entDef = (EntityImpl)entities.getNamedItem(getNodeName());
  367   
  368               // No Entity by this name. If we had a change count, reset it.
  369               if(null==entDef)
  370                   entityChanges=-1;
  371   
  372               // If no kids availalble, wipe any pre-existing children.
  373               // (See discussion above.)
  374               // Note that we have to use the superclass to avoid recursion
  375               // through Synchronize.
  376               readOnly=false;
  377               if(null==entDef || !entDef.hasChildNodes())
  378                   for(Node kid=super.getFirstChild();
  379                       kid!=null;
  380                       kid=super.getFirstChild())
  381                       removeChild(kid);
  382   
  383               // If entity's definition changed, clone its kids
  384               // (See discussion above.)
  385               if(null!=entDef && entDef.changes!=entityChanges) {
  386                   for(Node defkid=entDef.getFirstChild();
  387                       defkid!=null;
  388                       defkid=defkid.getNextSibling()) {
  389   
  390                       NodeImpl newkid=(NodeImpl) defkid.cloneNode(true);
  391                       newkid.setReadOnly(true,true);
  392                       insertBefore(newkid,null);
  393                   }
  394                   entityChanges=entDef.changes;
  395               }
  396               readOnly=true;
  397           }
  398       }
  399        /***/
  400   
  401   
  402   } // class EntityReferenceImpl

Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » dom » [javadoc | source]