1 | package de.uni_leipzig.asv.clarin.webservices.pidservices2.impl; |
---|
2 | |
---|
3 | import java.util.Iterator; |
---|
4 | import java.util.Map; |
---|
5 | import java.util.regex.Matcher; |
---|
6 | import java.util.regex.Pattern; |
---|
7 | |
---|
8 | import net.sf.json.JSONArray; |
---|
9 | import net.sf.json.JSONObject; |
---|
10 | |
---|
11 | import org.apache.commons.httpclient.HttpException; |
---|
12 | import org.slf4j.Logger; |
---|
13 | import org.slf4j.LoggerFactory; |
---|
14 | |
---|
15 | import com.sun.jersey.api.client.Client; |
---|
16 | import com.sun.jersey.api.client.ClientHandlerException; |
---|
17 | import com.sun.jersey.api.client.ClientResponse; |
---|
18 | import com.sun.jersey.api.client.UniformInterfaceException; |
---|
19 | import com.sun.jersey.api.client.WebResource; |
---|
20 | import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; |
---|
21 | |
---|
22 | import de.uni_leipzig.asv.clarin.webservices.pidservices2.Configuration; |
---|
23 | import de.uni_leipzig.asv.clarin.webservices.pidservices2.HandleField; |
---|
24 | import de.uni_leipzig.asv.clarin.webservices.pidservices2.interfaces.PidWriter; |
---|
25 | |
---|
26 | /** |
---|
27 | * Registering new handles at handle server or modifying existing PID entries |
---|
28 | * |
---|
29 | * @author Thomas Eckart |
---|
30 | * @author Twan Goosen |
---|
31 | */ |
---|
32 | public class PidWriterImpl implements PidWriter { |
---|
33 | |
---|
34 | private final static Logger LOG = LoggerFactory.getLogger(PidWriterImpl.class); |
---|
35 | public static final Pattern PID_INPUT_PATTERN = Pattern.compile("^[0-9A-z-]+$"); |
---|
36 | private static final Pattern PID_OUTPUT_PATTERN = Pattern.compile(".*location</dt><dd><a href=\"([0-9A-z-]+)\">.*"); |
---|
37 | |
---|
38 | /** |
---|
39 | * |
---|
40 | * @param configuration |
---|
41 | * @param fieldMap |
---|
42 | * @param pid PID to be created, must match {@link #PID_INPUT_PATTERN} |
---|
43 | * @return |
---|
44 | * @throws HttpException if the PID could not be created, for instance |
---|
45 | * because the requested PID already exists |
---|
46 | * @throws IllegalArgumentException if the provided PID does not match |
---|
47 | * {@link #PID_INPUT_PATTERN} |
---|
48 | */ |
---|
49 | @Override |
---|
50 | public String registerNewPID(final Configuration configuration, Map<HandleField, String> fieldMap, String pid) |
---|
51 | throws HttpException, IllegalArgumentException { |
---|
52 | LOG.debug("Try to create handle {} at {} with values: {}", pid, configuration.getServiceBaseURL(), fieldMap); |
---|
53 | |
---|
54 | // validate the requested PID |
---|
55 | if (!PID_INPUT_PATTERN.matcher(pid).matches()) { |
---|
56 | throw new IllegalArgumentException(pid); |
---|
57 | } |
---|
58 | |
---|
59 | // adding the PID to the request URL |
---|
60 | final String baseUrl = String.format("%s%s/%s", |
---|
61 | configuration.getServiceBaseURL(), configuration.getHandlePrefix(), pid); |
---|
62 | final WebResource.Builder resourceBuilder = createResourceBuilderForNewPID(configuration, baseUrl); |
---|
63 | |
---|
64 | final JSONArray jsonArray = createJSONArray(fieldMap); |
---|
65 | final ClientResponse response = resourceBuilder |
---|
66 | // this header will tell the server to fail if the requested PID already exists |
---|
67 | .header("If-None-Match", "*") |
---|
68 | // PUT the handle at the specified location |
---|
69 | .put(ClientResponse.class, jsonArray.toString()); |
---|
70 | return processCreateResponse(response, configuration); |
---|
71 | } |
---|
72 | |
---|
73 | @Override |
---|
74 | public String registerNewPID(final Configuration configuration, Map<HandleField, String> fieldMap) |
---|
75 | throws HttpException { |
---|
76 | LOG.debug("Try to create handle at {} with values: {}", configuration.getServiceBaseURL(), fieldMap); |
---|
77 | |
---|
78 | final String baseUrl = configuration.getServiceBaseURL() + configuration.getHandlePrefix(); |
---|
79 | final WebResource.Builder resourceBuilder = createResourceBuilderForNewPID(configuration, baseUrl); |
---|
80 | |
---|
81 | final JSONArray jsonArray = createJSONArray(fieldMap); |
---|
82 | final ClientResponse response = resourceBuilder |
---|
83 | // POST the new handle definition to the handles resource |
---|
84 | .post(ClientResponse.class, jsonArray.toString()); |
---|
85 | return processCreateResponse(response, configuration); |
---|
86 | } |
---|
87 | |
---|
88 | private WebResource.Builder createResourceBuilderForNewPID(final Configuration configuration, final String baseUrl) { |
---|
89 | final Client client = Client.create(); |
---|
90 | client.addFilter(new HTTPBasicAuthFilter(configuration.getUser(), configuration.getPassword())); |
---|
91 | // TODO: request JSON ("application/json") as soon as GWDG respects that accept header |
---|
92 | final WebResource.Builder resourceBuilder = client.resource(baseUrl).accept("application/xhtml+xml").type("application/json"); |
---|
93 | return resourceBuilder; |
---|
94 | } |
---|
95 | |
---|
96 | private String processCreateResponse(final ClientResponse response, final Configuration configuration) throws HttpException, UniformInterfaceException, RuntimeException, ClientHandlerException { |
---|
97 | if (response.getStatus() != 201) { |
---|
98 | throw new HttpException("" + response.getStatus()); |
---|
99 | } |
---|
100 | |
---|
101 | // TODO CHANGE this to JSON processing ASAP, when GWDG respects accept header |
---|
102 | String responseString = response.getEntity(String.class).trim().replaceAll("\n", ""); |
---|
103 | Matcher matcher = PID_OUTPUT_PATTERN.matcher(responseString); |
---|
104 | if (matcher.matches()) { |
---|
105 | return configuration.getHandlePrefix() + "/" + matcher.group(1); |
---|
106 | } else { |
---|
107 | LOG.error("No PID found in response string: {}", responseString); |
---|
108 | throw new RuntimeException("Unparsable response from " + configuration.getServiceBaseURL()); |
---|
109 | } |
---|
110 | } |
---|
111 | |
---|
112 | @Override |
---|
113 | public void modifyPid(final Configuration configuration, final String pid, Map<HandleField, String> fieldMap) { |
---|
114 | LOG.debug("Try to modify handle \"" + pid + "\" at " + configuration.getServiceBaseURL() + " with new values: " |
---|
115 | + fieldMap); |
---|
116 | |
---|
117 | final Client client = Client.create(); |
---|
118 | client.addFilter(new HTTPBasicAuthFilter(configuration.getUser(), configuration.getPassword())); |
---|
119 | final WebResource webResource = client.resource(configuration.getServiceBaseURL() + pid); |
---|
120 | |
---|
121 | JSONArray jsonArray = createJSONArray(fieldMap); |
---|
122 | webResource.accept("application/json").type("application/json").put(ClientResponse.class, jsonArray.toString()); |
---|
123 | } |
---|
124 | |
---|
125 | /** |
---|
126 | * Generates JSON array that is understood by the EPIC handle service |
---|
127 | * |
---|
128 | * @param fieldMap mapping handle field -> value |
---|
129 | * @return JSON array |
---|
130 | */ |
---|
131 | private JSONArray createJSONArray(Map<HandleField, String> fieldMap) { |
---|
132 | JSONArray jsonArray = new JSONArray(); |
---|
133 | JSONObject jsonObject; |
---|
134 | |
---|
135 | Iterator<HandleField> fieldIter = fieldMap.keySet().iterator(); |
---|
136 | while (fieldIter.hasNext()) { |
---|
137 | jsonObject = new JSONObject(); |
---|
138 | HandleField handleFieldTyp = fieldIter.next(); |
---|
139 | jsonObject.put("type", handleFieldTyp); |
---|
140 | jsonObject.put("parsed_data", fieldMap.get(handleFieldTyp)); |
---|
141 | jsonArray.add(jsonObject); |
---|
142 | } |
---|
143 | |
---|
144 | return jsonArray; |
---|
145 | } |
---|
146 | } |
---|