/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package fedora.server.storage.service; import java.io.InputStream; import java.util.HashMap; import java.util.StringTokenizer; import java.util.Vector; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import fedora.common.Constants; import fedora.server.errors.ObjectIntegrityException; import fedora.server.errors.RepositoryConfigurationException; import fedora.server.storage.types.DeploymentDSBindRule; import fedora.server.storage.types.DeploymentDSBindSpec; /** * A class for parsing the special XML format in Fedora for a Datastream Input * Specification (DSInputSpec). A DSInputSpec exists within a Service Deployment * Object, and is used to define the "data contract" between the service * represented by the deployment and a data object. * * @author Sandy Payette * @version $Id$ */ public class DSInputSpecParser extends DefaultHandler implements Constants { /** * URI-to-namespace prefix mapping info from SAX2 startPrefixMapping events. */ private HashMap<String, String> nsPrefixMap; private boolean inDSInputLabel = false; private boolean inDSInputInstructions = false; private boolean inDSInputMIME = false; // Fedora Datastream Binding Spec objects private DeploymentDSBindSpec dsInputSpec; private DeploymentDSBindRule dsInputRule; private final String sDepPID; // Working variables... private Vector<DeploymentDSBindRule> tmp_InputRules; /** * Constructor to enable another class to initiate the parsing */ public DSInputSpecParser(String parentPID) { sDepPID = parentPID; } /** * Constructor allows this class to initiate the parsing */ public DSInputSpecParser(String parentPID, InputStream in) throws RepositoryConfigurationException, ObjectIntegrityException { sDepPID = parentPID; XMLReader xmlReader = null; try { SAXParserFactory saxfactory = SAXParserFactory.newInstance(); saxfactory.setValidating(false); SAXParser parser = saxfactory.newSAXParser(); xmlReader = parser.getXMLReader(); xmlReader.setContentHandler(this); xmlReader.setFeature("http://xml.org/sax/features/namespaces", false); xmlReader .setFeature("http://xml.org/sax/features/namespace-prefixes", false); } catch (Exception e) { throw new RepositoryConfigurationException("Internal SAX error while " + "preparing for DSInputSpec datastream deserialization: " + e.getMessage()); } try { xmlReader.parse(new InputSource(in)); } catch (Exception e) { throw new ObjectIntegrityException("Error parsing DSInputSpec datastream" + e.getClass().getName() + ": " + e.getMessage()); } } public DeploymentDSBindSpec getServiceDSInputSpec() { return dsInputSpec; } @Override public void startDocument() throws SAXException { nsPrefixMap = new HashMap<String, String>(); tmp_InputRules = new Vector<DeploymentDSBindRule>(); dsInputSpec = new DeploymentDSBindSpec(); } @Override public void endDocument() throws SAXException { dsInputSpec.dsBindRules = (DeploymentDSBindRule[]) tmp_InputRules .toArray(new DeploymentDSBindRule[0]); tmp_InputRules = null; nsPrefixMap = null; } @Override public void startPrefixMapping(String prefix, String uri) throws SAXException { nsPrefixMap.put(uri, prefix); } @Override public void skippedEntity(String name) throws SAXException { StringBuffer sb = new StringBuffer(); sb.append('&'); sb.append(name); sb.append(';'); char[] text = new char[sb.length()]; sb.getChars(0, sb.length(), text, 0); characters(text, 0, text.length); } @Override public void characters(char ch[], int start, int length) throws SAXException { if (inDSInputLabel) { dsInputRule.bindingLabel = new String(ch, start, length); } else if (inDSInputInstructions) { dsInputRule.bindingInstruction = new String(ch, start, length); } else if (inDSInputMIME) { StringTokenizer st = new StringTokenizer(new String(ch, start, length), " "); String[] MIMETypes = new String[st.countTokens()]; for (int i = 0; i < MIMETypes.length; i++) { MIMETypes[i] = st.nextToken(); } dsInputRule.bindingMIMETypes = MIMETypes; } } @Override public void startElement(String namespaceURI, String localName, String qName, Attributes attrs) throws SAXException { if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInputSpec")) { dsInputSpec.serviceDeploymentPID = sDepPID; dsInputSpec.bindSpecLabel = attrs.getValue("label"); } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInput")) { dsInputRule = new DeploymentDSBindRule(); if (attrs.getValue("pid") != null) { dsInputRule.pid = attrs.getValue("pid"); } dsInputRule.bindingKeyName = attrs.getValue("wsdlMsgPartName"); dsInputRule.maxNumBindings = new Integer(attrs.getValue("DSMax")).intValue(); dsInputRule.minNumBindings = new Integer(attrs.getValue("DSMin")).intValue(); dsInputRule.ordinality = Boolean.parseBoolean(attrs.getValue("DSOrdinality")); } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInputLabel")) { inDSInputLabel = true; } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInputInstruction")) { inDSInputInstructions = true; } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSMIME")) { inDSInputMIME = true; } } @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInputSpec")) { } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInput")) { tmp_InputRules.add(dsInputRule); dsInputRule = null; } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInputLabel")) { inDSInputLabel = false; } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSInputInstruction")) { inDSInputInstructions = false; } else if (namespaceURI.equalsIgnoreCase(BINDING_SPEC.uri) && localName.equalsIgnoreCase("DSMIME")) { inDSInputMIME = false; } } }