/** * Copyright (C) 2012 Orbeon, Inc. * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; either version * 2.1 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html */ package org.orbeon.oxf.processor.XQuery; import org.orbeon.oxf.xml.XMLReceiver; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ObjectReceiver implements XMLReceiver { private XMLReceiver currentReceiver = null; private Field currentField = null; private Class currentMemberType = null; private StringBuilder buffer = null; private int level = 0; public void setDocumentLocator(Locator locator) { if (currentReceiver != null) { currentReceiver.setDocumentLocator(locator); } } public void startDocument() throws SAXException { if (currentReceiver != null) { currentReceiver.startDocument(); } } public void endDocument() throws SAXException { if (currentReceiver != null) { currentReceiver.endDocument(); } } public void startPrefixMapping(String s, String s1) throws SAXException { if (currentReceiver != null) { currentReceiver.startPrefixMapping(s, s1); } } public void endPrefixMapping(String s) throws SAXException { if (currentReceiver != null) { currentReceiver.endPrefixMapping(s); } } private XMLReceiver instantiateXMLReceiver(Class klass) throws SAXException { try { return (XMLReceiver) (klass.newInstance()); } catch (InstantiationException e) { // If we can't instantiate the class, it may be because it is an inner class of the current one... try { Constructor constructor = klass.getConstructor(this.getClass()); return (XMLReceiver) constructor.newInstance(this); } catch (NoSuchMethodException e1) { throw new SAXException(e1); } catch (InstantiationException e1) { throw new SAXException(e1); } catch (InvocationTargetException e1) { throw new SAXException(e1); } catch (IllegalAccessException e1) { throw new SAXException(e1); } } catch (IllegalAccessException e) { throw new SAXException(e); } } private static boolean classIsCollection(Class klass) { return Collection.class.isAssignableFrom(klass); } private static boolean classIsXMLReceiver(Class klass) { return XMLReceiver.class.isAssignableFrom(klass); } private static Class classMemberType(Field field) { // Can't believe there isn't some smarter way to do that... String genericType = field.getGenericType().toString(); Pattern memberPattern = Pattern.compile(".*<(.*)>"); Matcher matcher = memberPattern.matcher(genericType); if (matcher.matches()) { String memberTypeName = matcher.group(1); try { return Class.forName(memberTypeName); } catch (ClassNotFoundException e) { return null; } } return null; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { if (currentReceiver != null) { /* Forwarding state */ currentReceiver.startElement(uri, localName, qName, attributes); } else if (currentField == null) { /* Need to create a new object to receive the content of a new element */ currentField = this.getClass().getField(localName); Class klass = currentField.getType(); if (classIsXMLReceiver(klass)) { currentReceiver = instantiateXMLReceiver(klass); } else if (classIsCollection(klass)) { currentMemberType = classMemberType(currentField); if (classIsXMLReceiver(currentMemberType)) { currentReceiver = instantiateXMLReceiver(currentMemberType); } } buffer = null; } else { /* Sub elements are not expected here! */ throw new SAXException("Sub element " + localName + " was not expected here!"); } } catch (NoSuchFieldException e) { throw new SAXException(e); } level++; } public void endElement(String s, String s1, String s2) throws SAXException { try { level--; if (level == 0) { /* We have finished to receive an object */ if (currentReceiver == null && currentMemberType == null) { /* This was a non repeatable simple type element */ Class klass = currentField.getType(); String className = klass.getName(); String value = buffer == null ? "" : buffer.toString(); if (className.equals("int")) { currentField.setInt(this, Integer.parseInt(value)); } else if (className.equals("boolean")) { currentField.setBoolean(this, value.equals("true")); } else if (klass.equals(value.getClass())) { currentField.set(this, value); } else { currentField.set(this, klass.getConstructor(value.getClass()).newInstance(value)); } //Method method = this.getClass().getMethod("addValue", Class.forName("java.lang.String")); //method.invoke(buffer.toString()); } else if (currentReceiver == null && currentMemberType != null) { /* This was a repeatable simple type element */ String value = buffer == null ? "" : buffer.toString(); Class klass = currentField.getType(); Collection collection = (Collection) currentField.get(this); if (collection == null) { collection = (Collection) klass.newInstance(); currentField.set(this, collection); } if (currentMemberType.equals(value.getClass())) { collection.add(value); } else { collection.add(currentMemberType.getConstructor(value.getClass()).newInstance(value)); } } else if (currentMemberType != null) { Class klass = currentField.getType(); Collection collection = (Collection) currentField.get(this); if (collection == null) { collection = (Collection) klass.newInstance(); currentField.set(this, collection); } collection.add(currentReceiver); } else { /* This was not a simple type element */ currentField.set(this, currentReceiver); } currentReceiver = null; currentField = null; currentMemberType = null; buffer = null; } else { currentReceiver.endElement(s, s1, s2); } } catch (IllegalAccessException e) { throw new SAXException(e); } catch (NoSuchMethodException e) { throw new SAXException(e); } catch (InstantiationException e) { throw new SAXException(e); } catch (InvocationTargetException e) { throw new SAXException(e); } } public void characters(char[] chars, int i, int i1) throws SAXException { if (currentReceiver != null) { currentReceiver.characters(chars, i, i1); } else if (buffer == null) { buffer = new StringBuilder(new String(chars, i, i1)); } else { buffer.append(chars, i, i1); } } public void ignorableWhitespace(char[] chars, int i, int i1) throws SAXException { if (currentReceiver != null) { currentReceiver.ignorableWhitespace(chars, i, i1); } } public void processingInstruction(String s, String s1) throws SAXException { if (currentReceiver != null) { currentReceiver.processingInstruction(s, s1); } } public void skippedEntity(String s) throws SAXException { if (currentReceiver != null) { currentReceiver.skippedEntity(s); } } public void startDTD(String s, String s1, String s2) throws SAXException { if (currentReceiver != null) { currentReceiver.startDTD(s, s1, s2); } } public void endDTD() throws SAXException { if (currentReceiver != null) { currentReceiver.endDTD(); } } public void startEntity(String s) throws SAXException { if (currentReceiver != null) { currentReceiver.startEntity(s); } } public void endEntity(String s) throws SAXException { if (currentReceiver != null) { currentReceiver.endEntity(s); } } public void startCDATA() throws SAXException { if (currentReceiver != null) { currentReceiver.startCDATA(); } } public void endCDATA() throws SAXException { if (currentReceiver != null) { currentReceiver.endCDATA(); } } public void comment(char[] chars, int i, int i1) throws SAXException { if (currentReceiver != null) { currentReceiver.comment(chars, i, i1); } } }