comparison src/main/java/de/mpiwg/itgroup/annotations/restlet/AnnotatorResourceImpl.java @ 4:3599b29c393f

store seems to work now :-)
author casties
date Mon, 02 Jul 2012 22:39:46 +0200
parents 47b53ae385d1
children bbf0cc5bee29
comparison
equal deleted inserted replaced
3:47b53ae385d1 4:3599b29c393f
11 import java.util.ArrayList; 11 import java.util.ArrayList;
12 import java.util.List; 12 import java.util.List;
13 import java.util.regex.Matcher; 13 import java.util.regex.Matcher;
14 import java.util.regex.Pattern; 14 import java.util.regex.Pattern;
15 15
16 import javax.servlet.ServletContext;
17
16 import net.oauth.jsontoken.Checker; 18 import net.oauth.jsontoken.Checker;
17 import net.oauth.jsontoken.JsonToken; 19 import net.oauth.jsontoken.JsonToken;
18 import net.oauth.jsontoken.JsonTokenParser; 20 import net.oauth.jsontoken.JsonTokenParser;
19 import net.oauth.jsontoken.SystemClock; 21 import net.oauth.jsontoken.SystemClock;
20 import net.oauth.jsontoken.crypto.HmacSHA256Verifier; 22 import net.oauth.jsontoken.crypto.HmacSHA256Verifier;
23 import org.apache.commons.codec.binary.Base64; 25 import org.apache.commons.codec.binary.Base64;
24 import org.apache.log4j.Logger; 26 import org.apache.log4j.Logger;
25 import org.json.JSONArray; 27 import org.json.JSONArray;
26 import org.json.JSONException; 28 import org.json.JSONException;
27 import org.json.JSONObject; 29 import org.json.JSONObject;
28 import org.restlet.data.ClientInfo;
29 import org.restlet.data.Form; 30 import org.restlet.data.Form;
30 import org.restlet.data.Status; 31 import org.restlet.data.Status;
31 import org.restlet.representation.Representation; 32 import org.restlet.representation.Representation;
32 import org.restlet.resource.Options; 33 import org.restlet.resource.Options;
33 import org.restlet.resource.ServerResource; 34 import org.restlet.resource.ServerResource;
34 import org.restlet.security.User; 35
35 36 import de.mpiwg.itgroup.annotations.Annotation;
36 import de.mpiwg.itgroup.annotationManager.Constants.NS; 37 import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes;
37 import de.mpiwg.itgroup.annotationManager.RDFHandling.Annotation; 38 import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
39 import de.mpiwg.itgroup.annotations.old.NS;
38 40
39 /** 41 /**
40 * Base class for Annotator resource classes. 42 * Base class for Annotator resource classes.
41 * 43 *
42 * @author dwinter, casties 44 * @author dwinter, casties
43 * 45 *
44 */ 46 */
45 public abstract class AnnotatorResourceImpl extends ServerResource { 47 public abstract class AnnotatorResourceImpl extends ServerResource {
46 48
47 protected Logger logger = Logger.getRootLogger(); 49 protected static Logger logger = Logger.getLogger(AnnotatorResourceImpl.class);
50
51 private AnnotationStore store;
48 52
49 protected String getAllowedMethodsForHeader() { 53 protected String getAllowedMethodsForHeader() {
50 return "OPTIONS,GET,POST"; 54 return "OPTIONS,GET,POST";
55 }
56
57 protected AnnotationStore getAnnotationStore() {
58 if (store == null) {
59 ServletContext sc = (ServletContext) getContext().getServerDispatcher().getContext().getAttributes()
60 .get("org.restlet.ext.servlet.ServletContext");
61 logger.debug("Getting AnnotationStore from Context");
62 store = (AnnotationStore) sc.getAttribute(RestServer.ANNSTORE_KEY);
63 }
64 return store;
51 } 65 }
52 66
53 public String encodeJsonId(String id) { 67 public String encodeJsonId(String id) {
54 try { 68 try {
55 return Base64.encodeBase64URLSafeString(id.getBytes("UTF-8")); 69 return Base64.encodeBase64URLSafeString(id.getBytes("UTF-8"));
112 public boolean isAuthenticated(Representation entity) { 126 public boolean isAuthenticated(Representation entity) {
113 return (checkAuthToken(entity) != null); 127 return (checkAuthToken(entity) != null);
114 } 128 }
115 129
116 /** 130 /**
117 * checks Annotator Auth plugin authentication information from headers. returns userId if successful. 131 * checks Annotator Auth plugin authentication information from headers.
132 * returns userId if successful.
118 * 133 *
119 * @param entity 134 * @param entity
120 * @return 135 * @return
121 */ 136 */
122 public String checkAuthToken(Representation entity) { 137 public String checkAuthToken(Representation entity) {
163 */ 178 */
164 public JSONObject createAnnotatorJson(Annotation annot) { 179 public JSONObject createAnnotatorJson(Annotation annot) {
165 boolean makeUserObject = true; 180 boolean makeUserObject = true;
166 JSONObject jo = new JSONObject(); 181 JSONObject jo = new JSONObject();
167 try { 182 try {
168 jo.put("text", annot.text); 183 jo.put("text", annot.getBodyText());
169 jo.put("uri", annot.url); 184 jo.put("uri", annot.getTargetBaseUri());
170 185
171 if (makeUserObject) { 186 if (makeUserObject) {
172 // create user object 187 // create user object
173 JSONObject userObject = new JSONObject(); 188 JSONObject userObject = new JSONObject();
174 // save creator as uri 189 // save creator as uri
175 userObject.put("uri", annot.creator); 190 userObject.put("uri", annot.getCreatorUri());
176 // make short user id 191 // make short user id
177 String userID = annot.creator; 192 String userId = annot.getCreatorUri();
178 if (userID.startsWith(NS.MPIWG_PERSONS_URL)) { 193 if (userId != null && userId.startsWith(NS.MPIWG_PERSONS_URL)) {
179 userID = userID.replace(NS.MPIWG_PERSONS_URL, ""); // entferne 194 userId = userId.replace(NS.MPIWG_PERSONS_URL, ""); // entferne
180 // NAMESPACE 195 // NAMESPACE
181 } 196 }
182 // save as id 197 // save as id
183 userObject.put("id", userID); 198 userObject.put("id", userId);
184 // get full name 199 // get full name
185 RestServer restServer = (RestServer) getApplication(); 200 RestServer restServer = (RestServer) getApplication();
186 String userName = restServer.getUserNameFromLdap(userID); 201 String userName = restServer.getUserNameFromLdap(userId);
187 userObject.put("name", userName); 202 userObject.put("name", userName);
188 // save user object 203 // save user object
189 jo.put("user", userObject); 204 jo.put("user", userObject);
190 } else { 205 } else {
191 // save user as string 206 // save user as string
192 jo.put("user", annot.creator); 207 jo.put("user", annot.getCreatorUri());
193 } 208 }
194 209
195 List<String> xpointers = new ArrayList<String>(); 210 if (annot.getTargetFragment() != null) {
196 if (annot.xpointers == null || annot.xpointers.size() == 0)
197 xpointers.add(annot.xpointer);
198 else {
199 for (String xpointerString : annot.xpointers) {
200 xpointers.add(xpointerString);
201 }
202 }
203 if (!xpointers.isEmpty()) {
204 // we only look at the first xpointer 211 // we only look at the first xpointer
205 String xt = getXpointerType(xpointers.get(0)); 212 List<String> fragments = new ArrayList<String>();
206 if (xt == "range") { 213 fragments.add(annot.getTargetFragment());
207 jo.put("ranges", transformToRanges(xpointers)); 214 FragmentTypes xt = annot.getFragmentType();
208 } else if (xt == "area") { 215 if (xt == FragmentTypes.XPOINTER) {
209 jo.put("areas", transformToAreas(xpointers)); 216 jo.put("ranges", transformToRanges(fragments));
217 } else if (xt == FragmentTypes.AREA) {
218 jo.put("areas", transformToAreas(fragments));
210 } 219 }
211 } 220 }
212 // encode Annotation URL (=id) in base64 221 // encode Annotation URL (=id) in base64
213 String annotUrl = annot.getAnnotationUri(); 222 String annotUrl = annot.getUri();
214 String annotId = encodeJsonId(annotUrl); 223 String annotId = encodeJsonId(annotUrl);
215 jo.put("id", annotId); 224 jo.put("id", annotId);
216 return jo; 225 return jo;
217 } catch (JSONException e) { 226 } catch (JSONException e) {
218 // TODO Auto-generated catch block 227 // TODO Auto-generated catch block
219 e.printStackTrace(); 228 e.printStackTrace();
220 } 229 }
221 return null; 230 return null;
222 } 231 }
223 232
224 private String getXpointerType(String xpointer) {
225 if (xpointer.contains("#xpointer")) {
226 return "range";
227 } else if (xpointer.contains("#xywh")) {
228 return "area";
229 }
230 return null;
231 }
232
233 private JSONArray transformToRanges(List<String> xpointers) { 233 private JSONArray transformToRanges(List<String> xpointers) {
234 234
235 JSONArray ja = new JSONArray(); 235 JSONArray ja = new JSONArray();
236 236
237 Pattern rg = Pattern 237 Pattern rg = Pattern
238 .compile("#xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)/range-to\\(end-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)\\)"); 238 .compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)/range-to\\(end-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)\\)");
239 Pattern rg1 = Pattern.compile("#xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)"); 239 Pattern rg1 = Pattern.compile("xpointer\\(start-point\\(string-range\\(\"([^\"]*)\",([^,]*),1\\)\\)\\)");
240 240
241 try { 241 try {
242 for (String xpointer : xpointers) { 242 for (String xpointer : xpointers) {
243 String decoded = URLDecoder.decode(xpointer, "utf-8"); 243 String decoded = URLDecoder.decode(xpointer, "utf-8");
244 Matcher m = rg.matcher(decoded); 244 Matcher m = rg.matcher(decoded);
275 275
276 private JSONArray transformToAreas(List<String> xpointers) { 276 private JSONArray transformToAreas(List<String> xpointers) {
277 277
278 JSONArray ja = new JSONArray(); 278 JSONArray ja = new JSONArray();
279 279
280 Pattern rg = Pattern.compile("#xywh=(\\w*:)([\\d\\.]+),([\\d\\.]+),([\\d\\.]+),([\\d\\.]+)"); 280 Pattern rg = Pattern.compile("xywh=(\\w*:)([\\d\\.]+),([\\d\\.]+),([\\d\\.]+),([\\d\\.]+)");
281 281
282 try { 282 try {
283 for (String xpointer : xpointers) { 283 for (String xpointer : xpointers) {
284 String decoded = URLDecoder.decode(xpointer, "utf-8"); 284 String decoded = URLDecoder.decode(xpointer, "utf-8");
285 Matcher m = rg.matcher(decoded); 285 Matcher m = rg.matcher(decoded);
305 } 305 }
306 306
307 return ja; 307 return ja;
308 } 308 }
309 309
310 protected String parseArea(JSONObject area) throws JSONException, UnsupportedEncodingException {
311 String x = area.getString("x");
312 String y = area.getString("y");
313 String width = "0";
314 String height = "0";
315 if (area.has("width")) {
316 width = area.getString("width");
317 height = area.getString("height");
318 }
319 String fragment = URLEncoder.encode(String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height), "utf-8");
320 return fragment;
321 }
322
323 protected String parseRange(JSONObject range) throws JSONException, UnsupportedEncodingException {
324 String start = range.getString("start");
325 String end = range.getString("end");
326 String startOffset = range.getString("startOffset");
327 String endOffset = range.getString("endOffset");
328
329 String fragment = URLEncoder.encode(String.format(
330 "xpointer(start-point(string-range(\"%s\",%s,1))/range-to(end-point(string-range(\"%s\",%s,1))))", start,
331 startOffset, end, endOffset), "utf-8");
332 return fragment;
333 }
334
310 /** 335 /**
311 * creates an Annotation object with data from JSON. 336 * creates an Annotation object with data from JSON.
312 * 337 *
313 * uses the specification from the annotator project: {@link https ://github.com/okfn/annotator/wiki/Annotation-format} 338 * uses the specification from the annotator project: {@link https
314 * 339 * ://github.com/okfn/annotator/wiki/Annotation-format}
315 * The username will be transformed to an URI if not given already as URI, if not it will set to the MPIWG namespace defined in 340 *
341 * The username will be transformed to an URI if not given already as URI,
342 * if not it will set to the MPIWG namespace defined in
316 * de.mpiwg.itgroup.annotationManager.Constants.NS 343 * de.mpiwg.itgroup.annotationManager.Constants.NS
317 * 344 *
318 * @param jo 345 * @param jo
319 * @return 346 * @return
320 * @throws JSONException 347 * @throws JSONException
321 */ 348 * @throws UnsupportedEncodingException
322 public Annotation createAnnotation(JSONObject jo, Representation entity) throws JSONException { 349 */
350 public Annotation createAnnotation(JSONObject jo, Representation entity) throws JSONException, UnsupportedEncodingException {
323 return updateAnnotation(new Annotation(), jo, entity); 351 return updateAnnotation(new Annotation(), jo, entity);
324 } 352 }
325 353
326 public Annotation updateAnnotation(Annotation annot, JSONObject jo, Representation entity) throws JSONException { 354 public Annotation updateAnnotation(Annotation annot, JSONObject jo, Representation entity) throws JSONException,
355 UnsupportedEncodingException {
327 // annotated uri 356 // annotated uri
328 String url = annot.url;
329 if (jo.has("uri")) { 357 if (jo.has("uri")) {
330 url = jo.getString("uri"); 358 annot.setTargetBaseUri(jo.getString("uri"));
331 } 359 }
332 // annotation text 360 // annotation text
333 String text = annot.text;
334 if (jo.has("text")) { 361 if (jo.has("text")) {
335 text = jo.getString("text"); 362 annot.setBodyText(jo.getString("text"));
336 } 363 }
337 // check authentication 364 // check authentication
338 String authUser = checkAuthToken(entity); 365 String authUser = checkAuthToken(entity);
339 if (authUser == null) { 366 if (authUser == null) {
340 // try http auth 367 /*
341 User httpUser = getHttpAuthUser(entity); 368 * // try http auth User httpUser = getHttpAuthUser(entity); if
342 if (httpUser == null) { 369 * (httpUser == null) {
343 setStatus(Status.CLIENT_ERROR_FORBIDDEN); 370 */
344 return null; 371 setStatus(Status.CLIENT_ERROR_FORBIDDEN);
345 } 372 return null;
346 authUser = httpUser.getIdentifier(); 373 /*
374 * } authUser = httpUser.getIdentifier();
375 */
347 } 376 }
348 // username not required, if no username given authuser will be used 377 // username not required, if no username given authuser will be used
349 String username = null; 378 String username = null;
350 String userUri = annot.creator; 379 String userUri = annot.getCreatorUri();
351 if (jo.has("user")) { 380 if (jo.has("user")) {
352 if (jo.get("user") instanceof String) { 381 if (jo.get("user") instanceof String) {
353 // user is just a String 382 // user is just a String
354 username = jo.getString("user"); 383 username = jo.getString("user");
355 // TODO: what if username and authUser are different? 384 // TODO: what if username and authUser are different?
378 } 407 }
379 } 408 }
380 // TODO: should we overwrite the creator? 409 // TODO: should we overwrite the creator?
381 410
382 // create xpointer from the first range/area 411 // create xpointer from the first range/area
383 String xpointer = annot.xpointer;
384 if (jo.has("ranges")) { 412 if (jo.has("ranges")) {
385 JSONObject ranges = jo.getJSONArray("ranges").getJSONObject(0); 413 JSONObject ranges = jo.getJSONArray("ranges").getJSONObject(0);
386 String start = ranges.getString("start"); 414 annot.setFragmentType(FragmentTypes.XPOINTER);
387 String end = ranges.getString("end"); 415 String fragment = parseRange(ranges);
388 String startOffset = ranges.getString("startOffset"); 416 annot.setTargetFragment(fragment);
389 String endOffset = ranges.getString("endOffset");
390
391 try {
392 xpointer = url
393 + "#"
394 + URLEncoder.encode(String.format(
395 "xpointer(start-point(string-range(\"%s\",%s,1))/range-to(end-point(string-range(\"%s\",%s,1))))",
396 start, startOffset, end, endOffset), "utf-8");
397 } catch (UnsupportedEncodingException e) {
398 e.printStackTrace();
399 setStatus(Status.SERVER_ERROR_INTERNAL);
400 return null;
401 }
402 } 417 }
403 if (jo.has("areas")) { 418 if (jo.has("areas")) {
404 JSONObject area = jo.getJSONArray("areas").getJSONObject(0); 419 JSONObject area = jo.getJSONArray("areas").getJSONObject(0);
405 String x = area.getString("x"); 420 annot.setFragmentType(FragmentTypes.AREA);
406 String y = area.getString("y"); 421 String fragment = parseArea(area);
407 String width = "0"; 422 annot.setTargetFragment(fragment);
408 String height = "0"; 423 }
409 if (area.has("width")) { 424 return annot;
410 width = area.getString("width");
411 height = area.getString("height");
412 }
413 try {
414 xpointer = url + "#" + URLEncoder.encode(String.format("xywh=fraction:%s,%s,%s,%s", x, y, width, height), "utf-8");
415 } catch (UnsupportedEncodingException e) {
416 e.printStackTrace();
417 setStatus(Status.SERVER_ERROR_INTERNAL);
418 return null;
419 }
420 }
421 return new Annotation(xpointer, userUri, annot.time, text, annot.type);
422 }
423
424 /**
425 * returns the logged in User.
426 *
427 * @param entity
428 * @return
429 */
430 protected User getHttpAuthUser(Representation entity) {
431 RestServer restServer = (RestServer) getApplication();
432 if (!restServer.authenticate(getRequest(), getResponse())) {
433 // Not authenticated
434 return null;
435 }
436
437 ClientInfo ci = getRequest().getClientInfo();
438 logger.debug(ci);
439 return getRequest().getClientInfo().getUser();
440
441 } 425 }
442 426
443 } 427 }