/* * ALMA - Atacama Large Millimiter Array * (c) European Southern Observatory, 2002 * Copyright by ESO (in the framework of the ALMA collaboration), * All rights reserved * * This library 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 library 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., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package alma.acs.entityutil; import java.io.StringReader; import java.util.logging.Level; import java.util.logging.Logger; import org.exolab.castor.xml.Unmarshaller; import alma.entities.commonentity.EntityT; import alma.xmlentity.XmlEntityStruct; /** * Helper class to convert serialized XML entities from the ALMA project data model (APDM) * to their Java binding class representations. * <p> * Note that normally a Java component does not need to explicitly perform this conversion, * since the Java container translates between the XML-string representation that goes over CORBA, * and the binding class (tree) that the custom-generated component's Java interface uses * as parameters or return value. * <p> * However, there is a case where a Java component should use the <code>EntityDeserializer</code>: * Applications receiving XML data from the ALMA archive: the archive does currently not offer a type-safe * interface for APDM entities. Use {@link #deserializeEntity(XmlEntityStruct, Class)} to convert * the <code>XmlEntityStruct</code> you get from the archive into a Java binding object tree * whose root node is an instance of the specified <code>Class</code>. * * @author hsommer May 6, 2003 5:31:57 PM */ public class EntityDeserializer { private Logger m_logger; private static EntityDeserializer s_entityDeserializer; private EntityTFinder m_finder; /** * Singleton accessor. * * @param logger Logger to be used * (may be null in subsequent invocations since only one instance of * EntityDeserializer is constructed and then reused) * * @return single instance */ public static EntityDeserializer getEntityDeserializer(Logger logger) { if (s_entityDeserializer == null) { s_entityDeserializer = new EntityDeserializer(logger); } return s_entityDeserializer; } /** * @param logger */ private EntityDeserializer(Logger logger) { m_logger = logger; m_finder = new EntityTFinder(m_logger); } /** * Deserializes (parses) an entity xml and instantiates the binding objects. * * @param xmlString the stringified xml. * @param entityClass the binding class of which we want an instance * filled with the xml data. * @param timestamp the timestamp to be stored in the entity object, for later serialization. * @return the binding class instance (should be casted by the caller). * @throws EntityException if the binding class instance can't be constructed from the xml. * Note that this exception is only logged at FINER level by this method, so make sure to log it appropriately. */ private Object deserializeEntity(String xmlString, Class entityClass, String timestamp) throws EntityException { if (xmlString == null) throw new EntityException("xmlString was null."); if (entityClass == null) throw new EntityException("entityClass was null."); if (timestamp == null) timestamp = ""; Object entity; try { Unmarshaller unmarsh = new Unmarshaller(entityClass); unmarsh.setValidation(false); unmarsh.setWhitespacePreserve(true); // unmarsh.setIgnoreExtraAttributes(true); // unmarsh.setIgnoreExtraElements(true); entity = unmarsh.unmarshal(new StringReader(xmlString)); } catch (Exception e) { String xmlStringStart = xmlString.substring(0, Math.min(512, xmlString.length())); // trim huge xml to avoid overly long log message String msg = "Failed to parse xml into entity binding class '" + entityClass.getName() + "'. The xml data was " + xmlStringStart; m_logger.log(Level.FINER, msg, e); throw new EntityException(msg, e); } // store the timestamp in the entity; this is a temporary storage, until // the entity is converted back into an XmlEntityStruct; then the timestamp // becomes irrelevant. if (entity != null) { EntityT entityMeta = m_finder.extractEntityT(entity); if (entityMeta != null) { entityMeta.setTimestamp(timestamp); } } return entity; } /** * Deserializes (parses) the entity xml contained in <code>xes</code> * and instantiates the binding objects. * * @param xes the struct used for CORBA transport of serialized entity objects. * @param entityClass the binding class of which we want an instance * filled with the xml data, e.g. <code>SchedBlock.class</code>. * @return the binding class instance (should be cast to <code>entityClass</code> by the caller). * @throws EntityException */ public Object deserializeEntity(XmlEntityStruct xes, Class entityClass) throws EntityException { String xml = xes.xmlString; String timestamp = xes.timeStamp; return deserializeEntity(xml, entityClass, timestamp); } }