View Javadoc

1   /*
2    * Copyright (C) 2004 Christian Siefkes <christian@siefkes.net>.
3    * Development of this software is supported by the German Research Society,
4    * Berlin-Brandenburg Graduate School in Distributed Information Systems
5    * (DFG grant no. GRK 316).
6    *
7    * This library is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU Lesser General Public
9    * License as published by the Free Software Foundation; either
10   * version 2.1 of the License, or (at your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this library; if not, visit
19   * http://www.gnu.org/licenses/lgpl.html or write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21   */
22  package de.fu_berlin.ties.xml.io;
23  
24  import java.lang.reflect.Constructor;
25  import java.lang.reflect.InvocationTargetException;
26  
27  import org.dom4j.Attribute;
28  import org.dom4j.Element;
29  import org.dom4j.Namespace;
30  import org.dom4j.QName;
31  import org.dom4j.tree.DefaultElement;
32  
33  /***
34   * An XML element that is targeted at storing an Java object.
35   *
36   * @author Christian Siefkes
37   * @version $Revision: 1.1 $, $Date: 2004/12/06 18:00:41 $, $Author: siefkes $
38   */
39  public class ObjectElement extends DefaultElement {
40  
41      /***
42       * The name of the attribute used to store the Java class of an object:
43       * {@value}.
44       */
45      public static final String JAVA_CLASS_ATTRIBUTE = "java";
46  
47  
48      /***
49       * Creates (deserializes) an object of a specified type by calling a
50       * constructor of the class that accepts an XML element as single argument
51       * and passing itself as parameter. Only classes that provide a suitable
52       * constructor can be instantiated this way.
53       *
54       * @param type the class of the object to create; must have a constructor
55       * whose only argument is an {@link Element}
56       * @return the created object; the returned object will be an instance of
57       * the specified class
58       * @throws InstantiationException if instantiation failed
59       * @throws SecurityException if access to the required reflection
60       * information is denied
61       */
62      public static final Object createObject(final Element element,
63              final Class type)
64      throws InstantiationException, SecurityException {
65          try {
66              // load constructor with Element as only argument
67              final Constructor cons = type.getConstructor(
68                      new Class[] {Element.class});
69              // pass element as single argument
70              return cons.newInstance(new Object[] {element});
71          } catch (IllegalAccessException iae) {        // repackage exception
72              final InstantiationException ie =
73                  new InstantiationException(iae.toString());
74              ie.initCause(iae);
75              throw ie;
76          } catch (InvocationTargetException ite) {     // repackage exception
77              final InstantiationException ie =
78                  new InstantiationException(ite.toString());
79              ie.initCause(ite);
80              throw ie;
81          } catch (ExceptionInInitializerError eiie) {  // repackage exception
82              final InstantiationException ie =
83                  new InstantiationException(eiie.toString());
84              ie.initCause(eiie);
85              throw ie;
86          } catch (NoSuchMethodException nsme) {        // repackage exception
87              final InstantiationException ie =
88                  new InstantiationException(nsme.toString());
89              ie.initCause(nsme);
90              throw ie;
91          }
92      }
93  
94  
95      /***
96       * Creates a new instance.
97       *
98       * @param name the name of the element
99       * @param javaClass the class of the object to store
100      */
101     public ObjectElement(final String name, final Class javaClass) {
102         super(name);
103         addAttribute(JAVA_CLASS_ATTRIBUTE, javaClass.getName());
104     }
105 
106     /***
107      * Creates a new instance.
108      *
109      * @param qname the qualified name of the element
110      * @param javaClass the class of the object to store
111      */
112     public ObjectElement(final QName qname, final Class javaClass) {
113         super(qname);
114         addAttribute(JAVA_CLASS_ATTRIBUTE, javaClass.getName());
115     }
116 
117     /***
118      * Creates a new instance.
119      *
120      * @param name the local name of the element
121      * @param namespace the namespace of the element
122      * @param javaClass the class of the object to store
123      */
124     public ObjectElement(final String name, final Namespace namespace,
125             final Class javaClass) {
126         super(name, namespace);
127         addAttribute(JAVA_CLASS_ATTRIBUTE, javaClass.getName());
128     }
129 
130     /***
131      * Creates (deserializes) an object of a specified type by calling a
132      * constructor of the class that accepts an XML element as single argument
133      * and passing itself as parameter. Only classes that provide a suitable
134      * constructor can be instantiated this way.
135      *
136      * @return the created object
137      * @throws InstantiationException if instantiation failed
138      * @throws SecurityException if access to the required reflection
139      * information is denied
140      * @throws ClassNotFoundException if the class specified in the
141      * {@link #JAVA_CLASS_ATTRIBUTE} is not available on this system
142      * @throws IllegalStateException if the java class attribute has been
143      * removed (by calling {@link #unsetJavaClassAttrib()}
144      */
145     public final Object createObject() throws InstantiationException,
146     SecurityException, ClassNotFoundException, IllegalStateException {
147         return createObject(this, javaClass());
148     }
149 
150     /***
151      * Returns the name of the {@link Class} of the stored object.
152      *
153      * @return the class name of the stored object; or <code>null</code> if
154      * {@link #unsetJavaClassAttrib()} has been called before
155      */
156     public String javaClassName() {
157         return attributeValue(JAVA_CLASS_ATTRIBUTE);
158     }
159 
160     /***
161      * Returns the {@link Class} of the stored object.
162      *
163      * @return the class of the stored object
164      * @throws ClassNotFoundException if the class cannot be located
165      * @throws IllegalStateException if the java class attribute has been
166      * removed (by calling {@link #unsetJavaClassAttrib()}
167      */
168     public Class javaClass()
169     throws ClassNotFoundException, IllegalStateException {
170         final String className = javaClassName();
171 
172         if (className != null) {
173             return Class.forName(className);            
174         } else {
175             throw new IllegalStateException(
176                     "Java class attribute has been unset");
177         }
178     }
179 
180     /***
181      * Unsets the attribute representing the {@link Class} of the stored object.
182      * @return <code>true</code> if the attribute was successfully removed
183      * (first call to this method); <code>false</code> if there was no such
184      * attribute (later calls to this method)
185      */
186     public boolean unsetJavaClassAttrib() {
187         // remove the java attrib
188         final Attribute javaAttrib = attribute(JAVA_CLASS_ATTRIBUTE);
189 
190         if (javaAttrib != null) {
191             return remove(javaAttrib);
192         } else {
193             return false;
194         }
195     }
196 
197 }