Merge branch 'master' of ssh://git.indexdata.com/home/git/private/mkjsf.git into...
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / data / ResponseParser.java
diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/data/ResponseParser.java b/src/main/java/com/indexdata/mkjsf/pazpar2/data/ResponseParser.java
new file mode 100644 (file)
index 0000000..56e4218
--- /dev/null
@@ -0,0 +1,174 @@
+package com.indexdata.mkjsf.pazpar2.data;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+import java.io.UnsupportedEncodingException;\r
+import java.util.Arrays;\r
+import java.util.List;\r
+import java.util.Stack;\r
+\r
+import javax.xml.parsers.ParserConfigurationException;\r
+import javax.xml.parsers.SAXParser;\r
+import javax.xml.parsers.SAXParserFactory;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.xml.sax.Attributes;\r
+import org.xml.sax.InputSource;\r
+import org.xml.sax.SAXException;\r
+import org.xml.sax.XMLReader;\r
+import org.xml.sax.helpers.DefaultHandler;\r
+\r
+import com.indexdata.mkjsf.pazpar2.ClientCommandResponse;\r
+import com.indexdata.mkjsf.pazpar2.data.sp.AuthResponse;\r
+import com.indexdata.mkjsf.pazpar2.data.sp.CategoriesResponse;\r
+import com.indexdata.mkjsf.pazpar2.data.sp.TargetCategory;\r
+\r
+/**\r
+ * Parses the XML stored in ClientCommandResponses and builds ResponseDataObjects from it.\r
+ *  \r
+ * @author Niels Erik\r
+ *\r
+ */\r
+public class ResponseParser extends DefaultHandler {\r
+\r
+  private XMLReader xmlReader = null;\r
+  private ResponseDataObject currentElement = null;\r
+  private Stack<ResponseDataObject> dataElements = new Stack<ResponseDataObject>();\r
+  private ResponseDataObject result = null;\r
+  private String xml = null;\r
+  private static Logger logger = Logger.getLogger(ResponseParser.class);\r
+\r
+  public static List<String> docTypes = Arrays.asList(  "bytarget","termlist","show","stat","record","search","init",\r
+                                        /* SP extras */ "auth", "categories" );                                        \r
+  \r
+  public ResponseParser() {\r
+    try {\r
+      initSax();\r
+    } catch (ParserConfigurationException e) {\r
+      // TODO Auto-generated catch block\r
+      e.printStackTrace();\r
+    } catch (SAXException e) {\r
+      // TODO Auto-generated catch block\r
+      e.printStackTrace();\r
+    }\r
+  }\r
+  \r
+  public static ResponseParser getParser() {\r
+    return new ResponseParser();\r
+  }\r
+  \r
+  private void initSax() throws ParserConfigurationException, SAXException {\r
+    SAXParserFactory spf = SAXParserFactory.newInstance();\r
+    spf.setNamespaceAware(true);\r
+    SAXParser saxParser = spf.newSAXParser();\r
+    xmlReader = saxParser.getXMLReader();\r
+    xmlReader.setContentHandler(this);         \r
+  }\r
+  \r
+  /**\r
+   * Parses a Pazpar2 XML response -- or an error response as XML -- and produces a \r
+   * ResponseDataObject object, i.e. a 'show' object\r
+   * \r
+   * @param response XML response string from Pazpar2\r
+   * @return Response data object\r
+   */\r
+  public ResponseDataObject getDataObject (ClientCommandResponse response) {\r
+    this.xml = response.getResponseString();\r
+    try {      \r
+      xmlReader.parse(new InputSource(new ByteArrayInputStream(response.getResponseToParse())));\r
+    } catch (UnsupportedEncodingException e) {\r
+      e.printStackTrace(); \r
+    } catch (IOException e) {\r
+      e.printStackTrace();\r
+    } catch (SAXException e) {\r
+      e.printStackTrace();      \r
+    }\r
+    return result;\r
+  }\r
+\r
+  /** \r
+   * Receive notification at the start of element \r
+   * \r
+   */\r
+  @Override\r
+  public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {\r
+    if (localName.equals("init")) {\r
+      currentElement = new InitResponse();\r
+    } else if (localName.equals("search")) {\r
+      currentElement = new SearchResponse();\r
+    } else if (localName.equals("show")) {\r
+      currentElement = new ShowResponse();      \r
+    } else if (localName.equals("hit")) {\r
+      currentElement = new Hit();\r
+    } else if (localName.equals("location")) {\r
+      currentElement = new Location();\r
+    } else if (localName.equals("record")) {\r
+      currentElement = new RecordResponse();            \r
+    } else if (localName.equals("bytarget")) {\r
+      currentElement = new ByTargetResponse();      \r
+    } else if (localName.equals("target")) {\r
+      currentElement = new Target();\r
+    } else if (localName.equals("stat")) {\r
+      currentElement = new StatResponse();      \r
+    } else if (localName.equals("termlist")) {\r
+      currentElement = new TermListsResponse();      \r
+    } else if (localName.equals("list")) {\r
+      currentElement = new TermListResponse();\r
+      ((TermListResponse)currentElement).setName(atts.getValue("name"));\r
+      ((TermListsResponse)dataElements.peek()).addTermList((TermListResponse)currentElement);\r
+    } else if (localName.equals("term")) {\r
+      if (dataElements.peek().getAttribute("name").equals("xtargets")) {\r
+        currentElement = new TermXTargetResponse();        \r
+      } else {\r
+        currentElement = new TermResponse();\r
+      }\r
+      ((TermListResponse)dataElements.peek()).addTerm((TermResponse)currentElement);\r
+    } else if (localName.equals("applicationerror")) {\r
+      currentElement = new CommandError();\r
+    } else if (localName.equals("error") && dataElements.peek().getType().equals("applicationerror")) {\r
+      currentElement = new ServiceError(); \r
+    // Service Proxy extras  \r
+    } else if (localName.equals("auth")) {  \r
+      currentElement = new AuthResponse();\r
+    } else if (localName.equals("categories")) {\r
+      currentElement = new CategoriesResponse();\r
+    } else if (localName.equals("category") && dataElements.peek().getType().equals("categories")) {\r
+      currentElement = new TargetCategory();\r
+    // Catch all\r
+    } else {\r
+      currentElement = new ResponseDataObject();\r
+    }\r
+    currentElement.setType(localName);\r
+    for (int i=0; i< atts.getLength(); i++) {\r
+       currentElement.setAttribute(atts.getLocalName(i), atts.getValue(i));\r
+    }    \r
+    if (!docTypes.contains(localName)) {\r
+      if (dataElements.size() == 0) {\r
+        logger.info("Encountered unknown top level element [" + localName + "]. Creating generic data object.");\r
+        currentElement.setType(localName);\r
+      } else {\r
+        dataElements.peek().addElement(localName, currentElement);\r
+      }\r
+    }\r
+    if (this.xml != null) { // Store XML for doc level elements\r
+      currentElement.setXml(xml);\r
+      xml = null;\r
+    }\r
+    dataElements.push(currentElement);    \r
+  }\r
\r
+  @Override\r
+  public void characters(char[] ch, int start, int length) throws SAXException {\r
+    String data = new String(ch, start, length);        \r
+    dataElements.peek().appendContent(data);    \r
+  }\r
+  \r
+  @Override\r
+  public void endElement(String namespaceURI, String localName, String qName) throws SAXException {\r
+    if (dataElements.size()==1) {\r
+      result = dataElements.pop();\r
+    } else {\r
+      dataElements.pop();\r
+    }\r
+  }\r
+}\r