1 package org.fedoracommons.funapi.fedora;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.StringReader;
6 import java.io.StringWriter;
7
8 import java.net.MalformedURLException;
9 import java.net.URL;
10
11 import java.util.ArrayList;
12 import java.util.HashSet;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Properties;
16 import java.util.Set;
17
18 import javax.xml.parsers.DocumentBuilder;
19 import javax.xml.parsers.DocumentBuilderFactory;
20 import javax.xml.parsers.ParserConfigurationException;
21 import javax.xml.rpc.ServiceException;
22
23 import org.apache.commons.httpclient.HttpClient;
24 import org.apache.commons.httpclient.HttpException;
25 import org.apache.commons.httpclient.HttpMethod;
26 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
27 import org.apache.commons.httpclient.UsernamePasswordCredentials;
28 import org.apache.commons.httpclient.auth.AuthScope;
29 import org.apache.commons.httpclient.methods.HeadMethod;
30
31 import org.w3c.dom.Document;
32 import org.w3c.dom.Element;
33
34 import org.xml.sax.InputSource;
35 import org.xml.sax.SAXException;
36
37 import org.codehaus.jackson.JsonFactory;
38 import org.codehaus.jackson.JsonGenerator;
39 import org.codehaus.jackson.map.JsonNode;
40 import org.codehaus.jackson.map.JsonTypeMapper;
41 import org.fedoracommons.funapi.FormatException;
42 import org.fedoracommons.funapi.ObjectResolver;
43 import org.fedoracommons.funapi.UnapiException;
44 import org.fedoracommons.funapi.UnapiFormat;
45 import org.fedoracommons.funapi.UnapiFormats;
46 import org.fedoracommons.funapi.UnapiObject;
47
48 import fedora.client.FedoraClient;
49
50 import fedora.common.PID;
51
52 import fedora.server.access.FedoraAPIA;
53 import fedora.server.management.FedoraAPIM;
54 import fedora.server.types.gen.DatastreamDef;
55 import fedora.server.types.gen.MIMETypedStream;
56 import fedora.server.types.gen.RelationshipTuple;
57
58 import static org.apache.commons.httpclient.HttpStatus.SC_OK;
59
60 import static fedora.common.Constants.MODEL;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public class FedoraResolver
95 implements ObjectResolver {
96
97 private Properties props;
98 private URL baseURL;
99 private String username;
100 private String password;
101 private String formatsDS;
102 private String defaultFormats;
103 private final static String FEDORA_URI = "info:fedora/";
104 private FedoraClient fedoraClient;
105 private JsonFactory jsonFactory;
106 private HttpClient httpClient;
107
108 public FedoraResolver() throws UnapiException {
109 InputStream in = getClass().getResourceAsStream("/FedoraResolver.properties");
110 props = new Properties();
111 try {
112 props.load(in);
113 } catch (IOException e) {
114 throw new UnapiException(e.getMessage(), e);
115 }
116
117
118 String temp = props.getProperty("baseURL");
119 if (!temp.endsWith("/")) {
120 temp += "/";
121 }
122 try {
123 baseURL = new URL(temp);
124 } catch (MalformedURLException e) {
125 throw new UnapiException(e.getMessage(), e);
126 }
127
128 username = props.getProperty("username");
129 password = props.getProperty("password");
130 formatsDS = props.getProperty("formatsDatastream");
131 defaultFormats = props.getProperty("defaultFormats");
132 try {
133 fedoraClient = new FedoraClient(baseURL.toString(), username, password);
134 } catch (MalformedURLException e) {
135 throw new UnapiException(e.getMessage(), e);
136 }
137 jsonFactory = new JsonFactory();
138 }
139
140 public UnapiFormats getFormats() throws UnapiException {
141 UnapiFormats formats;
142 if (defaultFormats == null) {
143 formats = new UnapiFormats(null);
144 UnapiFormat format = new UnapiFormat("oai_dc","text/xml","http://www.openarchives.org/OAI/2.0/oai_dc.xsd");
145 formats.addFormat(format);
146 } else {
147 try {
148 formats = parseJsonArray(null, defaultFormats);
149 } catch (IOException e) {
150 throw new UnapiException(e.getMessage(), e);
151 }
152 }
153 return formats;
154 }
155
156 public UnapiFormats getFormats(String id) throws UnapiException {
157 checkHttpStatusCode(id);
158
159 UnapiFormats formats;
160 try {
161 formats = parseJsonArray(id, getJsonArray(id));
162 } catch (ServiceException e) {
163 throw new UnapiException(e.getMessage(), e);
164 } catch (IOException e) {
165 throw new UnapiException(e.getMessage(), e);
166 }
167 return formats;
168 }
169
170 public UnapiObject getObject(String id, String format) throws UnapiException {
171 checkHttpStatusCode(id);
172 String url;
173 try {
174 url = getDisseminationUrl(id, format);
175 } catch (ServiceException e) {
176 throw new FormatException(e.getMessage(), e);
177 } catch (IOException e) {
178 throw new UnapiException(e.getMessage(), e);
179 }
180 return new UnapiObject(url);
181 }
182
183
184
185
186
187
188
189 private String getURL(String id) {
190 String newId = null;
191 if (id.startsWith(FEDORA_URI)) {
192 newId = id.substring(FEDORA_URI.length());
193 } else {
194 newId = id;
195 }
196 return baseURL + "get/" + newId;
197 }
198
199
200
201
202
203
204
205
206
207 private String getJsonArray(String id) throws IOException, ServiceException, UnapiException {
208 FedoraAPIA apia;
209 FedoraAPIM apim;
210 apia = fedoraClient.getAPIA();
211 apim = fedoraClient.getAPIM();
212
213 PID pid = PID.getInstance(id);
214
215 RelationshipTuple[] tuples = apim.getRelationships(pid.toString(), MODEL.HAS_MODEL.uri);
216 List<String> cmodels = new ArrayList<String>();
217 for (RelationshipTuple tuple: tuples) {
218 cmodels.add(tuple.getObject());
219 }
220
221 JsonTypeMapper jtMapper = new JsonTypeMapper();
222 JsonNode rootNode = null;
223 for (String cmodel : cmodels) {
224 MIMETypedStream ds = null;
225
226 DatastreamDef[] dsDefs = apia.listDatastreams(cmodel, null);
227 for (DatastreamDef dsDef : dsDefs) {
228 if (dsDef.getID().equals(formatsDS)) {
229 ds = apia.getDatastreamDissemination(cmodel, formatsDS, null);
230 continue;
231 }
232 }
233 if (ds == null) {
234 continue;
235 }
236 String dsXML = new String(ds.getStream(), "UTF-8");
237
238 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
239 DocumentBuilder builder;
240 Document doc = null;
241 try {
242 builder = factory.newDocumentBuilder();
243 doc = builder.parse(new InputSource(new StringReader(dsXML)));
244 } catch (ParserConfigurationException e) {
245 throw new UnapiException(e.getMessage(), e);
246 } catch (SAXException e) {
247 throw new UnapiException(e.getMessage(), e);
248 }
249
250 Element jsonElement = (Element)doc.getElementsByTagName("json").item(0);
251
252 String json = jsonElement.getTextContent();
253 JsonNode node = jtMapper.read(jsonFactory.createJsonParser(new StringReader(json)));
254 if (rootNode == null) {
255 rootNode = node;
256 } else {
257 Iterator<JsonNode> it = node.getElements();
258 while(it.hasNext()) {
259 rootNode.appendElement(it.next());
260 }
261 }
262 }
263
264 if (rootNode == null) {
265 return null;
266 } else {
267 StringWriter sw = new StringWriter();
268 JsonGenerator gen = jsonFactory.createJsonGenerator(sw);
269 rootNode.writeTo(gen);
270 gen.close();
271 return sw.toString();
272 }
273 }
274
275 private UnapiFormats parseJsonArray(String id, String jsonContent) throws IOException, UnapiException {
276 UnapiFormats uFormats = new UnapiFormats(id);
277 if (jsonContent == null) {
278 return uFormats;
279 }
280 Set<String> formats = new HashSet<String>();
281
282 JsonNode rootNode = new JsonTypeMapper().read(jsonFactory.createJsonParser(new StringReader(jsonContent)));
283 Iterator<JsonNode> it = rootNode.getElements();
284 while (it.hasNext()) {
285 JsonNode innerArray = it.next();
286 String format = innerArray.getElementValue(1).getTextValue();
287 String type = innerArray.getElementValue(2).getTextValue();
288 String docs = innerArray.getElementValue(3).getTextValue();
289
290 if (formats.add(format)) {
291 UnapiFormat uFormat = new UnapiFormat(format, type, docs);
292 uFormats.addFormat(uFormat);
293 }
294 }
295 return uFormats;
296 }
297
298 private String getDisseminationUrl(String id, String format) throws ServiceException, IOException, UnapiException {
299 String pid = PID.getInstance(id).toString();
300 String dissType = null;
301
302 String jsonContent = getJsonArray(id);
303 JsonNode rootNode = new JsonTypeMapper().read(jsonFactory.createJsonParser(new StringReader(jsonContent)));
304
305 Iterator<JsonNode> it = rootNode.getElements();
306 while (it.hasNext()) {
307 JsonNode innerArray = it.next();
308
309 String fmt = innerArray.getElementValue(1).getTextValue();
310 if (format.equalsIgnoreCase(fmt)) {
311 dissType = innerArray.getElementValue(0).getTextValue();
312 break;
313 }
314 }
315 if (dissType == null) {
316 throw new UnapiException("No dissType for " + id);
317 }
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367