All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.enhydra.xml.xmlc.compiler.ElementInfo Maven / Gradle / Ivy

The newest version!
/*
 * Enhydra Java Application Server Project
 * 
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site ( http://www.enhydra.org/ ).
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
 * the License for the specific terms governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * $Id: ElementInfo.java,v 1.5 2005/11/19 21:30:41 jkjome Exp $
 */

package org.enhydra.xml.xmlc.compiler;

import org.enhydra.xml.xmlc.codegen.JavaLang;
import org.enhydra.xml.xmlc.dom.XMLCDocument;
import org.enhydra.xml.xmlc.metadata.DocumentClass;
import org.enhydra.xml.xmlc.metadata.MetaData;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.html.HTMLElement;

//FIXME: this is designed to evolve forward to something that provides
//information taken from both the DOM and metadata.
//FIXME: Maybe really need a clientdata instead of adjust size & buildMethodFlags.
//FIXME: are sizes still needed??

//  jrk_20040703 - I think the setText fixme is solved (see comment in the constructor
//               for details), but leaving the note here for posterity.
//FIXME: `accessor' terminology is broken; sometimes accessor includes
// setText and sometimes it doesn.

/**
 * Information about a particular Element.  Several fields are also
 * kept for code generators, although this is not do in a general
 * way.
 */
public final class ElementInfo {
    /**
     * Information about an accessor method (getElementXXX, getTagXXX) to
     * create for this element.
     */
    public class AccessorInfo {
        /** Name of the method to create */
        public final String fName;

        /** Return type of accessor */
        public final String fReturnType;

        /**
         * Constructor.
         */
        public AccessorInfo(String name,
                            String returnType) {
            fName = name;
            fReturnType = returnType;
        }
    }

    /**
     * Container for DOM.
     */
    private XMLCDocument fXmlcDoc;

    /**
     * The element this object is associated with.
     */
    private Element fElement;

    /**
     * The interface or class name to use in referencing the element.
     */
    private String fReferenceName;

    /**
     * The XML id for the element (value of the id field).
     */
    private String fXmlId;

    /**
     * The java id for element.  Will be null if a valid Java id could not
     * be formed.
     */
    private String fJavaId;

    /**
     * List of accessors to create, or null if none.
     */
    private AccessorInfo[] fAccessorInfo;;

    /**
     * Should a setText method be generated for this element?
     */
    private boolean fCreateSetText;

    /**
     * Size of the element, in nodes, excluding children
     */
    private int fNodeSize;

    /**
     * Size of the subtree of this element, in number of nodes.
     */
    private int fSubTreeNodeSize;

    /**
     * Adjusted size of subtree.  This is used by the code generators
     * to store a size that is used in optimizing subtree creation.
     * Initialized to the subtree node-size.
     */
    private int fAdjustedSubTreeNodeSize;

    /**
     * Constructor.
     */
    public ElementInfo(Element element,
                       int nodeSize,
                       int subTreeNodeSize,
                       MetaData metaData,
                       XMLCDocument xmlcDoc) {
        if (element == null) {
            throw new IllegalArgumentException("element null");
        }
        fElement = element;
        fNodeSize = nodeSize;
        fSubTreeNodeSize = subTreeNodeSize;
        fAdjustedSubTreeNodeSize = subTreeNodeSize;
        fXmlcDoc = xmlcDoc;

        determineIds();
        initAccessorInfo(metaData);

        // Create setTextXXX() if there is a legal Java id, #PCDATA is in the
        // content model and getTagXXX() or getElementXXX() methods also being generated
        fCreateSetText = (fJavaId != null && fReferenceName != null)
            && fXmlcDoc.hasPCDataInContentModel(fElement);
            //&& (XMLCUtil.findFirstText(fElement) != null); //jrk_20040703 - XMLObjectImpl.doSetText() now creates a text node if it doesn't already exist, so no need to avoid setText*() creation!
    }

    /**
     * Translate the accessor return type from the MetaData to a actual return
     * type.  They translates various short-cuts to actual class names.
     */
    private String getAccessorReturnType(String typeSpec) {
        if (typeSpec == null) return null; //expected if getCreateGetTagMethods() is false and getSuppressGetElementMethods() is true, so avoid null pointer exception below
        if (typeSpec.equals(DocumentClass.ACCESSOR_TYPE_INTERFACE)) {
            return fXmlcDoc.getDomFactory().nodeClassToInterface(fElement);
        } else if (typeSpec.equals(DocumentClass.ACCESSOR_TYPE_CLASS)) {
            return fElement.getClass().getName();
        } else if (typeSpec.equals(DocumentClass.ACCESSOR_TYPE_ELEMENT)) {
            return Element.class.getName();
        } else if (typeSpec.equals(DocumentClass.ACCESSOR_TYPE_HTML_ELEMENT)) {
            return HTMLElement.class.getName();
        } else {
            return typeSpec;
        }
    }

    /**
     * Initialize the information of the accessors to create.
     */
    private void initAccessorInfo(MetaData metaData) {
        boolean createGetElement = (fJavaId != null)
            && !metaData.getDocumentClass().getSuppressGetElementMethods();
        boolean createGetTag = (fJavaId != null)
            && metaData.getDocumentClass().getCreateGetTagMethods();
        
        int numAccessors = (createGetElement ? 1 : 0)
            + (createGetTag ? 1 : 0);
        if (numAccessors == 0) {
            return;
        }
        fAccessorInfo = new AccessorInfo[numAccessors];
        int idx = 0;
	
        fReferenceName = metaData.getDocumentClass().getGetTagReturnType();
        if (createGetElement) {
	    fReferenceName =
		fXmlcDoc.getDomFactory().nodeClassToInterface(fElement);
            fAccessorInfo[idx++]
                = new AccessorInfo("getElement" + fJavaId, fReferenceName);
                                   
                                                 
        }
        if (createGetTag) {
            fAccessorInfo[idx++]
                = new AccessorInfo("getTag" + fJavaId,
				   getAccessorReturnType(metaData.getDocumentClass().getGetTagReturnType()));
        }
    }

    /**
     * Adjust an element id to conform to the Java naming convention.
     * Upshifts the first character.
     */
    private String adjustElementId(String id) {
        return id.substring(0, 1).toUpperCase() + id.substring(1);
    }

    /**
     * Determine the XML and Java ids for the element.
     */
    private void determineIds() {
        // Get id attribute
        String idAttrName = fXmlcDoc.getIdAttrName(fElement);
        if (idAttrName != null) {
            Attr idAttr = fElement.getAttributeNode(idAttrName);
            if (idAttr != null) {
                fXmlId = idAttr.getNodeValue();
                if (JavaLang.legalJavaIdentifier(fXmlId)) {
                    fJavaId = adjustElementId(fXmlId);
                }
            }
        }
    }

    /**
     * Get the element.
     */
    public Element getElement() {
        return fElement;
    }

    /**
     * Get the Java class name of the element.
     */
    public String getClassName() {
        return fElement.getClass().getName();
    }

    /**
     * Get the reference name for this element. In general, this is
     * the name of the return type for the "getElementXXX()" accessor.
     */
    public String getReferenceName() {
        return getAccessorReturnType(fReferenceName);
    }

    /**
     * Get the XML id, or null if there isn't one.
     */
    public String getXmlId() {
        return fXmlId;
    }

    /**
     * Get the Java id, or null if there isn't one.
     */
    public String getJavaId() {
        return fJavaId;
    }

    /**
     * Get the element class (attribute) names
     */
    public String[] getElementClassNames() {
        return fXmlcDoc.getElementClassNames(fElement);
    }

    /**
     * Get the element name (name attribute in HTML).
     */
    public String getElementName() {
        return fXmlcDoc.getElementName(fElement);
    }

    /**
     * Is the element id an invalid Java identifier?
     */
    public boolean hasInvalidJavaId() {
        return (fXmlId != null) && (fJavaId == null);
    }

    /**
     * Get the total number of access methods for this element.
     */
    public int getNumAccessMethods() {
        return ((fAccessorInfo != null) ? fAccessorInfo.length : 0)
            + (fCreateSetText ? 1 : 0);
    }

    /**
     * Get the list of accessors to create.
     */
    public AccessorInfo[] getAccessors() {
        return fAccessorInfo;
    }

    /**
     * Should a setText method be generated for this element?
     */
    public boolean createSetText() {
        return fCreateSetText;
    }

    /*
     * Get the size of the element, in nodes.  This includes the element
     * itself, and attributes and their descendents, but not children.
     */
    public int getNodeSize() {
        return fNodeSize;
    }

    /*
     * Get the size of the subtree, in nodes, rooted at this element.
     */
    public int getSubTreeNodeSize() {
        return fSubTreeNodeSize;
    }

    /*
     * Get the adjusted size of the subtree.  This value is initially
     * the same as the subtree node-size, but can be adjusted by a
     * code generator for it's own purposes.
     */
    public int getAdjustedSubTreeNodeSize() {
        return fAdjustedSubTreeNodeSize;
    }

    /*
     * Set the adjusted size of the subtree.
     */
    public void setAdjustedSubTreeNodeSize(int size) {
        fAdjustedSubTreeNodeSize = size;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy