1 package org.fedoracommons.funapi.pmh;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.StringReader;
7 import java.io.StringWriter;
8 import java.io.UnsupportedEncodingException;
9
10 import java.net.URL;
11
12 import javax.xml.transform.Source;
13 import javax.xml.transform.Transformer;
14 import javax.xml.transform.TransformerException;
15 import javax.xml.transform.TransformerFactory;
16 import javax.xml.transform.dom.DOMSource;
17 import javax.xml.transform.stream.StreamResult;
18 import javax.xml.xpath.XPath;
19 import javax.xml.xpath.XPathConstants;
20 import javax.xml.xpath.XPathExpressionException;
21 import javax.xml.xpath.XPathFactory;
22
23 import org.apache.commons.httpclient.HttpClient;
24 import org.apache.commons.httpclient.HttpMethod;
25 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
26 import org.apache.commons.httpclient.UsernamePasswordCredentials;
27 import org.apache.commons.httpclient.auth.AuthScope;
28 import org.apache.commons.httpclient.methods.GetMethod;
29
30 import org.w3c.dom.Node;
31 import org.w3c.dom.NodeList;
32
33 import org.xml.sax.InputSource;
34
35 import org.fedoracommons.funapi.FormatException;
36 import org.fedoracommons.funapi.IdentifierException;
37 import org.fedoracommons.funapi.ObjectResolver;
38 import org.fedoracommons.funapi.UnapiException;
39 import org.fedoracommons.funapi.UnapiFormat;
40 import org.fedoracommons.funapi.UnapiFormats;
41 import org.fedoracommons.funapi.UnapiObject;
42 import org.fedoracommons.funapi.utilities.NamespaceContextImpl;
43
44
45 import static org.apache.commons.httpclient.HttpStatus.SC_OK;
46
47
48
49
50
51
52
53 public abstract class AbstractPmhResolver
54 implements ObjectResolver {
55
56 private final static String FORMATS = "%s?verb=ListMetadataFormats";
57 private final static String RECORD = "%s?verb=GetRecord&metadataPrefix=%s&identifier=%s";
58 private NamespaceContextImpl nsCtx;
59 private HttpClient httpClient;
60 private HttpMethod httpMethod;
61
62 public UnapiFormats getFormats() throws UnapiException {
63 String mdFormats = listMetadataFormats();
64 UnapiFormats formats = new UnapiFormats(null);
65 XPath xpath = getXPath();
66 NodeList nodelist = null;
67 try {
68 nodelist = (NodeList)xpath.evaluate("//oai:metadataFormat",
69 new InputSource(new StringReader(mdFormats)),
70 XPathConstants.NODESET);
71 for(int i = 0; i < nodelist.getLength(); i++) {
72 Node node = nodelist.item(i);
73 String format = xpath.evaluate("oai:metadataPrefix", node);
74 String docs = xpath.evaluate("oai:schema", node);
75 UnapiFormat uFormat = new UnapiFormat(format, "application/xml", docs);
76 formats.addFormat(uFormat);
77 }
78 } catch (XPathExpressionException e) {
79 throw new UnapiException(e.getMessage(), e);
80 }
81 return formats;
82 }
83
84 public UnapiFormats getFormats(String id) throws UnapiException {
85 UnapiFormats formats = getFormats();
86 formats.setId(id);
87 return formats;
88 }
89
90 public UnapiObject getObject(String id, String format) throws UnapiException {
91 try {
92 String record = getRecord(id, format);
93 XPath xpath = getXPath();
94
95 Node pmh = (Node)xpath.evaluate("//oai:OAI-PMH",
96 new InputSource(new StringReader(record)),
97 XPathConstants.NODE);
98
99 Node metadata = (Node)xpath.evaluate("//oai:metadata/*",
100 pmh,
101 XPathConstants.NODE);
102
103 if (metadata == null) {
104 String error = xpath.evaluate("//oai:error/@code", pmh);
105 if (error.equalsIgnoreCase("idDoesNotExist")) {
106 throw new IdentifierException(error);
107 } else if (error.equalsIgnoreCase("cannotDisseminateFormat")) {
108 throw new FormatException(error);
109 } else {
110 throw new UnapiException(error);
111 }
112 }
113
114 TransformerFactory xformFactory = TransformerFactory.newInstance();
115 Transformer transformer = xformFactory.newTransformer();
116
117 Source source = new DOMSource(metadata);
118 StringWriter sw = new StringWriter();
119 transformer.transform(source, new StreamResult(sw));
120 InputStream in = new ByteArrayInputStream(sw.toString().getBytes("UTF-8"));
121 return new UnapiObject(in, "application/xml");
122 } catch (XPathExpressionException e) {
123 throw new UnapiException(e.getMessage(), e);
124 } catch (TransformerException e) {
125 throw new UnapiException(e.getMessage(), e);
126 } catch (UnsupportedEncodingException e) {
127 throw new UnapiException(e.getMessage(), e);
128 }
129 }
130
131 private XPath getXPath() {
132 XPathFactory xpFactory = XPathFactory.newInstance();
133 XPath xpath = xpFactory.newXPath();
134 if (nsCtx == null) {
135 nsCtx = new NamespaceContextImpl();
136 nsCtx.addNamespace("oai", "http://www.openarchives.org/OAI/2.0/");
137 nsCtx.addNamespace("oai_dc", "http://www.openarchives.org/OAI/2.0/oai_dc/");
138 nsCtx.addNamespace("dc", "http://purl.org/dc/elements/1.1/");
139 }
140 xpath.setNamespaceContext(nsCtx);
141 return xpath;
142 }
143
144 protected HttpClient getHttpClient() {
145 if (httpClient != null) {
146 return httpClient;
147 }
148 MultiThreadedHttpConnectionManager connectionManager =
149 new MultiThreadedHttpConnectionManager();
150
151 HttpClient client = new HttpClient(connectionManager);
152 client.getParams().setAuthenticationPreemptive(true);
153 if (getUsername() != null && getPassword() != null) {
154 client.getState().setCredentials(
155 new AuthScope(getPmhBaseUrl().getHost(),
156 getPmhBaseUrl().getPort(), null),
157 new UsernamePasswordCredentials(getUsername(), getPassword())
158 );
159 }
160 return client;
161 }
162
163 protected void setHttpClient(HttpClient httpClient) {
164 this.httpClient = httpClient;
165 }
166
167 protected void setHttpMethod(HttpMethod httpMethod) {
168 this.httpMethod = httpMethod;
169 }
170
171 private String listMetadataFormats() throws UnapiException {
172 String url = String.format(FORMATS, getPmhBaseUrl());
173 return getResponse(url);
174 }
175
176 private String getRecord(String id, String format) throws UnapiException {
177 String url = String.format(RECORD, getPmhBaseUrl(), format, getPmhId(id));
178 return getResponse(url);
179 }
180
181 private String getResponse(String url) throws UnapiException {
182 HttpMethod getMethod;
183 if (httpMethod == null) {
184 getMethod = new GetMethod(url);
185 } else {
186 getMethod = httpMethod;
187 }
188 try {
189 int status = getHttpClient().executeMethod(getMethod);
190 if (status != SC_OK) {
191 throw new UnapiException(status, getMethod.getStatusText());
192 }
193 return getMethod.getResponseBodyAsString();
194 } catch (IOException e) {
195 throw new UnapiException(e.getMessage(), e);
196 } finally {
197 getMethod.releaseConnection();
198 }
199 }
200
201
202
203
204
205 protected abstract String getPmhId(String id);
206
207
208
209
210
211 protected abstract URL getPmhBaseUrl();
212
213
214
215
216 protected abstract String getUsername();
217
218
219
220
221 protected abstract String getPassword();
222 }