alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ContainerElement.java)

This example Java source code file (ContainerElement.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

cdata, class, containerelement, document, endtag, method, object, pcdata, reflection, starttag, string, typedxmlwriter, xmlelement, xmlvalue

The ContainerElement.java Java example source code

/*
 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.xml.internal.txw2;

import com.sun.xml.internal.txw2.annotation.XmlAttribute;
import com.sun.xml.internal.txw2.annotation.XmlElement;
import com.sun.xml.internal.txw2.annotation.XmlNamespace;
import com.sun.xml.internal.txw2.annotation.XmlValue;
import com.sun.xml.internal.txw2.annotation.XmlCDATA;

import javax.xml.namespace.QName;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Dynamically implements {@link TypedXmlWriter} interfaces.
 *
 * @author Kohsuke Kawaguchi
 */
final class ContainerElement implements InvocationHandler, TypedXmlWriter {

    final Document document;

    /**
     * Initially, point to the start tag token, but
     * once we know we are done with the start tag, we will reset it to null
     * so that the token sequence can be GC-ed.
     */
    StartTag startTag;
    final EndTag endTag = new EndTag();

    /**
     * Namespace URI of this element.
     */
    private final String nsUri;

    /**
     * When this element can accept more child content, this value
     * is non-null and holds the last child {@link Content}.
     *
     * If this element is committed, this parameter is null.
     */
    private Content tail;

    /**
     * Uncommitted {@link ContainerElement}s form a doubly-linked list,
     * so that the parent can close them recursively.
     */
    private ContainerElement prevOpen;
    private ContainerElement nextOpen;
    private final ContainerElement parent;
    private ContainerElement lastOpenChild;

    /**
     * Set to true if the start eleent is blocked.
     */
    private boolean blocked;

    public ContainerElement(Document document,ContainerElement parent,String nsUri, String localName) {
        this.parent = parent;
        this.document = document;
        this.nsUri = nsUri;
        this.startTag = new StartTag(this,nsUri,localName);
        tail = startTag;

        if(isRoot())
            document.setFirstContent(startTag);
    }

    private boolean isRoot() {
        return parent==null;
    }

    private boolean isCommitted() {
        return tail==null;
    }

    public Document getDocument() {
        return document;
    }

    boolean isBlocked() {
        return blocked && !isCommitted();
    }

    public void block() {
        blocked = true;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getDeclaringClass()==TypedXmlWriter.class || method.getDeclaringClass()==Object.class) {
            // forward to myself
            try {
                return method.invoke(this,args);
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            }
        }

        XmlAttribute xa = method.getAnnotation(XmlAttribute.class);
        XmlValue xv = method.getAnnotation(XmlValue.class);
        XmlElement xe = method.getAnnotation(XmlElement.class);


        if(xa!=null) {
            if(xv!=null || xe!=null)
                throw new IllegalAnnotationException(method.toString());

            addAttribute(xa,method,args);
            return proxy; // allow method chaining
        }
        if(xv!=null) {
            if(xe!=null)
                throw new IllegalAnnotationException(method.toString());

            _pcdata(args);
            return proxy; // allow method chaining
        }

        return addElement(xe,method,args);
    }

    /**
     * Writes an attribute.
     */
    private void addAttribute(XmlAttribute xa, Method method, Object[] args) {
        assert xa!=null;

        checkStartTag();

        String localName = xa.value();
        if(xa.value().length()==0)
            localName = method.getName();

        _attribute(xa.ns(),localName,args);
    }

    private void checkStartTag() {
        if(startTag==null)
            throw new IllegalStateException("start tag has already been written");
    }

    /**
     * Writes a new element.
     */
    private Object addElement(XmlElement e, Method method, Object[] args) {
        Class<?> rt = method.getReturnType();

        // the last precedence: default name
        String nsUri = "##default";
        String localName = method.getName();

        if(e!=null) {
            // then the annotation on this method
            if(e.value().length()!=0)
                localName = e.value();
            nsUri = e.ns();
        }

        if(nsUri.equals("##default")) {
            // look for the annotation on the declaring class
            Class<?> c = method.getDeclaringClass();
            XmlElement ce = c.getAnnotation(XmlElement.class);
            if(ce!=null) {
                nsUri = ce.ns();
            }

            if(nsUri.equals("##default"))
                // then default to the XmlNamespace
                nsUri = getNamespace(c.getPackage());
        }



        if(rt==Void.TYPE) {
            // leaf element with just a value

            boolean isCDATA = method.getAnnotation(XmlCDATA.class)!=null;

            StartTag st = new StartTag(document,nsUri,localName);
            addChild(st);
            for( Object arg : args ) {
                Text text;
                if(isCDATA)     text = new Cdata(document,st,arg);
                else            text = new Pcdata(document,st,arg);
                addChild(text);
            }
            addChild(new EndTag());
            return null;
        }
        if(TypedXmlWriter.class.isAssignableFrom(rt)) {
            // sub writer
            return _element(nsUri,localName,(Class)rt);
        }

        throw new IllegalSignatureException("Illegal return type: "+rt);
    }

    /**
     * Decides the namespace URI of the given package.
     */
    private String getNamespace(Package pkg) {
        if(pkg==null)       return "";

        String nsUri;
        XmlNamespace ns = pkg.getAnnotation(XmlNamespace.class);
        if(ns!=null)
            nsUri = ns.value();
        else
            nsUri = "";
        return nsUri;
    }

    /**
     * Appends this child object to the tail.
     */
    private void addChild(Content child) {
        tail.setNext(document,child);
        tail = child;
    }

    public void commit() {
        commit(true);
    }

    public void commit(boolean includingAllPredecessors) {
        _commit(includingAllPredecessors);
        document.flush();
    }

    private void _commit(boolean includingAllPredecessors) {
        if(isCommitted())  return;

        addChild(endTag);
        if(isRoot())
            addChild(new EndDocument());
        tail = null;

        // _commit predecessors if so told
        if(includingAllPredecessors) {
            for( ContainerElement e=this; e!=null; e=e.parent ) {
                while(e.prevOpen!=null) {
                    e.prevOpen._commit(false);
                    // e.prevOpen should change as a result of committing it.
                }
            }
        }

        // _commit all children recursively
        while(lastOpenChild!=null)
            lastOpenChild._commit(false);

        // remove this node from the link
        if(parent!=null) {
            if(parent.lastOpenChild==this) {
                assert nextOpen==null : "this must be the last one";
                parent.lastOpenChild = prevOpen;
            } else {
                assert nextOpen.prevOpen==this;
                nextOpen.prevOpen = this.prevOpen;
            }
            if(prevOpen!=null) {
                assert prevOpen.nextOpen==this;
                prevOpen.nextOpen = this.nextOpen;
            }
        }

        this.nextOpen = null;
        this.prevOpen = null;
    }

    public void _attribute(String localName, Object value) {
        _attribute("",localName,value);
    }

    public void _attribute(String nsUri, String localName, Object value) {
        checkStartTag();
        startTag.addAttribute(nsUri,localName,value);
    }

    public void _attribute(QName attributeName, Object value) {
        _attribute(attributeName.getNamespaceURI(),attributeName.getLocalPart(),value);
    }

    public void _namespace(String uri) {
        _namespace(uri,false);
    }

    public void _namespace(String uri, String prefix) {
        if(prefix==null)
            throw new IllegalArgumentException();
        checkStartTag();
        startTag.addNamespaceDecl(uri,prefix,false);
    }

    public void _namespace(String uri, boolean requirePrefix) {
        checkStartTag();
        startTag.addNamespaceDecl(uri,null,requirePrefix);
    }

    public void _pcdata(Object value) {
        // we need to allow this method even when startTag has already been completed.
        // checkStartTag();
        addChild(new Pcdata(document,startTag,value));
    }

    public void _cdata(Object value) {
        addChild(new Cdata(document,startTag,value));
    }

    public void _comment(Object value) throws UnsupportedOperationException {
        addChild(new Comment(document,startTag,value));
    }

    public <T extends TypedXmlWriter> T _element(String localName, Class contentModel) {
        return _element(nsUri,localName,contentModel);
    }

    public <T extends TypedXmlWriter> T _element(QName tagName, Class contentModel) {
        return _element(tagName.getNamespaceURI(),tagName.getLocalPart(),contentModel);
    }

    public <T extends TypedXmlWriter> T _element(Class contentModel) {
        return _element(TXW.getTagName(contentModel),contentModel);
    }

    public <T extends TypedXmlWriter> T _cast(Class facadeType) {
        return facadeType.cast(Proxy.newProxyInstance(facadeType.getClassLoader(),new Class[]{facadeType},this));
    }

    public <T extends TypedXmlWriter> T _element(String nsUri, String localName, Class contentModel) {
        ContainerElement child = new ContainerElement(document,this,nsUri,localName);
        addChild(child.startTag);
        tail = child.endTag;

        // update uncommitted link list
        if(lastOpenChild!=null) {
            assert lastOpenChild.parent==this;

            assert child.prevOpen==null;
            assert child.nextOpen==null;
            child.prevOpen = lastOpenChild;
            assert lastOpenChild.nextOpen==null;
            lastOpenChild.nextOpen = child;
        }

        this.lastOpenChild = child;

        return child._cast(contentModel);
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java ContainerElement.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.