Adds support for pazpar2 info command
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / data / ResponseParser.java
1 package com.indexdata.mkjsf.pazpar2.data;\r
2 \r
3 import java.io.ByteArrayInputStream;\r
4 import java.io.IOException;\r
5 import java.io.UnsupportedEncodingException;\r
6 import java.util.Arrays;\r
7 import java.util.List;\r
8 import java.util.Stack;\r
9 \r
10 import javax.xml.parsers.ParserConfigurationException;\r
11 import javax.xml.parsers.SAXParser;\r
12 import javax.xml.parsers.SAXParserFactory;\r
13 \r
14 import org.apache.log4j.Logger;\r
15 import org.xml.sax.Attributes;\r
16 import org.xml.sax.InputSource;\r
17 import org.xml.sax.SAXException;\r
18 import org.xml.sax.XMLReader;\r
19 import org.xml.sax.helpers.DefaultHandler;\r
20 \r
21 import com.indexdata.mkjsf.pazpar2.ClientCommandResponse;\r
22 import com.indexdata.mkjsf.pazpar2.data.sp.AuthResponse;\r
23 import com.indexdata.mkjsf.pazpar2.data.sp.CategoriesResponse;\r
24 import com.indexdata.mkjsf.pazpar2.data.sp.TargetCategory;\r
25 \r
26 /**\r
27  * Parses the XML stored in ClientCommandResponses and builds ResponseDataObjects from it.\r
28  *  \r
29  * @author Niels Erik\r
30  *\r
31  */\r
32 public class ResponseParser extends DefaultHandler {\r
33 \r
34   private XMLReader xmlReader = null;\r
35   private ResponseDataObject currentElement = null;\r
36   private Stack<ResponseDataObject> dataElements = new Stack<ResponseDataObject>();\r
37   private ResponseDataObject result = null;\r
38   private String xml = null;\r
39   private static Logger logger = Logger.getLogger(ResponseParser.class);\r
40 \r
41   public static List<String> docTypes = Arrays.asList(  "bytarget","termlist","show","stat","record","search","init","info",\r
42                                         /* SP extras */ "auth", "categories" );                                        \r
43   \r
44   public ResponseParser() {\r
45     try {\r
46       initSax();\r
47     } catch (ParserConfigurationException e) {\r
48       // TODO Auto-generated catch block\r
49       e.printStackTrace();\r
50     } catch (SAXException e) {\r
51       // TODO Auto-generated catch block\r
52       e.printStackTrace();\r
53     }\r
54   }\r
55   \r
56   public static ResponseParser getParser() {\r
57     return new ResponseParser();\r
58   }\r
59   \r
60   private void initSax() throws ParserConfigurationException, SAXException {\r
61     SAXParserFactory spf = SAXParserFactory.newInstance();\r
62     spf.setNamespaceAware(true);\r
63     SAXParser saxParser = spf.newSAXParser();\r
64     xmlReader = saxParser.getXMLReader();\r
65     xmlReader.setContentHandler(this);         \r
66   }\r
67   \r
68   /**\r
69    * Parses a Pazpar2 XML response -- or an error response as XML -- and produces a \r
70    * ResponseDataObject object, i.e. a 'show' object\r
71    * \r
72    * @param response XML response string from Pazpar2\r
73    * @return Response data object\r
74    */\r
75   public ResponseDataObject getDataObject (ClientCommandResponse response) {\r
76     this.xml = response.getResponseString();\r
77     try {      \r
78       xmlReader.parse(new InputSource(new ByteArrayInputStream(response.getResponseToParse())));\r
79     } catch (UnsupportedEncodingException e) {\r
80       e.printStackTrace(); \r
81     } catch (IOException e) {\r
82       e.printStackTrace();\r
83     } catch (SAXException e) {\r
84       e.printStackTrace();      \r
85     }\r
86     return result;\r
87   }\r
88 \r
89   /** \r
90    * Receive notification at the start of element \r
91    * \r
92    */\r
93   @Override\r
94   public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {\r
95     if (localName.equals("init")) {\r
96       currentElement = new InitResponse();\r
97     } else if (localName.equals("search")) {\r
98       currentElement = new SearchResponse();\r
99     } else if (localName.equals("show")) {\r
100       currentElement = new ShowResponse();      \r
101     } else if (localName.equals("hit")) {\r
102       currentElement = new Hit();\r
103     } else if (localName.equals("location")) {\r
104       currentElement = new Location();\r
105     } else if (localName.equals("record")) {\r
106       currentElement = new RecordResponse();            \r
107     } else if (localName.equals("bytarget")) {\r
108       currentElement = new ByTargetResponse();      \r
109     } else if (localName.equals("target")) {\r
110       currentElement = new Target();\r
111     } else if (localName.equals("stat")) {\r
112       currentElement = new StatResponse();      \r
113     } else if (localName.equals("termlist")) {\r
114       currentElement = new TermListsResponse();      \r
115     } else if (localName.equals("list")) {\r
116       currentElement = new TermListResponse();\r
117       ((TermListResponse)currentElement).setName(atts.getValue("name"));\r
118       ((TermListsResponse)dataElements.peek()).addTermList((TermListResponse)currentElement);\r
119     } else if (localName.equals("term")) {\r
120       if (dataElements.peek().getAttribute("name").equals("xtargets")) {\r
121         currentElement = new TermXTargetResponse();        \r
122       } else {\r
123         currentElement = new TermResponse();\r
124       }\r
125       ((TermListResponse)dataElements.peek()).addTerm((TermResponse)currentElement);\r
126     } else if (localName.equals("info")) {\r
127       currentElement = new InfoResponse();\r
128     } else if (localName.equals("version") && dataElements.peek().getType().equals("info")) {\r
129       currentElement = new Pazpar2VersionResponse();\r
130     } else if (localName.equals("applicationerror")) {\r
131       currentElement = new CommandError();\r
132     } else if (localName.equals("error") && dataElements.peek().getType().equals("applicationerror")) {\r
133       currentElement = new ServiceError(); \r
134     // Service Proxy extras  \r
135     } else if (localName.equals("auth")) {  \r
136       currentElement = new AuthResponse();\r
137     } else if (localName.equals("categories")) {\r
138       currentElement = new CategoriesResponse();\r
139     } else if (localName.equals("category") && dataElements.peek().getType().equals("categories")) {\r
140       currentElement = new TargetCategory();\r
141     // Catch all\r
142     } else {\r
143       currentElement = new ResponseDataObject();\r
144     }\r
145     currentElement.setType(localName);\r
146     for (int i=0; i< atts.getLength(); i++) {\r
147        currentElement.setAttribute(atts.getLocalName(i), atts.getValue(i));\r
148     }    \r
149     if (!docTypes.contains(localName)) {\r
150       if (dataElements.size() == 0) {\r
151         logger.info("Encountered unknown top level element [" + localName + "]. Creating generic data object.");\r
152         currentElement.setType(localName);\r
153       } else {\r
154         dataElements.peek().addElement(localName, currentElement);\r
155       }\r
156     }\r
157     if (this.xml != null) { // Store XML for doc level elements\r
158       currentElement.setXml(xml);\r
159       xml = null;\r
160     }\r
161     dataElements.push(currentElement);    \r
162   }\r
163  \r
164   @Override\r
165   public void characters(char[] ch, int start, int length) throws SAXException {\r
166     String data = new String(ch, start, length);        \r
167     dataElements.peek().appendContent(data);    \r
168   }\r
169   \r
170   @Override\r
171   public void endElement(String namespaceURI, String localName, String qName) throws SAXException {\r
172     if (dataElements.size()==1) {\r
173       result = dataElements.pop();\r
174     } else {\r
175       dataElements.pop();\r
176     }\r
177   }\r
178 }\r