/* * eXist Open Source Native XML Database * Copyright (C) 2001-2015 The eXist Project * http://exist-db.org * * 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 * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.exist.config.mapper; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Stack; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.events.XMLEvent; import org.exist.config.Configurable; import org.exist.config.Configuration; import org.exist.config.Configurator; import org.exist.config.annotation.NewClass; /** * @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a> */ public class Constructor { private static Map<Object, Configuration> configurations = new HashMap<Object, Configuration>(); public static Configuration getConfiguration(Object obj) { return configurations.get(obj); } /** * Create new java object by mapping instructions. */ public static Object load(NewClass newClazz, Configurable instance, Configuration conf) { final String url = newClazz.mapper(); if (url == null) { Configurator.LOG.error("Field must have 'ConfigurationFieldClassMask' annotation or " + "registered mapping instruction for class '" + newClazz.name() + "' [" + conf.getName() + "], " + "skip instance creation."); return null; } final InputStream is = instance.getClass().getClassLoader().getResourceAsStream(url); if (is == null) { Configurator.LOG.error("Registered mapping instruction for class '" + newClazz.name() + "' " + "missing resource '" + url + "', skip instance creation."); return null; } final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); try { final XMLStreamReader reader = inputFactory.createXMLStreamReader(is); Object obj = null; final Stack<Object> objs = new Stack<>(); final Stack<CallMethod> instructions = new Stack<>(); int eventType; while (reader.hasNext()) { eventType = reader.next(); switch (eventType) { case XMLEvent.START_ELEMENT: String localName = reader.getLocalName(); if ("class".equals(localName)) { if (!"name".equals(reader.getAttributeLocalName(0))) { Configurator.LOG.error("class element first attribute must be 'name', skip instance creation."); return null; } final String clazzName = reader.getAttributeValue(0); final Class<?> clazz = Class.forName(clazzName); final java.lang.reflect.Constructor<?> constructor = clazz.getConstructor(); Object newInstance = constructor.newInstance(); if (obj == null) { obj = newInstance; } objs.add(newInstance); if (!instructions.empty()) { instructions.peek().setValue(newInstance); } } else if ("callMethod".equals(localName)) { Configuration _conf_ = conf; if (!instructions.empty()) { _conf_ = instructions.peek().getConfiguration(); } final CallMethod call = new CallMethod(objs.peek(), _conf_); for (int i = 0; i < reader.getAttributeCount(); i++) { call.set(reader.getAttributeLocalName(i), reader.getAttributeValue(i)); } instructions.add(call); } break; case XMLEvent.END_ELEMENT: localName = reader.getLocalName(); //System.out.println("END_ELEMENT "+localName); if ("class".equals(localName)) { objs.pop(); } else if ("callMethod".equals(localName)) { final CallMethod call = instructions.pop(); call.eval(); } break; } } configurations.put(obj, conf); return obj; } catch (final Exception e) { Configurator.LOG.error(e); } return null; } }