package com.temenos.interaction.core.entity; /* * #%L * interaction-core * %% * Copyright (C) 2012 - 2013 Temenos Holdings N.V. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 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 General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.io.InputStream; import java.util.Collections; import java.util.Deque; import java.util.LinkedList; import java.util.Stack; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.temenos.interaction.core.entity.vocabulary.TermFactory; import com.temenos.interaction.core.entity.vocabulary.Vocabulary; import com.temenos.interaction.core.entity.vocabulary.terms.TermComplexGroup; import com.temenos.interaction.core.entity.vocabulary.terms.TermComplexType; /** * Parser to read metadata from an XML file. */ public class MetadataParser extends DefaultHandler { private static final Logger logger = LoggerFactory.getLogger(MetadataParser.class); TermFactory termFactory; Metadata metadata = null; EntityMetadata entityMetadata = null; //Meta data for current entity Stack<String> propertyName = new Stack<String>(); //Stack of property names Deque<Vocabulary> propertyVocabulary = new LinkedList<Vocabulary>(); //Stack of property vocabularies boolean isComplexProperty = false; //Indicates if this is a complex property String termName = null; //Name of vocabulary term String termValue = null; //Value of vocabulary term public MetadataParser() { termFactory = new TermFactory(); } public MetadataParser(TermFactory termFactory) { this.termFactory = termFactory; } /** * Parse an XML document. * @param reader I/O Reader providing the xml document * @return Metadata containing the metadata or null if error */ public Metadata parse(InputStream is) { SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser saxParser = factory.newSAXParser(); saxParser.parse(is, this); } catch (Exception e) { logger.debug("Failed to parse input stream content", e); return null; } logger.debug("parsed, element count = " + entityMetadata.getPropertyVocabularyKeySet().size() ); return metadata; } @Override public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException { if (qName.equalsIgnoreCase("Metadata")) { metadata = new Metadata(attributes.getValue("ModelName")); } else if (qName.equalsIgnoreCase("Entity")) { entityMetadata = new EntityMetadata(attributes.getValue("Name")); } else if (qName.equalsIgnoreCase("Property")) { String name = attributes.getValue("Name"); Vocabulary voc = new Vocabulary(); if(!propertyName.isEmpty()) { //This property belongs to a complex property => set complex group term try { voc.setTerm(termFactory.createTerm(TermComplexGroup.TERM_NAME, propertyName.peek())); } catch(Exception e) { throw new SAXException(e); } } propertyName.push(name); propertyVocabulary.push(voc); isComplexProperty = false; } else if (qName.equalsIgnoreCase("Term")) { termName = attributes.getValue("Name"); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equalsIgnoreCase("Entity")) { metadata.setEntityMetadata(entityMetadata); } else if (qName.equalsIgnoreCase("Property")) { String name = propertyName.pop(); Vocabulary voc = propertyVocabulary.pop(); if(isComplexProperty) { //This is a complex property try { voc.setTerm(termFactory.createTerm(TermComplexType.TERM_NAME, "true")); } catch(Exception e) { throw new SAXException(e); } } if ( name == null ) { throw new SAXException("Parse error: Property without name in Entity " + entityMetadata.getEntityName()); } entityMetadata.setPropertyVocabulary(name, voc, Collections.enumeration(propertyName)); isComplexProperty = !propertyName.isEmpty(); } else if (qName.equalsIgnoreCase("Term")) { try { if(!propertyName.isEmpty()) { propertyVocabulary.peek().setTerm(termFactory.createTerm(termName, termValue)); } else { Vocabulary voc = new Vocabulary(); voc.setTerm(termFactory.createTerm(termName, termValue)); entityMetadata.setVocabulary(voc); } termValue = null; } catch(Exception e) { throw new SAXException(e); } finally { termName = null; //characters() uses termName to avoid reading elements other than Terms } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (termName != null) { if(termValue != null) { //this method may be invoked multiple times if data is read in chunks termValue += new String(ch, start, length); } else { termValue = new String(ch, start, length); } } } }