Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 18AD6998F for ; Sun, 24 Jun 2012 21:58:02 +0000 (UTC) Received: (qmail 374 invoked by uid 500); 24 Jun 2012 21:58:02 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 347 invoked by uid 500); 24 Jun 2012 21:58:02 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-commits@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 339 invoked by uid 99); 24 Jun 2012 21:58:02 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 24 Jun 2012 21:58:02 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 24 Jun 2012 21:58:00 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 8F4852388865; Sun, 24 Jun 2012 21:57:40 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1353346 - in /jackrabbit/oak/trunk/oak-http: pom.xml src/main/java/org/apache/jackrabbit/oak/http/OakServlet.java Date: Sun, 24 Jun 2012 21:57:40 -0000 To: oak-commits@jackrabbit.apache.org From: jukka@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120624215740.8F4852388865@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: jukka Date: Sun Jun 24 21:57:39 2012 New Revision: 1353346 URL: http://svn.apache.org/viewvc?rev=1353346&view=rev Log: OAK-104: HTTP bindings for Oak Add basic JSON read support Modified: jackrabbit/oak/trunk/oak-http/pom.xml jackrabbit/oak/trunk/oak-http/src/main/java/org/apache/jackrabbit/oak/http/OakServlet.java Modified: jackrabbit/oak/trunk/oak-http/pom.xml URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-http/pom.xml?rev=1353346&r1=1353345&r2=1353346&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-http/pom.xml (original) +++ jackrabbit/oak/trunk/oak-http/pom.xml Sun Jun 24 21:57:39 2012 @@ -92,6 +92,11 @@ 2.0.0 + com.fasterxml.jackson.dataformat + jackson-dataformat-smile + 2.0.2 + + javax.servlet servlet-api 2.5 Modified: jackrabbit/oak/trunk/oak-http/src/main/java/org/apache/jackrabbit/oak/http/OakServlet.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-http/src/main/java/org/apache/jackrabbit/oak/http/OakServlet.java?rev=1353346&r1=1353345&r2=1353346&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-http/src/main/java/org/apache/jackrabbit/oak/http/OakServlet.java (original) +++ jackrabbit/oak/trunk/oak-http/src/main/java/org/apache/jackrabbit/oak/http/OakServlet.java Sun Jun 24 21:57:39 2012 @@ -16,11 +16,13 @@ */ package org.apache.jackrabbit.oak.http; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.PrintWriter; +import java.io.InputStream; import javax.jcr.GuestCredentials; import javax.jcr.NoSuchWorkspaceException; +import javax.jcr.PropertyType; import javax.security.auth.login.LoginException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -29,11 +31,22 @@ import javax.servlet.http.HttpServletRes import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.api.ContentSession; +import org.apache.jackrabbit.oak.api.CoreValue; import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.dataformat.smile.SmileFactory; + public class OakServlet extends HttpServlet { + private static final JsonFactory JSON_FACTORY = new JsonFactory(); + + private static final JsonFactory SMILE_FACTORY = new SmileFactory(); + private final ContentRepository repository; public OakServlet(ContentRepository repository) { @@ -47,17 +60,12 @@ public class OakServlet extends HttpServ try { ContentSession session = repository.login(new GuestCredentials(), null); try { - response.setContentType("text/plain"); - PrintWriter writer = response.getWriter(); - Tree tree = - session.getCurrentRoot().getTree(request.getPathInfo()); + Root root = session.getCurrentRoot(); + Tree tree = root.getTree(request.getPathInfo()); if (tree != null) { - for (PropertyState property : tree.getProperties()) { - writer.print("- " + property.getName() + "\n"); - } - for (Tree child : tree.getChildren()) { - writer.print("+ " + child.getName() + "\n"); - } + JsonGenerator generator = getRenderer(request, response); + int depth = getDepth(request); + render(tree, depth, generator); } else { response.sendError(HttpServletResponse.SC_NOT_FOUND); } @@ -71,4 +79,95 @@ public class OakServlet extends HttpServ } } + private int getDepth(HttpServletRequest request) { + String d = request.getParameter("depth"); + if (d == null) { + d = request.getParameter("d"); + } + if (d != null) { + try { + return Integer.parseInt(d); + } catch (NumberFormatException e) { + // ignore + } + } + return 1; + } + + private JsonGenerator getRenderer( + HttpServletRequest request, HttpServletResponse response) + throws IOException { + AcceptHeader accept = new AcceptHeader(request.getHeader("Accept")); + String type = accept.resolve( + "application/json", + "application/x-jackson-smile"); + if ("application/x-jackson-smile".equals(type)) { + response.setContentType("application/x-jackson-smile"); + return SMILE_FACTORY.createJsonGenerator(response.getOutputStream()); + } else { + response.setContentType("application/json"); + return JSON_FACTORY.createJsonGenerator(response.getOutputStream()); + } + } + + private void render(Tree tree, int depth, JsonGenerator generator) + throws JsonGenerationException, IOException { + generator.writeStartObject(); + if (depth > 0) { + for (PropertyState property : tree.getProperties()) { + render(property, generator); + } + for (Tree child : tree.getChildren()) { + generator.writeFieldName(child.getName()); + render(child, depth - 1, generator); + } + } + generator.writeEndObject(); + generator.close(); + } + + private void render(PropertyState property, JsonGenerator generator) + throws JsonGenerationException, IOException { + generator.writeFieldName(property.getName()); + if (property.isArray()) { + generator.writeStartArray(); + for (CoreValue value : property.getValues()) { + render(value, generator); + } + generator.writeEndArray(); + } else { + render(property.getValue(), generator); + } + } + + private void render(CoreValue value, JsonGenerator generator) + throws JsonGenerationException, IOException { + // TODO: Type info? + if (value.getType() == PropertyType.BOOLEAN) { + generator.writeBoolean(value.getBoolean()); + } else if (value.getType() == PropertyType.DECIMAL) { + generator.writeNumber(value.getDecimal()); + } else if (value.getType() == PropertyType.DOUBLE) { + generator.writeNumber(value.getDouble()); + } else if (value.getType() == PropertyType.LONG) { + generator.writeNumber(value.getLong()); + } else if (value.getType() == PropertyType.BINARY) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + InputStream stream = value.getNewStream(); + try { + byte[] b = new byte[1024]; + int n = stream.read(b); + while (n != -1) { + buffer.write(b, 0, n); + n = stream.read(b); + } + } finally { + stream.close(); + } + generator.writeBinary(buffer.toByteArray()); + } else { + generator.writeString(value.getString()); + } + } + }