001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */ 
017    package org.apache.commons.betwixt;
018    
019    /** <p><code>XMLBeanInfo</code> represents the XML metadata information
020      * used to map a Java Bean cleanly to XML. This provides a default
021      * introspection mechansim, rather like {@link java.beans.BeanInfo} 
022      * which can be customized through some mechansim, either via Java code 
023      * or XSLT for example.</p>
024      *
025      * <h4><code>ID</code> and <code>IDREF</code> Attribute Names</h4>
026      * <p>These special attributes are defined in the xml specification.
027      * They are used by Betwixt to write bean graphs with cyclic references.
028      * In most cases, these will take the values 'id' and 'idref' respectively 
029      * but these names can be varied in the DTD.
030      * Therefore, these names are specified by this class but default to the
031      * usual values.</p>
032      *
033      * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
034      * @version $Revision: 438373 $
035      */
036    public class XMLBeanInfo {
037        /** Descriptor for main element */
038        private ElementDescriptor elementDescriptor;
039        
040        /** the beans class that this XML info refers to */
041        private Class beanClass;
042        /** <code>ID</code> attribute name */
043        private String idAttributeName = "id";
044        /** <code>IDREF</code> attribute name */
045        private String idrefAttributeName = "idref";
046        /** Have we already cached the <code>idAttributeDescriptor</code>? */
047        private boolean cachedIDAttribute = false;
048        /** Cached <code>ID</code> attribute descriptor */
049        private AttributeDescriptor idAttributeDescriptor;
050        
051        /** 
052         * Base constructor 
053         * @param beanClass for this Class
054         */
055        public XMLBeanInfo( Class beanClass ) {
056            this.beanClass = beanClass;        
057        }
058    
059        /** 
060         * Gets descriptor for bean represention 
061         *
062         * @return ElementDescriptor describing root element
063         */
064        public ElementDescriptor getElementDescriptor() {
065            return elementDescriptor;
066        }
067    
068        /** 
069         * Sets descriptor for bean represention 
070         *
071         * @param elementDescriptor descriptor for bean
072         */
073        public void setElementDescriptor(ElementDescriptor elementDescriptor) {
074            this.elementDescriptor = elementDescriptor;
075        }    
076        
077        /**  
078         * Gets the beans class that this XML info refers to
079         *
080         * @return the beans class that this XML info refers to 
081         */
082        public Class getBeanClass() {
083            return beanClass;
084        }
085        
086        /** 
087         * Sets the beans class that this XML info refers to 
088         *
089         * @param beanClass the class that this refers to
090         */
091        public void setBeanClass(Class beanClass) {
092            this.beanClass = beanClass;
093        }
094        
095        /** 
096         * Search attributes for one matching <code>ID</code> attribute name 
097         *
098         * @return the xml ID attribute
099         */
100        public AttributeDescriptor getIDAttribute() {
101            //
102            // XXX for some reason caching isn't working at the moment
103            // it could be that this method is called too early
104            // and not reset when attributes change
105            // on the other hand, the speed gain is likely to be too
106            // small to bother about
107            //
108            //if ( cachedIDAttribute = false ) {
109                idAttributeDescriptor = findIDAttribute();
110              //  cachedIDAttribute = true;
111            //}
112            return idAttributeDescriptor;
113        }
114        
115        /** 
116         * ID attribute search implementation 
117         * @return the AttributeDescriptor for the <code>ID</code> attribute
118         */
119        private AttributeDescriptor findIDAttribute() {
120            // we'll check to see if the bean already has an id
121            if ( getElementDescriptor().hasAttributes() ) {
122                AttributeDescriptor[] attributes = getElementDescriptor().getAttributeDescriptors();
123                if ( attributes != null ) {
124                    for ( int i = 0, size = attributes.length; i < size; i++ ) {
125                        // support a match either on local or qualified name
126                        if ( getIDAttributeName().equals( attributes[i].getQualifiedName() ) 
127                            || getIDAttributeName().equals( attributes[i].getLocalName() )) {
128                            // we've got a match so use this attribute
129                            return attributes[i];
130                            
131                        }
132                    }
133                }
134            }
135            return null;
136        }
137        
138        /** 
139          * <p>Get name of <code>ID</code> attribute.
140          * This is used to write (for example) automatic <code>ID</code>
141          * attribute values.</p>
142          * 
143          * <p>The default name is 'id'.</p>
144          *
145          * @return name for the special <code>ID</code> attribute
146          */
147        public String getIDAttributeName() {
148            return idAttributeName;
149        }
150        
151        /** 
152          * Set name of <code>ID</code> attribute 
153          * This is used to write (for example) automatic <code>ID</code>
154          * attribute values.</p>
155          * 
156          * <p>The default name is 'id'.</p>
157          *
158          * @param idAttributeName the attribute name for the special <code>ID</code> attribute
159          */
160        public void setIDAttributeName(String idAttributeName) {
161            this.idAttributeName = idAttributeName;
162        }
163        
164        /** 
165          * <p>Get <code>IDREF</code> attribute name 
166          * This is used (for example) to deal with cyclic references.
167          *
168          * <p>The default name is 'idref'.</p>
169          *
170          * @return name for the special <code>IDREF</code> attribute
171          */
172        public String getIDREFAttributeName() {
173            return idrefAttributeName;
174        }
175        
176        /** 
177          * Set <code>IDREF</code> attribute name 
178          * This is used (for example) to deal with cyclic references.
179          *
180          * <p>The default name is 'idref'.</p>
181          *
182          * @param idrefAttributeName the attribute name for the special <code>IDREF</code> attribute
183          */
184        public void setIDREFAttributeName(String idrefAttributeName) {
185            this.idrefAttributeName = idrefAttributeName;
186        }
187        
188        /**
189         * Gets log-friendly string representation.
190         *
191         * @return something useful for logging
192         */
193        public String toString() {
194            return 
195                    "XMLBeanInfo [class=" + getBeanClass() 
196                    + ", descriptor=" + getElementDescriptor() + "]";
197        }
198    }