001: package net.sourceforge.squirrel_sql.fw.xml;
002:
003: /*
004: * Copyright (C) 2001-2004 Colin Bell
005: * colbell@users.sourceforge.net
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: import java.beans.BeanInfo;
022: import java.beans.Introspector;
023: import java.beans.PropertyDescriptor;
024: import java.io.File;
025: import java.io.FileNotFoundException;
026: import java.io.FileReader;
027: import java.io.IOException;
028: import java.io.Reader;
029: import java.lang.reflect.Array;
030: import java.lang.reflect.Method;
031: import java.util.ArrayList;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Map;
036:
037: import net.n3.nanoxml.IXMLElement;
038: import net.n3.nanoxml.IXMLParser;
039: import net.n3.nanoxml.StdXMLReader;
040: import net.n3.nanoxml.XMLParserFactory;
041:
042: import net.sourceforge.squirrel_sql.fw.util.EnumerationIterator;
043: import net.sourceforge.squirrel_sql.fw.util.beanwrapper.StringWrapper;
044: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
045: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
046:
047: public class XMLBeanReader implements Iterable<Object> {
048: /** Logger for this class. */
049: private static final ILogger s_log = LoggerController
050: .createLogger(XMLBeanReader.class);
051:
052: private String[][] _fixStrings = new String[][] {
053: { "com.bigfoot.colbell.squirrel",
054: "net.sourceforge.squirrel_sql.client" },
055: { "com.bigfoot.colbell.fw",
056: "net.sourceforge.squirrel_sql.fw" },
057: {
058: "net.sourceforge.squirrel_sql.client.mainframe.MainFrameWindowState",
059: "net.sourceforge.squirrel_sql.client.gui.mainframe.MainFrameWindowState" } };
060:
061: private ClassLoader _cl;
062: private final List<Object> _beanColl = new ArrayList<Object>();
063:
064: public XMLBeanReader() {
065: super ();
066: }
067:
068: public void load(File xmlFile) throws FileNotFoundException,
069: XMLException {
070: load(xmlFile, null);
071: }
072:
073: public void load(File xmlFile, ClassLoader cl)
074: throws FileNotFoundException, XMLException {
075: if (!xmlFile.exists()) {
076: throw new FileNotFoundException(xmlFile.getName());
077: }
078: load(xmlFile.getAbsolutePath(), cl);
079: }
080:
081: public void load(String xmlFileName) throws FileNotFoundException,
082: XMLException {
083: load(xmlFileName, null);
084: }
085:
086: public synchronized void load(String xmlFileName, ClassLoader cl)
087: throws FileNotFoundException, IllegalArgumentException,
088: XMLException {
089: if (xmlFileName == null) {
090: throw new IllegalArgumentException(
091: "Null xmlFileName passed");
092: }
093:
094: _cl = cl;
095: _beanColl.clear();
096:
097: FileReader frdr = new FileReader(xmlFileName);
098: try {
099: load(frdr, cl);
100: } finally {
101: try {
102: frdr.close();
103: } catch (IOException ex) {
104: s_log.error("Error closing FileReader", ex);
105: }
106: }
107: }
108:
109: public void load(Reader rdr) throws XMLException {
110: load(rdr, null);
111: }
112:
113: public void load(Reader rdr, ClassLoader cl) throws XMLException {
114: try {
115: final IXMLParser parser = XMLParserFactory
116: .createDefaultXMLParser();
117: parser.setReader(new StdXMLReader(rdr));
118: IXMLElement element = (IXMLElement) parser.parse();
119: Iterator it = new EnumerationIterator(element
120: .enumerateChildren());
121: while (it.hasNext()) {
122: final IXMLElement elem = (IXMLElement) it.next();
123: if (isBeanElement(elem)) {
124: _beanColl.add(loadBean(elem));
125: }
126: }
127: } catch (Exception ex) {
128: throw new XMLException(ex);
129: }
130: }
131:
132: public Iterator<Object> iterator() {
133: return _beanColl.iterator();
134: }
135:
136: private Object loadBean(IXMLElement beanElement)
137: throws XMLException {
138: String beanClassName = null;
139: try {
140: beanClassName = getClassNameFromElement(beanElement);
141: beanClassName = fixClassName(beanClassName);
142: Class beanClass = null;
143: if (_cl == null) {
144: beanClass = Class.forName(beanClassName);
145: } else {
146: beanClass = Class.forName(beanClassName, true, _cl);
147: }
148: Object bean = beanClass.newInstance();
149: BeanInfo info = Introspector.getBeanInfo(bean.getClass(),
150: Introspector.USE_ALL_BEANINFO);
151: PropertyDescriptor[] propDesc = info
152: .getPropertyDescriptors();
153: Map<String, PropertyDescriptor> props = new HashMap<String, PropertyDescriptor>();
154: for (int i = 0; i < propDesc.length; ++i) {
155: props.put(propDesc[i].getName(), propDesc[i]);
156: }
157: final List<IXMLElement> children = beanElement
158: .getChildren();
159: for (Iterator<IXMLElement> it = children.iterator(); it
160: .hasNext();) {
161: final IXMLElement propElem = it.next();
162: final PropertyDescriptor curProp = props.get(propElem
163: .getName());
164: if (curProp != null) {
165: loadProperty(bean, curProp, propElem);
166: }
167: }
168:
169: return bean;
170: } catch (Exception ex) {
171: s_log.error(
172: "Unexpected exception while attempting to load xml bean "
173: + ex.getMessage(), ex);
174: throw new XMLException(ex);
175: }
176: }
177:
178: private void loadProperty(Object bean,
179: PropertyDescriptor propDescr, IXMLElement propElem)
180: throws XMLException {
181: final Method setter = propDescr.getWriteMethod();
182: if (setter != null) {
183: final Class parmType = setter.getParameterTypes()[0];
184: final Class arrayType = parmType.getComponentType();
185: final String value = propElem.getContent();
186: if (isIndexedElement(propElem)) {
187: Object[] data = loadIndexedProperty(propElem);
188: try {
189: // Arrays of Strings are a special case.
190: // In XMLBeanWriter method ProcessProperty an array of
191: // Strings is turned into a list of StringWrapper objects
192: // in the XML (presumably so that when reading them back
193: // we have a class that we can call setters on). Thus,
194: // when reading back an array of Strings we actually read
195: // an array of StringWrappers, which gives a type mis-match
196: // in the following arrayCopy. Therefore we need to convert
197: // the data that is currently in the StringWrapper objects
198: // into actual Strings.
199: if (arrayType.getName().equals("java.lang.String")) {
200: // convert data from StringWrappers to Strings
201: Object[] stringData = new Object[data.length];
202: for (int i = 0; i < data.length; i++)
203: stringData[i] = ((StringWrapper) data[i])
204: .getString();
205: data = stringData;
206: }
207:
208: Object obj = Array.newInstance(arrayType,
209: data.length);
210: System.arraycopy(data, 0, obj, 0, data.length);
211: setter.invoke(bean, new Object[] { obj });
212: } catch (Exception ex) {
213: throw new XMLException(ex);
214: }
215: } else if (isBeanElement(propElem)) {
216: Object data = loadBean(propElem);
217: try {
218: setter.invoke(bean, new Object[] { data });
219: } catch (Exception ex) {
220: throw new XMLException(ex);
221: }
222: } else if (parmType == boolean.class) {
223: Object data = new Boolean(value);
224: try {
225: setter.invoke(bean, new Object[] { data });
226: } catch (Exception ex) {
227: throw new XMLException(ex);
228: }
229: } else if (parmType == int.class) {
230: Object data = new Integer(value);
231: try {
232: setter.invoke(bean, new Object[] { data });
233: } catch (Exception ex) {
234: throw new XMLException(ex);
235: }
236: } else if (parmType == short.class) {
237: Object data = new Short(value);
238: try {
239: setter.invoke(bean, new Object[] { data });
240: } catch (Exception ex) {
241: throw new XMLException(ex);
242: }
243: } else if (parmType == long.class) {
244: Object data = new Long(value);
245: try {
246: setter.invoke(bean, new Object[] { data });
247: } catch (Exception ex) {
248: throw new XMLException(ex);
249: }
250: } else if (parmType == float.class) {
251: Object data = new Float(value);
252: try {
253: setter.invoke(bean, new Object[] { data });
254: } catch (Exception ex) {
255: throw new XMLException(ex);
256: }
257: } else if (parmType == double.class) {
258: Object data = new Double(value);
259: try {
260: setter.invoke(bean, new Object[] { data });
261: } catch (Exception ex) {
262: throw new XMLException(ex);
263: }
264: } else if (parmType == char.class) {
265: Object data;
266: if (value != null && value.length() > 0) {
267: data = new Character(value.charAt(0));
268: } else {
269: data = new Character(' ');
270: }
271: try {
272: setter.invoke(bean, new Object[] { data });
273: } catch (Exception ex) {
274: throw new XMLException(ex);
275: }
276: } else {
277: Object data = value;
278: try {
279: setter.invoke(bean, new Object[] { data });
280: } catch (Exception ex) {
281: throw new XMLException(ex);
282: }
283: }
284: }
285: }
286:
287: private Object[] loadIndexedProperty(IXMLElement beanElement)
288: throws XMLException {
289: final List<Object> beans = new ArrayList<Object>();
290: final List<IXMLElement> children = beanElement.getChildren();
291: for (Iterator<IXMLElement> it = children.iterator(); it
292: .hasNext();) {
293: beans.add(loadBean(it.next()));
294: }
295: return beans.toArray(new Object[beans.size()]);
296: }
297:
298: private boolean isBeanElement(IXMLElement elem) {
299: return elem.getAttribute(XMLConstants.CLASS_ATTRIBUTE_NAME,
300: null) != null;
301: }
302:
303: private boolean isIndexedElement(IXMLElement elem) {
304: String att = elem.getAttribute(XMLConstants.INDEXED, "false");
305: return att != null && att.equals("true");
306: }
307:
308: private String getClassNameFromElement(IXMLElement elem) {
309: return elem.getAttribute(XMLConstants.CLASS_ATTRIBUTE_NAME,
310: null);
311: }
312:
313: private String fixClassName(String className) {
314: for (int i = 0; i < _fixStrings.length; ++i) {
315: String from = _fixStrings[i][0];
316: if (className.startsWith(from)) {
317: className = _fixStrings[i][1]
318: + className.substring(from.length());
319: break;
320: }
321: }
322: return className;
323: }
324: }
|