src/share/jaxws_classes/com/sun/xml/internal/txw2/ContainerElement.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.xml.internal.txw2;
    28 import com.sun.xml.internal.txw2.annotation.XmlAttribute;
    29 import com.sun.xml.internal.txw2.annotation.XmlElement;
    30 import com.sun.xml.internal.txw2.annotation.XmlNamespace;
    31 import com.sun.xml.internal.txw2.annotation.XmlValue;
    32 import com.sun.xml.internal.txw2.annotation.XmlCDATA;
    34 import javax.xml.namespace.QName;
    35 import java.lang.reflect.InvocationHandler;
    36 import java.lang.reflect.InvocationTargetException;
    37 import java.lang.reflect.Method;
    38 import java.lang.reflect.Proxy;
    40 /**
    41  * Dynamically implements {@link TypedXmlWriter} interfaces.
    42  *
    43  * @author Kohsuke Kawaguchi
    44  */
    45 final class ContainerElement implements InvocationHandler, TypedXmlWriter {
    47     final Document document;
    49     /**
    50      * Initially, point to the start tag token, but
    51      * once we know we are done with the start tag, we will reset it to null
    52      * so that the token sequence can be GC-ed.
    53      */
    54     StartTag startTag;
    55     final EndTag endTag = new EndTag();
    57     /**
    58      * Namespace URI of this element.
    59      */
    60     private final String nsUri;
    62     /**
    63      * When this element can accept more child content, this value
    64      * is non-null and holds the last child {@link Content}.
    65      *
    66      * If this element is committed, this parameter is null.
    67      */
    68     private Content tail;
    70     /**
    71      * Uncommitted {@link ContainerElement}s form a doubly-linked list,
    72      * so that the parent can close them recursively.
    73      */
    74     private ContainerElement prevOpen;
    75     private ContainerElement nextOpen;
    76     private final ContainerElement parent;
    77     private ContainerElement lastOpenChild;
    79     /**
    80      * Set to true if the start eleent is blocked.
    81      */
    82     private boolean blocked;
    84     public ContainerElement(Document document,ContainerElement parent,String nsUri, String localName) {
    85         this.parent = parent;
    86         this.document = document;
    87         this.nsUri = nsUri;
    88         this.startTag = new StartTag(this,nsUri,localName);
    89         tail = startTag;
    91         if(isRoot())
    92             document.setFirstContent(startTag);
    93     }
    95     private boolean isRoot() {
    96         return parent==null;
    97     }
    99     private boolean isCommitted() {
   100         return tail==null;
   101     }
   103     public Document getDocument() {
   104         return document;
   105     }
   107     boolean isBlocked() {
   108         return blocked && !isCommitted();
   109     }
   111     public void block() {
   112         blocked = true;
   113     }
   115     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   116         if(method.getDeclaringClass()==TypedXmlWriter.class || method.getDeclaringClass()==Object.class) {
   117             // forward to myself
   118             try {
   119                 return method.invoke(this,args);
   120             } catch (InvocationTargetException e) {
   121                 throw e.getTargetException();
   122             }
   123         }
   125         XmlAttribute xa = method.getAnnotation(XmlAttribute.class);
   126         XmlValue xv = method.getAnnotation(XmlValue.class);
   127         XmlElement xe = method.getAnnotation(XmlElement.class);
   130         if(xa!=null) {
   131             if(xv!=null || xe!=null)
   132                 throw new IllegalAnnotationException(method.toString());
   134             addAttribute(xa,method,args);
   135             return proxy; // allow method chaining
   136         }
   137         if(xv!=null) {
   138             if(xe!=null)
   139                 throw new IllegalAnnotationException(method.toString());
   141             _pcdata(args);
   142             return proxy; // allow method chaining
   143         }
   145         return addElement(xe,method,args);
   146     }
   148     /**
   149      * Writes an attribute.
   150      */
   151     private void addAttribute(XmlAttribute xa, Method method, Object[] args) {
   152         assert xa!=null;
   154         checkStartTag();
   156         String localName = xa.value();
   157         if(xa.value().length()==0)
   158             localName = method.getName();
   160         _attribute(xa.ns(),localName,args);
   161     }
   163     private void checkStartTag() {
   164         if(startTag==null)
   165             throw new IllegalStateException("start tag has already been written");
   166     }
   168     /**
   169      * Writes a new element.
   170      */
   171     private Object addElement(XmlElement e, Method method, Object[] args) {
   172         Class<?> rt = method.getReturnType();
   174         // the last precedence: default name
   175         String nsUri = "##default";
   176         String localName = method.getName();
   178         if(e!=null) {
   179             // then the annotation on this method
   180             if(e.value().length()!=0)
   181                 localName = e.value();
   182             nsUri = e.ns();
   183         }
   185         if(nsUri.equals("##default")) {
   186             // look for the annotation on the declaring class
   187             Class<?> c = method.getDeclaringClass();
   188             XmlElement ce = c.getAnnotation(XmlElement.class);
   189             if(ce!=null) {
   190                 nsUri = ce.ns();
   191             }
   193             if(nsUri.equals("##default"))
   194                 // then default to the XmlNamespace
   195                 nsUri = getNamespace(c.getPackage());
   196         }
   200         if(rt==Void.TYPE) {
   201             // leaf element with just a value
   203             boolean isCDATA = method.getAnnotation(XmlCDATA.class)!=null;
   205             StartTag st = new StartTag(document,nsUri,localName);
   206             addChild(st);
   207             for( Object arg : args ) {
   208                 Text text;
   209                 if(isCDATA)     text = new Cdata(document,st,arg);
   210                 else            text = new Pcdata(document,st,arg);
   211                 addChild(text);
   212             }
   213             addChild(new EndTag());
   214             return null;
   215         }
   216         if(TypedXmlWriter.class.isAssignableFrom(rt)) {
   217             // sub writer
   218             return _element(nsUri,localName,(Class)rt);
   219         }
   221         throw new IllegalSignatureException("Illegal return type: "+rt);
   222     }
   224     /**
   225      * Decides the namespace URI of the given package.
   226      */
   227     private String getNamespace(Package pkg) {
   228         if(pkg==null)       return "";
   230         String nsUri;
   231         XmlNamespace ns = pkg.getAnnotation(XmlNamespace.class);
   232         if(ns!=null)
   233             nsUri = ns.value();
   234         else
   235             nsUri = "";
   236         return nsUri;
   237     }
   239     /**
   240      * Appends this child object to the tail.
   241      */
   242     private void addChild(Content child) {
   243         tail.setNext(document,child);
   244         tail = child;
   245     }
   247     public void commit() {
   248         commit(true);
   249     }
   251     public void commit(boolean includingAllPredecessors) {
   252         _commit(includingAllPredecessors);
   253         document.flush();
   254     }
   256     private void _commit(boolean includingAllPredecessors) {
   257         if(isCommitted())  return;
   259         addChild(endTag);
   260         if(isRoot())
   261             addChild(new EndDocument());
   262         tail = null;
   264         // _commit predecessors if so told
   265         if(includingAllPredecessors) {
   266             for( ContainerElement e=this; e!=null; e=e.parent ) {
   267                 while(e.prevOpen!=null) {
   268                     e.prevOpen._commit(false);
   269                     // e.prevOpen should change as a result of committing it.
   270                 }
   271             }
   272         }
   274         // _commit all children recursively
   275         while(lastOpenChild!=null)
   276             lastOpenChild._commit(false);
   278         // remove this node from the link
   279         if(parent!=null) {
   280             if(parent.lastOpenChild==this) {
   281                 assert nextOpen==null : "this must be the last one";
   282                 parent.lastOpenChild = prevOpen;
   283             } else {
   284                 assert nextOpen.prevOpen==this;
   285                 nextOpen.prevOpen = this.prevOpen;
   286             }
   287             if(prevOpen!=null) {
   288                 assert prevOpen.nextOpen==this;
   289                 prevOpen.nextOpen = this.nextOpen;
   290             }
   291         }
   293         this.nextOpen = null;
   294         this.prevOpen = null;
   295     }
   297     public void _attribute(String localName, Object value) {
   298         _attribute("",localName,value);
   299     }
   301     public void _attribute(String nsUri, String localName, Object value) {
   302         checkStartTag();
   303         startTag.addAttribute(nsUri,localName,value);
   304     }
   306     public void _attribute(QName attributeName, Object value) {
   307         _attribute(attributeName.getNamespaceURI(),attributeName.getLocalPart(),value);
   308     }
   310     public void _namespace(String uri) {
   311         _namespace(uri,false);
   312     }
   314     public void _namespace(String uri, String prefix) {
   315         if(prefix==null)
   316             throw new IllegalArgumentException();
   317         checkStartTag();
   318         startTag.addNamespaceDecl(uri,prefix,false);
   319     }
   321     public void _namespace(String uri, boolean requirePrefix) {
   322         checkStartTag();
   323         startTag.addNamespaceDecl(uri,null,requirePrefix);
   324     }
   326     public void _pcdata(Object value) {
   327         // we need to allow this method even when startTag has already been completed.
   328         // checkStartTag();
   329         addChild(new Pcdata(document,startTag,value));
   330     }
   332     public void _cdata(Object value) {
   333         addChild(new Cdata(document,startTag,value));
   334     }
   336     public void _comment(Object value) throws UnsupportedOperationException {
   337         addChild(new Comment(document,startTag,value));
   338     }
   340     public <T extends TypedXmlWriter> T _element(String localName, Class<T> contentModel) {
   341         return _element(nsUri,localName,contentModel);
   342     }
   344     public <T extends TypedXmlWriter> T _element(QName tagName, Class<T> contentModel) {
   345         return _element(tagName.getNamespaceURI(),tagName.getLocalPart(),contentModel);
   346     }
   348     public <T extends TypedXmlWriter> T _element(Class<T> contentModel) {
   349         return _element(TXW.getTagName(contentModel),contentModel);
   350     }
   352     public <T extends TypedXmlWriter> T _cast(Class<T> facadeType) {
   353         return facadeType.cast(Proxy.newProxyInstance(facadeType.getClassLoader(),new Class[]{facadeType},this));
   354     }
   356     public <T extends TypedXmlWriter> T _element(String nsUri, String localName, Class<T> contentModel) {
   357         ContainerElement child = new ContainerElement(document,this,nsUri,localName);
   358         addChild(child.startTag);
   359         tail = child.endTag;
   361         // update uncommitted link list
   362         if(lastOpenChild!=null) {
   363             assert lastOpenChild.parent==this;
   365             assert child.prevOpen==null;
   366             assert child.nextOpen==null;
   367             child.prevOpen = lastOpenChild;
   368             assert lastOpenChild.nextOpen==null;
   369             lastOpenChild.nextOpen = child;
   370         }
   372         this.lastOpenChild = child;
   374         return child._cast(contentModel);
   375     }
   376 }

mercurial