package jpos.config.simple.xml;
///////////////////////////////////////////////////////////////////////////////
//
// This software is provided "AS IS". The JavaPOS working group (including
// each of the Corporate members, contributors and individuals) MAKES NO
// REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NON-INFRINGEMENT. The JavaPOS working group shall not be liable for
// any damages suffered as a result of using, modifying or distributing this
// software or its derivatives. Permission to use, copy, modify, and distribute
// the software and its documentation for any purpose is hereby granted.
//
// The JavaPOS Config/Loader (aka JCL) is now under the CPL license, which
// is an OSS Apache-like license. The complete license is located at:
// http://oss.software.ibm.com/developerworks/opensource/license-cpl.html
//
///////////////////////////////////////////////////////////////////////////////
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Vector;
import jpos.config.JposConfigException;
import jpos.config.JposEntry;
import jpos.config.simple.SimpleEntry;
import jpos.util.JposEntryUtility;
import jpos.util.tracing.Tracer;
import jpos.util.tracing.TracerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* Simple implementation of the JposRegPopulator that loads and saves
* the entries in XML using the "jpos/res/jcl.dtd" DTD and the XML4J
* (Xerces) API
* NOTE: this class must define a public no-argument ctor so that it may be
* created via reflection when its defined in the jpos.properties as
* the jpos.config.regPopulatorClass
* @see jpos.util.JposProperties#JPOS_REG_POPULATOR_CLASS_PROP_NAME
* @since 1.2 (NY 2K meeting)
* @author E. Michael Maximilien (maxim@us.ibm.com)
*/
public class XercesRegPopulator extends AbstractXercesRegPopulator {
//-------------------------------------------------------------------------
// Ctor(s)
//
/**
* Default ctor
* @since 1.2 (NY 2K meeting)
*/
public XercesRegPopulator() {
super(XercesRegPopulator.class.getName());
}
/**
* 1-arg constructor that takes the unique ID
* @param s the unique ID string
* @since 1.3 (Washington DC 2001)
*/
public XercesRegPopulator(String s) {
super(s);
}
//-------------------------------------------------------------------------
// Public methods
//
/**
* @return the fully qualified class name implementing the
* JposRegPopulator interface
* @since 1.3 (Washington DC 2001 meeting)
*/
public String getClassName() {
return XercesRegPopulator.class.getName();
}
/**
* Tell the populator to load the entries
* @since 1.2 (NY 2K meeting)
*/
public void load() {
tracer.println("load(): isPopulatorFileDefined=" + isPopulatorFileDefined());
if (isPopulatorFileDefined() == false) {
getJposEntries().clear();
xmlFileName = DEFAULT_XML_FILE_NAME;
load(xmlFileName);
return;
}
try {
getJposEntries().clear();
domParser.setEntityResolver(new XercesRegPopulator.JPOSDTDEntityResolver());
domParser.parse(new InputSource(getPopulatorFileIS()));
Document document = domParser.getDocument();
Enumeration entries = extractJposEntries(document);
while (entries.hasMoreElements()) {
JposEntry jposEntry = (JposEntry) entries.nextElement();
if (jposEntry.hasPropertyWithName(JposEntry.LOGICAL_NAME_PROP_NAME))
getJposEntries().put(jposEntry.getLogicalName(), jposEntry);
}
lastLoadException = null;
} catch (Exception e) {
lastLoadException = e;
tracer.println("Error loading XML file. Exception.msg = " + e.getMessage());
} finally {
}
}
/**
* Loads the entries specified in the xmlFileName
* @param xmlFileName the XML file name
* @since 1.3 (SF 2K meeting)
*/
public void load(String xmlFileName) {
tracer.println("load: xmlFileName=" + xmlFileName);
InputStream is = null;
File xmlFile = new File(xmlFileName);
try {
if (xmlFile.exists())
is = new FileInputStream(xmlFile);
else
is = findFileInClasspath(xmlFileName);
if (is == null) {
is = getClass().getClassLoader().getResourceAsStream(xmlFileName);
}
if (is == null) {
getJposEntries().clear();
tracer.println("Could not find file: " + xmlFileName + " in path or CLASSPATH");
lastLoadException = new FileNotFoundException(xmlFileName);
return;
}
lastLoadException = null;
} catch (Exception e) {
lastLoadException = e;
tracer.println("Error loading XML file. Exception.message = " + e.getMessage());
}
try {
getJposEntries().clear();
domParser.setEntityResolver(new XercesRegPopulator.JPOSDTDEntityResolver());
domParser.parse(new InputSource(is));
Document document = domParser.getDocument();
Enumeration entries = extractJposEntries(document);
while (entries.hasMoreElements()) {
JposEntry jposEntry = (JposEntry) entries.nextElement();
if (jposEntry.hasPropertyWithName(JposEntry.LOGICAL_NAME_PROP_NAME))
getJposEntries().put(jposEntry.getLogicalName(), jposEntry);
}
lastLoadException = null;
} catch (Exception e) {
lastLoadException = e;
tracer.println("Error loading XML file. Exception.message = " + e.getMessage());
} finally {
}
}
/**
* @return the name of this populator. This should be a short descriptive name
* @since 1.3 (Washington DC 2001 meeting)
*/
public String getName() {
return XERCES_REG_POPULATOR_NAME_STRING;
}
//--------------------------------------------------------------------------
// Protected methods
//
/**
* @return an enumeration of JposEntry objects read from the XML document object
* @param document the XML document object
* @since 1.2 (NY 2K meeting)
*/
protected Enumeration extractJposEntries(Document document) {
Vector entries = new Vector();
NodeList nodeList = document.getElementsByTagName("JposEntry");
String currentEntryLogicalName = "";
try {
for (int i = 0; i < nodeList.getLength(); ++i) {
Node node = nodeList.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE)
continue;
JposEntry jposEntry = new SimpleEntry();
Element jposEntryElement = (Element) node;
currentEntryLogicalName = jposEntryElement.getAttribute("logicalName");
jposEntry.addProperty("logicalName", currentEntryLogicalName);
NodeList childList = nodeList.item(i).getChildNodes();
for (int j = 0; j < childList.getLength(); ++j) {
Node child = childList.item(j);
if (child.getNodeType() != Node.ELEMENT_NODE)
continue;
Element element = (Element) child;
String elementName = element.getNodeName();
if (elementName.equals("creation"))
extractCreationAttr(jposEntry, element);
else if (elementName.equals("vendor"))
extractVendorAttr(jposEntry, element);
else if (elementName.equals("jpos"))
extractJposAttr(jposEntry, element);
else if (elementName.equals("product"))
extractProductAttr(jposEntry, element);
else
extractPropAttr(jposEntry, element);
}
if (JposEntryUtility.isValidJposEntry(jposEntry))
entries.addElement(jposEntry);
else {
String msg = "JposEntry with logicalName: " + currentEntryLogicalName + " is not valid (missing required properties)";
throw new JposConfigException(msg);
}
}
} catch (JposConfigException jce) {
tracer.println("Skipping invalid entry with logicalName: " + currentEntryLogicalName);
tracer.println("--->JposConfigException.message = " + jce.getMessage());
tracer.print(jce);
if (jce.getOrigException() != null)
tracer.print(jce.getOrigException());
}
return entries.elements();
}
/**
* Get the <creation> element attributes and adds corresponding
* properties to JposEntry
* @param jposEntry the entry to add properties to
* @param element the <creation> XML element
* @since 1.2 (NY 2K meeting)
*/
protected void extractCreationAttr(JposEntry jposEntry, Element element) {
jposEntry.addProperty("serviceInstanceFactoryClass", element.getAttribute("factoryClass"));
jposEntry.addProperty("serviceClass", element.getAttribute("serviceClass"));
}
/**
* Get the <vendor> element attributes and adds corresponding
* properties to JposEntry
* @param jposEntry the entry to add properties to
* @param element the <vendor> XML element
* @since 1.2 (NY 2K meeting)
*/
protected void extractVendorAttr(JposEntry jposEntry, Element element) {
jposEntry.addProperty("vendorName", element.getAttribute("name"));
jposEntry.addProperty("vendorURL", element.getAttribute("url"));
}
/**
* Get the <jpos> element attributes and adds corresponding properties
* to JposEntry
* @param jposEntry the entry to add properties to
* @param element the <jpos> XML element
* @since 1.2 (NY 2K meeting)
*/
protected void extractJposAttr(JposEntry jposEntry, Element element) {
jposEntry.addProperty("jposVersion", element.getAttribute("version"));
jposEntry.addProperty("deviceCategory", element.getAttribute("category"));
}
/**
* Get the <product> element attributes and adds corresponding
* properties to JposEntry
* @param jposEntry the entry to add properties to
* @param element the <product> XML element
* @since 1.2 (NY 2K meeting)
*/
protected void extractProductAttr(JposEntry jposEntry, Element element) {
jposEntry.addProperty("productName", element.getAttribute("name"));
jposEntry.addProperty("productDescription", element.getAttribute("description"));
jposEntry.addProperty("productURL", element.getAttribute("url"));
}
/**
* Get the <prop> element attributes and adds corresponding properties
* to JposEntry
* @param jposEntry the entry to add properties to
* @param element the <prop> XML element
* @since 1.2 (NY 2K meeting)
* @throws jpos.config.JposConfigException if the property value does
* not match the type or is not a valid value (like for instance
* an invalid number)
*/
protected void extractPropAttr(JposEntry jposEntry, Element element) throws JposConfigException {
String propName = element.getAttribute("name");
String propValueString = element.getAttribute("value");
String propTypeString = element.getAttribute("type");
if (propTypeString.equals(""))
propTypeString = "String";
Object propValue = null;
Class propType = null;
try {
propType = Class.forName((propTypeString.startsWith("java.lang.") ? propTypeString : "java.lang." + propTypeString));
} catch (ClassNotFoundException cnfe) {
throw new JposConfigException("Invalid property type: " + propTypeString + " for property named: " + propName, cnfe);
}
if (JposEntryUtility.isValidPropType(propType) == false)
throw new JposConfigException("Invalid property type: " + propTypeString + " for property named: " + propName);
propValue = JposEntryUtility.parsePropValue(propValueString, propType);
if (JposEntryUtility.validatePropValue(propValue, propType) == false)
throw new JposConfigException("Invalid property type: " + propTypeString + " for property named: " + propName);
jposEntry.add(jposEntry.createProp(propName, propValue, propType));
}
/**
* JposDTDEntityResolver to resolve DTD
*/
public class JPOSDTDEntityResolver implements org.xml.sax.EntityResolver {
/**
* @return the DTD as an InputSource if it is found in a JAR
* file in the CLASSPATH otherwise return null
*/
public org.xml.sax.InputSource resolveEntity(String publicId, String systemId) throws org.xml.sax.SAXException, java.io.IOException {
if (publicId.equals("-//JavaPOS//DTD//EN")) {
InputStream is = getClass().getResourceAsStream(DTD_JAR_FILE_NAME);
if (is != null) {
return (new org.xml.sax.InputSource(new InputStreamReader(is)));
}
}
return null;
}
}
//--------------------------------------------------------------------------
// Instance variables
//
private Tracer tracer = TracerFactory.getInstance().createTracer("XercesRegPopulator");
//--------------------------------------------------------------------------
// Public constants
//
public static final String DTD_JAR_FILE_NAME = "/jpos/res/jcl.dtd";
public static final String XERCES_REG_POPULATOR_NAME_STRING = "JCL XML Entries Populator";
}