package org.curriki.xwiki.servlet.restlet.resource; import org.restlet.resource.Resource; import org.restlet.resource.Representation; import org.restlet.resource.StringRepresentation; import org.restlet.resource.Variant; import org.restlet.resource.ResourceException; import org.restlet.Context; import org.restlet.data.*; import org.curriki.xwiki.plugin.curriki.CurrikiPluginApi; import org.curriki.xwiki.plugin.curriki.CurrikiPlugin; import com.xpn.xwiki.XWikiContext; import net.sf.json.xml.XMLSerializer; import net.sf.json.JSONObject; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONSerializer; import net.sf.json.JSONException; import net.sf.json.util.JSONUtils; import java.util.Map; import java.util.List; import java.io.IOException; import java.io.StringWriter; import java.io.PrintWriter; /** */ public class BaseResource extends Resource { protected XWikiContext xwikiContext; protected CurrikiPluginApi plugin; public BaseResource() { super(); } public BaseResource(Context context, Request request, Response response) { super(context, request, response); } protected XWikiContext getXWikiContext() { return (XWikiContext) getContext().getAttributes().get("XWikiContext"); } protected void setupXWiki() { xwikiContext = getXWikiContext(); plugin = (CurrikiPluginApi) xwikiContext.getWiki().getPluginApi(CurrikiPlugin.PLUGIN_NAME, xwikiContext); } public void acceptRepresentation(Representation representation) throws ResourceException { // Allow PUT to be tunnelled over POST (unless overridden by a subclass) Form f = getRequest().getResourceRef().getQueryAsForm(); if ("put".equalsIgnoreCase(f.getFirstValue("_method", "NOT-PUT"))) { storeRepresentation(representation); return; } throw new ResourceException(Status.SERVER_ERROR_INTERNAL); } protected ResourceException error(Status status, String message) { getResponse().setEntity(message, MediaType.TEXT_PLAIN); return new ResourceException(status, message); } protected ResourceException error(Status status, String message, Throwable cause) { StringWriter sw = new StringWriter(); cause.printStackTrace(new PrintWriter(sw)); String st = sw.toString(); getResponse().setEntity(message+" Stacktrace: "+st, MediaType.TEXT_PLAIN); // TODO: Remove // DEBUGGING CODE for CURRIKI-4238 System.out.println("ERROR THROWN: "+message+" Stacktrace: "+st); return new ResourceException(status, message+" Stacktrace: "+st, cause); } protected ResourceException error(Status status, Throwable cause) { StringWriter sw = new StringWriter(); cause.printStackTrace(new PrintWriter(sw)); String st = sw.toString(); getResponse().setEntity("Exception Thrown: "+cause.getMessage()+" Stacktrace: "+st, MediaType.TEXT_PLAIN); return new ResourceException(status, cause); } protected Representation formatJSON(JSON json, Variant variant) { Representation r = null; // TODO: Firefox 2 seems to not send the specified application/json header // (especially after a redirect) // so we will send application/json always for now // (as we don't support this API any other way right now) if (true /* TODO: This is a hack */) { r = new StringRepresentation(json.toString(), MediaType.APPLICATION_JSON); } else if (MediaType.APPLICATION_JSON.equals(variant.getMediaType()) || MediaType.APPLICATION_JAVASCRIPT.equals(variant.getMediaType()) || MediaType.TEXT_JAVASCRIPT.equals(variant.getMediaType())) { r = new StringRepresentation(json.toString(), variant.getMediaType()); } else if (MediaType.APPLICATION_XML.equals(variant.getMediaType()) || MediaType.TEXT_XML.equals(variant.getMediaType())) { r = new StringRepresentation(new XMLSerializer().write(json), variant.getMediaType()); } else if (MediaType.TEXT_PLAIN.equals(variant.getMediaType()) || MediaType.TEXT_HTML.equals(variant.getMediaType())) { r = new StringRepresentation(json.toString(4), variant.getMediaType()); } else { getResponse().setStatus(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE); } r.setCharacterSet(CharacterSet.UTF_8); return r; } protected void defaultVariants(){ getVariants().add(new Variant(MediaType.APPLICATION_JSON)); getVariants().add(new Variant(MediaType.APPLICATION_JAVASCRIPT)); getVariants().add(new Variant(MediaType.TEXT_JAVASCRIPT)); getVariants().add(new Variant(MediaType.APPLICATION_XML)); getVariants().add(new Variant(MediaType.TEXT_XML)); getVariants().add(new Variant(MediaType.TEXT_PLAIN)); getVariants().add(new Variant(MediaType.TEXT_HTML)); } protected JSONArray flattenMapToJSONArray(Map<String,Object> map, String itemName) { JSONArray json = new JSONArray(); for (String item : map.keySet()) { JSONObject o = new JSONObject(); o.put(itemName, item); Map<String,Object> info = (Map<String,Object>) map.get(item); for (String infoItem : info.keySet()) { o.put(infoItem, info.get(infoItem)); } json.add(o); } return json; } protected JSONArray flattenMapToJSONArray(Map<String,Object> map, List<String> items, String itemName) throws ResourceException { JSONArray json = new JSONArray(); for (String item : items) { JSONObject o = new JSONObject(); o.put(itemName, item); Map<String,Object> info = (Map<String,Object>) map.get(item); if (info != null) { for (String infoItem : info.keySet()) { o.put(infoItem, info.get(infoItem)); } } else { // Error: Item in list is not in the map throw error(Status.SERVER_ERROR_INTERNAL, "Map for "+itemName+": "+item+" cannot be found"); } json.add(o); } return json; } protected JSONObject representationToJSONObject(Representation representation) throws ResourceException { String posted; try { posted = representation.getText(); } catch (IOException e) { throw error(Status.CLIENT_ERROR_NOT_ACCEPTABLE, "IOException on input."); } if (!JSONUtils.mayBeJSON(posted)) { throw error(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "Please PUT in JSON format."); } JSONObject json; try { JSON input = JSONSerializer.toJSON(posted); if (!input.isArray()){ json = (JSONObject) input; } else { throw error(Status.CLIENT_ERROR_NOT_ACCEPTABLE, "Please send a proper JSON object."); } } catch (JSONException e){ throw error(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "JSON format required."); } return json; } protected Reference getChildReference(Reference parentRef, String childId) { if (parentRef.getIdentifier().endsWith("/")) { return new Reference(parentRef.getIdentifier() + childId); } else { return new Reference(parentRef.getIdentifier() + "/" + childId); } } }