001/*
002 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
003 * 
004 * This software is open source. 
005 * See the bottom of this file for the licence.
006 * 
007 * $Id: BeanMetaData.java,v 1.4 2001/05/15 18:17:38 jstrachan Exp $
008 */
009
010package org.dom4j.bean;
011
012import java.beans.BeanInfo;
013import java.beans.Introspector;
014import java.beans.IntrospectionException;
015import java.beans.PropertyDescriptor;
016import java.lang.reflect.Method;
017import java.util.HashMap;
018import java.util.Map;
019
020import org.dom4j.DocumentFactory;
021import org.dom4j.QName;
022
023/** <p><code>BeanMetaData</code> contains metadata about a bean class.</p>
024  *
025  * @author <a href="mailto:james.strachan@metastuff.com">James Strachan</a>
026  * @version $Revision: 1.4 $
027  */
028public class BeanMetaData {
029
030    /** Empty arguments for reflection calls */
031    protected static final Object[] NULL_ARGS = {};
032    
033    /** Singleton cache */
034    private static Map singletonCache = new HashMap();
035    
036    private static final DocumentFactory DOCUMENT_FACTORY = BeanDocumentFactory.getInstance();
037    
038    /** The class of the bean */
039    private Class beanClass;
040    
041    /** Property descriptors for the bean */
042    private PropertyDescriptor[] propertyDescriptors;
043
044    /** QNames for the attributes */
045    private QName[] qNames;
046
047    /** Read methods used for getting properties */
048    private Method[] readMethods;
049    
050    /** Write methods used for setting properties */
051    private Method[] writeMethods;
052
053    /** Index of names and QNames to indices */
054    private Map nameMap = new HashMap();
055    
056    
057    /** Static helper method to find and cache meta data objects for bean types 
058      */
059    public static BeanMetaData get(Class beanClass) {
060        BeanMetaData answer = (BeanMetaData) singletonCache.get( beanClass );
061        if ( answer == null ) {
062            answer = new BeanMetaData( beanClass );
063            singletonCache.put( beanClass, answer );
064        }
065        return answer;
066    }
067    
068    public BeanMetaData(Class beanClass) { 
069        this.beanClass = beanClass;
070        if ( beanClass != null ) {
071            try {
072                BeanInfo beanInfo = Introspector.getBeanInfo( beanClass );
073                propertyDescriptors = beanInfo.getPropertyDescriptors();
074            }
075            catch (IntrospectionException e) {
076                handleException(e);
077            }
078        }
079        if ( propertyDescriptors == null ) {
080            propertyDescriptors = new PropertyDescriptor[0];
081        }
082        int size = propertyDescriptors.length;
083        qNames = new QName[size];
084        readMethods = new Method[size];
085        writeMethods = new Method[size];
086        for ( int i = 0; i < size; i++ ) {
087            PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
088            String name = propertyDescriptor.getName();
089            QName qName = DOCUMENT_FACTORY.createQName( name );
090            qNames[i] = qName;
091            readMethods[i] = propertyDescriptor.getReadMethod();
092            writeMethods[i] = propertyDescriptor.getWriteMethod();
093            
094            Integer index = new Integer(i);
095            nameMap.put( name, index );
096            nameMap.put( qName, index );
097        }
098    }
099        
100    /** @return the number of attribtutes for this bean type
101      */
102    public int attributeCount() {
103        return propertyDescriptors.length;
104    }
105    
106    public BeanAttributeList createAttributeList(BeanElement parent) {
107        return new BeanAttributeList( parent, this );
108    }
109    
110    public QName getQName(int index) {
111        return qNames[index];
112    }
113
114    public int getIndex(String name) {
115        Integer index = (Integer) nameMap.get(name);
116        return ( index != null ) ? index.intValue() : -1;
117    }
118    
119    public int getIndex(QName qName) {
120        Integer index = (Integer) nameMap.get(qName);
121        return ( index != null ) ? index.intValue() : -1;
122    }
123    
124    public Object getData(int index, Object bean) {
125        try {
126            Method method = readMethods[index];
127            return method.invoke( bean, NULL_ARGS );
128        }
129        catch (Exception e) {
130            handleException(e);
131            return null;
132        }
133    }
134    
135    public void setData(int index, Object bean, Object data) {
136        try {
137            Method method = writeMethods[index];
138            Object[] args = { data };
139            method.invoke( bean, args );
140        }
141        catch (Exception e) {
142            handleException(e);
143        }
144    }
145    
146    // Implementation methods
147    //-------------------------------------------------------------------------    
148    protected void handleException(Exception e) {
149        // ignore introspection exceptions
150    }
151}
152
153
154
155
156/*
157 * Redistribution and use of this software and associated documentation
158 * ("Software"), with or without modification, are permitted provided
159 * that the following conditions are met:
160 *
161 * 1. Redistributions of source code must retain copyright
162 *    statements and notices.  Redistributions must also contain a
163 *    copy of this document.
164 *
165 * 2. Redistributions in binary form must reproduce the
166 *    above copyright notice, this list of conditions and the
167 *    following disclaimer in the documentation and/or other
168 *    materials provided with the distribution.
169 *
170 * 3. The name "DOM4J" must not be used to endorse or promote
171 *    products derived from this Software without prior written
172 *    permission of MetaStuff, Ltd.  For written permission,
173 *    please contact dom4j-info@metastuff.com.
174 *
175 * 4. Products derived from this Software may not be called "DOM4J"
176 *    nor may "DOM4J" appear in their names without prior written
177 *    permission of MetaStuff, Ltd. DOM4J is a registered
178 *    trademark of MetaStuff, Ltd.
179 *
180 * 5. Due credit should be given to the DOM4J Project
181 *    (http://dom4j.org/).
182 *
183 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
184 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
185 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
186 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
187 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
188 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
189 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
190 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
191 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
192 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
193 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
194 * OF THE POSSIBILITY OF SUCH DAMAGE.
195 *
196 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
197 *
198 * $Id: BeanMetaData.java,v 1.4 2001/05/15 18:17:38 jstrachan Exp $
199 */