You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2015/06/11 14:09:17 UTC
svn commit: r1684861 [4/8] - in /jackrabbit/oak/trunk: ./ oak-remote/
oak-remote/src/ oak-remote/src/main/ oak-remote/src/main/java/
oak-remote/src/main/java/org/ oak-remote/src/main/java/org/apache/
oak-remote/src/main/java/org/apache/jackrabbit/ oak-...
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/GetTreeHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/GetTreeHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/GetTreeHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/GetTreeHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+import org.apache.jackrabbit.oak.remote.RemoteTree;
+import org.apache.jackrabbit.oak.remote.RemoteTreeFilters;
+import org.apache.jackrabbit.oak.remote.RemoteValue;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import static java.util.Collections.singletonMap;
+import static org.apache.jackrabbit.oak.remote.http.handler.RemoteValues.renderJson;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendGone;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendInternalServerError;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendNotFound;
+
+abstract class GetTreeHandler implements Handler {
+
+ protected abstract String readPath(HttpServletRequest request);
+
+ protected abstract RemoteRevision readRevision(HttpServletRequest request, RemoteSession session);
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ RemoteSession session = (RemoteSession) request.getAttribute("session");
+
+ if (session == null) {
+ sendInternalServerError(response, "session not found");
+ return;
+ }
+
+ RemoteRevision revision = readRevision(request, session);
+
+ if (revision == null) {
+ sendGone(response, "unable to read the revision");
+ return;
+ }
+
+ RemoteTree tree = session.readTree(revision, readPath(request), readFilters(request));
+
+ if (tree == null) {
+ sendNotFound(response, singletonMap("Oak-Revision", revision.asString()), "tree not found");
+ return;
+ }
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setHeader("Oak-Revision", revision.asString());
+ response.setContentType("application/json");
+
+ ServletOutputStream stream = response.getOutputStream();
+
+ JsonGenerator generator = new JsonFactory().createJsonGenerator(stream, JsonEncoding.UTF8);
+ renderResponse(generator, tree);
+ generator.flush();
+
+ stream.close();
+ }
+
+ private void renderResponse(JsonGenerator generator, RemoteTree tree) throws IOException {
+ if (tree == null) {
+ generator.writeNull();
+ } else {
+ generator.writeStartObject();
+ generator.writeFieldName("properties");
+ renderProperties(generator, tree.getProperties());
+ generator.writeFieldName("children");
+ renderChildren(generator, tree.getChildren());
+ generator.writeFieldName("hasMoreChildren");
+ generator.writeBoolean(tree.hasMoreChildren());
+ generator.writeEndObject();
+ }
+ }
+
+ private void renderChildren(JsonGenerator generator, Map<String, RemoteTree> children) throws IOException {
+ generator.writeStartObject();
+
+ for (Map.Entry<String, RemoteTree> entry : children.entrySet()) {
+ generator.writeFieldName(entry.getKey());
+ renderResponse(generator, entry.getValue());
+ }
+
+ generator.writeEndObject();
+ }
+
+ private void renderProperties(JsonGenerator generator, Map<String, RemoteValue> properties) throws IOException {
+ generator.writeStartObject();
+
+ for (Map.Entry<String, RemoteValue> entry : properties.entrySet()) {
+ generator.writeFieldName(entry.getKey());
+ renderJson(generator, entry.getValue());
+ }
+
+ generator.writeEndObject();
+ }
+
+ private RemoteTreeFilters readFilters(final HttpServletRequest request) {
+ return new RemoteTreeFilters() {
+
+ @Override
+ public int getDepth() {
+ Integer depth = readDepth(request);
+
+ if (depth == null) {
+ return super.getDepth();
+ }
+
+ return depth;
+ }
+
+ @Override
+ public Set<String> getPropertyFilters() {
+ Set<String> propertyFilters = readPropertyFilters(request);
+
+ if (propertyFilters == null) {
+ return super.getPropertyFilters();
+ }
+
+ return propertyFilters;
+ }
+
+ @Override
+ public Set<String> getNodeFilters() {
+ Set<String> nodeFilters = readNodeFilters(request);
+
+ if (nodeFilters == null) {
+ return super.getNodeFilters();
+ }
+
+ return nodeFilters;
+ }
+
+ @Override
+ public long getBinaryThreshold() {
+ Long binaryThreshold = readBinaryThreshold(request);
+
+ if (binaryThreshold == null) {
+ return super.getBinaryThreshold();
+ }
+
+ return binaryThreshold;
+ }
+
+ @Override
+ public int getChildrenStart() {
+ Integer childrenStart = readChildrenStart(request);
+
+ if (childrenStart == null) {
+ return super.getChildrenStart();
+ }
+
+ return childrenStart;
+ }
+
+ @Override
+ public int getChildrenCount() {
+ Integer childrenCount = readChildrenCount(request);
+
+ if (childrenCount == null) {
+ return super.getChildrenCount();
+ }
+
+ return childrenCount;
+ }
+
+ };
+ }
+
+ private Integer readDepth(HttpServletRequest request) {
+ return readIntegerParameter(request, "depth");
+ }
+
+ private Set<String> readPropertyFilters(HttpServletRequest request) {
+ return readSetParameter(request, "properties");
+ }
+
+ private Set<String> readNodeFilters(HttpServletRequest request) {
+ return readSetParameter(request, "children");
+ }
+
+ private Long readBinaryThreshold(HttpServletRequest request) {
+ return readLongParameter(request, "binaries");
+ }
+
+ private Integer readChildrenStart(HttpServletRequest request) {
+ return readIntegerParameter(request, "childrenStart");
+ }
+
+ private Integer readChildrenCount(HttpServletRequest request) {
+ return readIntegerParameter(request, "childrenCount");
+ }
+
+ private Integer readIntegerParameter(HttpServletRequest request, String name) {
+ String value = request.getParameter(name);
+
+ if (value == null) {
+ return null;
+ }
+
+ Integer result;
+
+ try {
+ result = Integer.parseInt(value, 10);
+ } catch (NumberFormatException e) {
+ result = null;
+ }
+
+ return result;
+ }
+
+ private Long readLongParameter(HttpServletRequest request, String name) {
+ String value = request.getParameter(name);
+
+ if (value == null) {
+ return null;
+ }
+
+ Long result;
+
+ try {
+ result = Long.parseLong(value, 10);
+ } catch (NumberFormatException e) {
+ result = null;
+ }
+
+ return result;
+ }
+
+ private Set<String> readSetParameter(HttpServletRequest request, String name) {
+ String[] values = request.getParameterValues(name);
+
+ if (values == null) {
+ return null;
+ }
+
+ return Sets.newHashSet(values);
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public interface Handler {
+
+ void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handlers.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handlers.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handlers.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/Handlers.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+/**
+ * A collection of handlers used to respond to some requests handled by the
+ * remote servlet.
+ */
+public class Handlers {
+
+ private Handlers() {
+ }
+
+ /**
+ * Create an handler that will return the last revision available to the
+ * server.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createGetLastRevisionHandler() {
+ return withAuthentication(new GetLastRevisionHandler());
+ }
+
+ /**
+ * Create an handler that will return a repository sub-tree at a specific
+ * revision.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createGetRevisionTreeHandler() {
+ return withAuthentication(new GetRevisionTreeHandler());
+ }
+
+ /**
+ * Create an handler that will return a repository sub-tree at the latest
+ * known state.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createGetLastTreeHandler() {
+ return withAuthentication(new GetLastTreeHandler());
+ }
+
+ /**
+ * Create an handler that will return a 404 response to the client.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createNotFoundHandler() {
+ return new NotFoundHandler();
+ }
+
+ /**
+ * Create a handler that will read a binary object from the repository.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createGetBinaryHandler() {
+ return withAuthentication(new GetBinaryHandler());
+ }
+
+ /**
+ * Create a handler that will check if a binary exists
+ *
+ * @return An instance of {@code Handler}
+ */
+ public static Handler createHeadBinaryHandler() {
+ return withAuthentication(new HeadBinaryHandler());
+ }
+
+ /**
+ * Create a handler that will perform the creation of new binary object.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createPostBinaryHandler() {
+ return withAuthentication(new PostBinaryHandler());
+ }
+
+ /**
+ * Create a handler that will patch the content at a specific revision.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createPatchSpecificRevisionHandler() {
+ return withAuthentication(new PatchSpecificRevisionHandler());
+ }
+
+ /**
+ * Create a handler that will patch the content at the last revision.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createPatchLastRevisionHandler() {
+ return withAuthentication(new PatchLastRevisionHandler());
+ }
+
+ /**
+ * Create a handler that checks if a tree exists at the last revision.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createHeadLastTreeHandler() {
+ return withAuthentication(new HeadLastTreeHandler());
+ }
+
+ /**
+ * Create a handler that checks if a tree exists at a given revision.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createHeadRevisionTreeHandler() {
+ return withAuthentication(new HeadRevisionTreeHandler());
+ }
+
+ /**
+ * Create a handler that searches for content at the last revision.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createSearchLastRevisionHandler() {
+ return withAuthentication(new SearchLastRevisionHandler());
+ }
+
+ /**
+ * Create a handler that searches for content at the provided revision.
+ *
+ * @return An instance of {@code Handler}.
+ */
+ public static Handler createSearchSpecificRevisionHandler() {
+ return withAuthentication(new SearchSpecificRevisionHandler());
+ }
+
+ private static Handler withAuthentication(Handler authenticated) {
+ return new AuthenticationWrapperHandler(authenticated, createForbiddenHandler());
+ }
+
+ private static Handler createForbiddenHandler() {
+ return new UnauthorizedHandler();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadBinaryHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadBinaryHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadBinaryHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadBinaryHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteBinaryId;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendBadRequest;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendInternalServerError;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendNotFound;
+
+class HeadBinaryHandler implements Handler {
+
+ private static final Pattern REQUEST_PATTERN = Pattern.compile("^/binaries/(.*)$");
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+ RemoteSession session = (RemoteSession) request.getAttribute("session");
+
+ if (session == null) {
+ sendInternalServerError(response, "session not found");
+ return;
+ }
+
+ String providedBinaryId = readBinaryId(request);
+
+ if (providedBinaryId == null) {
+ sendBadRequest(response, "unable to read the provided binary ID");
+ return;
+ }
+
+ RemoteBinaryId binaryId = session.readBinaryId(providedBinaryId);
+
+ if (binaryId == null) {
+ sendNotFound(response, "binary ID not found");
+ return;
+ }
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setHeader("Accept-Ranges", "bytes");
+ }
+
+ /**
+ * Extract binary id from request path and return it
+ */
+ private String readBinaryId(HttpServletRequest request) {
+ Matcher matcher = REQUEST_PATTERN.matcher(request.getPathInfo());
+
+ if (matcher.matches()) {
+ return matcher.group(1);
+ }
+
+ throw new IllegalStateException("handler bound at the wrong path");
+ }
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadLastTreeHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadLastTreeHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadLastTreeHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadLastTreeHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class HeadLastTreeHandler extends HeadTreeHandler {
+
+ private static final Pattern REQUEST_PATTERN = Pattern.compile("^/revisions/last/tree(/.*)$");
+
+ protected String readPath(HttpServletRequest request) {
+ Matcher matcher = REQUEST_PATTERN.matcher(request.getPathInfo());
+
+ if (matcher.matches()) {
+ return matcher.group(1);
+ }
+
+ throw new IllegalStateException("handler bound at the wrong path");
+ }
+
+ @Override
+ protected RemoteRevision readRevision(HttpServletRequest request, RemoteSession session) {
+ return session.readLastRevision();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadRevisionTreeHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadRevisionTreeHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadRevisionTreeHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadRevisionTreeHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class HeadRevisionTreeHandler extends HeadTreeHandler {
+
+ private static final Pattern REQUEST_PATTERN = Pattern.compile("^/revisions/([^/]+)/tree(/.*)$");
+
+ @Override
+ protected String readPath(HttpServletRequest request) {
+ Matcher matcher = REQUEST_PATTERN.matcher(request.getPathInfo());
+
+ if (matcher.matches()) {
+ return matcher.group(2);
+ }
+
+ throw new IllegalStateException("handler bound at the wrong path");
+ }
+
+ @Override
+ protected RemoteRevision readRevision(HttpServletRequest request, RemoteSession session) {
+ Matcher matcher = REQUEST_PATTERN.matcher(request.getPathInfo());
+
+ if (matcher.matches()) {
+ return session.readRevision(matcher.group(1));
+ }
+
+ throw new IllegalStateException("handler bound at the wrong path");
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadTreeHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadTreeHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadTreeHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/HeadTreeHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+import org.apache.jackrabbit.oak.remote.RemoteTree;
+import org.apache.jackrabbit.oak.remote.RemoteTreeFilters;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static java.util.Collections.singletonMap;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendGone;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendInternalServerError;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendNotFound;
+
+abstract class HeadTreeHandler implements Handler {
+
+ protected abstract String readPath(HttpServletRequest request);
+
+ protected abstract RemoteRevision readRevision(HttpServletRequest request, RemoteSession session);
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ RemoteSession session = (RemoteSession) request.getAttribute("session");
+
+ if (session == null) {
+ sendInternalServerError(response, "session not found");
+ return;
+ }
+
+ RemoteRevision revision = readRevision(request, session);
+
+ if (revision == null) {
+ sendGone(response, "revision not found");
+ return;
+ }
+
+ RemoteTree tree = session.readTree(revision, readPath(request), new RemoteTreeFilters());
+
+ if (tree == null) {
+ sendNotFound(response, singletonMap("Oak-Revision", revision.asString()), "tree not found");
+ return;
+ }
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setHeader("Oak-Revision", revision.asString());
+ response.setContentType("application/json");
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/NotFoundHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/NotFoundHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/NotFoundHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/NotFoundHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendNotFound;
+
+class NotFoundHandler implements Handler {
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ sendNotFound(response, "requested path not found");
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchLastRevisionHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchLastRevisionHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchLastRevisionHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchLastRevisionHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.http.HttpServletRequest;
+
+class PatchLastRevisionHandler extends PatchRevisionHandler {
+
+ @Override
+ protected RemoteRevision readRevision(HttpServletRequest request, RemoteSession session) {
+ return session.readLastRevision();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchRevisionHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchRevisionHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchRevisionHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchRevisionHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.jackrabbit.oak.remote.RemoteCommitException;
+import org.apache.jackrabbit.oak.remote.RemoteOperation;
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+import org.apache.jackrabbit.oak.remote.RemoteValue;
+import org.apache.jackrabbit.oak.remote.RemoteValue.Supplier;
+import org.apache.jackrabbit.util.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendBadRequest;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendGone;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendInternalServerError;
+
+abstract class PatchRevisionHandler implements Handler {
+
+ private static final Logger logger = LoggerFactory.getLogger(PatchRevisionHandler.class);
+
+ protected abstract RemoteRevision readRevision(HttpServletRequest request, RemoteSession session);
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ RemoteSession session = (RemoteSession) request.getAttribute("session");
+
+ if (session == null) {
+ sendInternalServerError(response, "session not found");
+ return;
+ }
+
+ RemoteRevision base = readRevision(request, session);
+
+ if (base == null) {
+ sendGone(response, "revision not found");
+ return;
+ }
+
+ RemoteOperation operation;
+
+ try {
+ operation = parseOperations(session, new ObjectMapper().readTree(request.getInputStream()));
+ } catch (Exception e) {
+ operation = null;
+ }
+
+ if (operation == null) {
+ sendBadRequest(response, "unable to parse the list of operations");
+ return;
+ }
+
+ RemoteRevision revision;
+
+ try {
+ revision = session.commit(base, operation);
+ } catch (RemoteCommitException e) {
+ logger.warn("unable to perform the commit", e);
+ sendBadRequest(response, "commit failed");
+ return;
+ }
+
+ response.setStatus(HttpServletResponse.SC_CREATED);
+ response.setContentType("application/json");
+
+ ServletOutputStream stream = response.getOutputStream();
+
+ JsonGenerator generator = new JsonFactory().createJsonGenerator(stream, JsonEncoding.UTF8);
+ renderResponse(generator, revision);
+ generator.flush();
+
+ stream.close();
+ }
+
+ private void renderResponse(JsonGenerator generator, RemoteRevision revision) throws IOException {
+ generator.writeStartObject();
+ generator.writeStringField("revision", revision.asString());
+ generator.writeEndObject();
+ }
+
+ private RemoteOperation parseOperations(RemoteSession session, JsonNode json) {
+ List<RemoteOperation> operations = new ArrayList<RemoteOperation>();
+
+ for (JsonNode child : json) {
+ operations.add(parseOperation(session, child));
+ }
+
+ return session.createAggregateOperation(operations);
+ }
+
+ private RemoteOperation parseOperation(RemoteSession session, JsonNode json) {
+ String type = parseStringField(json, "op");
+
+ if (type.equals("add")) {
+ return parseAddOperation(session, json);
+ }
+
+ if (type.equals("remove")) {
+ return parseRemoveOperation(session, json);
+ }
+
+ if (type.equals("set")) {
+ return parseSetOperation(session, json);
+ }
+
+ if (type.equals("unset")) {
+ return parseUnsetOperation(session, json);
+ }
+
+ if (type.equals("copy")) {
+ return parseCopyOperation(session, json);
+ }
+
+ if (type.equals("move")) {
+ return parseMoveOperation(session, json);
+ }
+
+ throw new IllegalArgumentException("invalid operation type");
+ }
+
+ private RemoteOperation parseMoveOperation(RemoteSession session, JsonNode node) {
+ return session.createMoveOperation(parseStringField(node, "from"), parseStringField(node, "to"));
+ }
+
+ private RemoteOperation parseCopyOperation(RemoteSession session, JsonNode node) {
+ return session.createCopyOperation(parseStringField(node, "from"), parseStringField(node, "to"));
+ }
+
+ private RemoteOperation parseUnsetOperation(RemoteSession session, JsonNode node) {
+ return session.createUnsetOperation(parseStringField(node, "path"), parseStringField(node, "name"));
+ }
+
+ private RemoteOperation parseSetOperation(RemoteSession session, JsonNode node) {
+ return session.createSetOperation(parseStringField(node, "path"), parseStringField(node, "name"), parseValue(node));
+ }
+
+ private RemoteOperation parseRemoveOperation(RemoteSession session, JsonNode node) {
+ return session.createRemoveOperation(parseStringField(node, "path"));
+ }
+
+ private RemoteOperation parseAddOperation(RemoteSession session, JsonNode json) {
+ return session.createAddOperation(parseStringField(json, "path"), parsePropertiesField(json, "properties"));
+ }
+
+ private Map<String, RemoteValue> parsePropertiesField(JsonNode node, String name) {
+ return parseProperties(node.get(name));
+ }
+
+ private Map<String, RemoteValue> parseProperties(JsonNode node) {
+ Map<String, RemoteValue> values = new HashMap<String, RemoteValue>();
+
+ Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
+
+ while (iterator.hasNext()) {
+ Map.Entry<String, JsonNode> entry = iterator.next();
+ values.put(entry.getKey(), parseValue(entry.getValue()));
+ }
+
+ return values;
+ }
+
+ private RemoteValue parseValue(JsonNode node) {
+ String type = parseStringField(node, "type");
+
+ if (type.equals("string")) {
+ return RemoteValue.toText(parseStringField(node, "value"));
+ }
+
+ if (type.equals("strings")) {
+ return RemoteValue.toMultiText(parseStringArrayField(node, "value"));
+ }
+
+ if (type.equals("binary")) {
+ return RemoteValue.toBinary(parseBinaryField(node, "value"));
+ }
+
+ if (type.equals("binaries")) {
+ return RemoteValue.toMultiBinary(parseBinaryArrayField(node, "value"));
+ }
+
+ if (type.equals("binaryId")) {
+ return RemoteValue.toBinaryId(parseStringField(node, "value"));
+ }
+
+ if (type.equals("binaryIds")) {
+ return RemoteValue.toMultiBinaryId(parseStringArrayField(node, "value"));
+ }
+
+ if (type.equals("long")) {
+ return RemoteValue.toLong(parseLongField(node, "value"));
+ }
+
+ if (type.equals("longs")) {
+ return RemoteValue.toMultiLong(parseLongArrayField(node, "value"));
+ }
+
+ if (type.equals("double")) {
+ return RemoteValue.toDouble(parseDoubleField(node, "value"));
+ }
+
+ if (type.equals("doubles")) {
+ return RemoteValue.toMultiDouble(parseDoubleArrayField(node, "value"));
+ }
+
+ if (type.equals("date")) {
+ return RemoteValue.toDate(parseLongField(node, "value"));
+ }
+
+ if (type.equals("dates")) {
+ return RemoteValue.toMultiDate(parseLongArrayField(node, "value"));
+ }
+
+ if (type.equals("boolean")) {
+ return RemoteValue.toBoolean(parseBooleanField(node, "value"));
+ }
+
+ if (type.equals("booleans")) {
+ return RemoteValue.toMultiBoolean(parseBooleanArrayField(node, "value"));
+ }
+
+ if (type.equals("name")) {
+ return RemoteValue.toName(parseStringField(node, "value"));
+ }
+
+ if (type.equals("names")) {
+ return RemoteValue.toMultiName(parseStringArrayField(node, "value"));
+ }
+
+ if (type.equals("path")) {
+ return RemoteValue.toPath(parseStringField(node, "value"));
+ }
+
+ if (type.equals("paths")) {
+ return RemoteValue.toMultiPath(parseStringArrayField(node, "value"));
+ }
+
+ if (type.equals("reference")) {
+ return RemoteValue.toReference(parseStringField(node, "value"));
+ }
+
+ if (type.equals("references")) {
+ return RemoteValue.toMultiReference(parseStringArrayField(node, "value"));
+ }
+
+ if (type.equals("weakReference")) {
+ return RemoteValue.toWeakReference(parseStringField(node, "value"));
+ }
+
+ if (type.equals("weakReferences")) {
+ return RemoteValue.toMultiWeakReference(parseStringArrayField(node, "value"));
+ }
+
+ if (type.equals("uri")) {
+ return RemoteValue.toUri(parseStringField(node, "value"));
+ }
+
+ if (type.equals("uris")) {
+ return RemoteValue.toMultiUri(parseStringArrayField(node, "value"));
+ }
+
+ if (type.equals("decimal")) {
+ return RemoteValue.toDecimal(parseDecimalField(node, "value"));
+ }
+
+ if (type.equals("decimals")) {
+ return RemoteValue.toMultiDecimal(parseDecimalArrayField(node, "value"));
+ }
+
+ throw new IllegalArgumentException("invalid value type");
+ }
+
+ private BigDecimal parseDecimalField(JsonNode node, String field) {
+ return parseDecimal(node.get(field));
+ }
+
+ private BigDecimal parseDecimal(JsonNode node) {
+ return new BigDecimal(node.asText());
+ }
+
+ private Iterable<BigDecimal> parseDecimalArrayField(JsonNode node, String field) {
+ return parseDecimalArray(node.get(field));
+ }
+
+ private Iterable<BigDecimal> parseDecimalArray(JsonNode node) {
+ List<BigDecimal> result = new ArrayList<BigDecimal>();
+
+ for (JsonNode element : node) {
+ result.add(parseDecimal(element));
+ }
+
+ return result;
+ }
+
+ private boolean parseBooleanField(JsonNode node, String field) {
+ return parseBoolean(node.get(field));
+ }
+
+ private boolean parseBoolean(JsonNode node) {
+ return node.asBoolean();
+ }
+
+ private Iterable<Boolean> parseBooleanArrayField(JsonNode node, String field) {
+ return parseBooleanArray(node.get(field));
+ }
+
+ private Iterable<Boolean> parseBooleanArray(JsonNode node) {
+ List<Boolean> result = new ArrayList<Boolean>();
+
+ for (JsonNode element : node) {
+ result.add(parseBoolean(element));
+ }
+
+ return result;
+ }
+
+ private double parseDoubleField(JsonNode node, String field) {
+ return parseDouble(node.get(field));
+ }
+
+ private double parseDouble(JsonNode node) {
+ return node.asDouble();
+ }
+
+ private Iterable<Double> parseDoubleArrayField(JsonNode node, String field) {
+ return parseDoubleArray(node.get(field));
+ }
+
+ private Iterable<Double> parseDoubleArray(JsonNode node) {
+ List<Double> result = new ArrayList<Double>();
+
+ for (JsonNode element : node) {
+ result.add(parseDouble(element));
+ }
+
+ return result;
+ }
+
+ private long parseLongField(JsonNode node, String field) {
+ return parseLong(node.get(field));
+ }
+
+ private long parseLong(JsonNode node) {
+ return node.asLong();
+ }
+
+ private Iterable<Long> parseLongArrayField(JsonNode node, String field) {
+ return parseLongArray(node.get(field));
+ }
+
+ private Iterable<Long> parseLongArray(JsonNode node) {
+ List<Long> result = new ArrayList<Long>();
+
+ for (JsonNode element : node) {
+ result.add(parseLong(element));
+ }
+
+ return result;
+ }
+
+ private Supplier<InputStream> parseBinaryField(JsonNode node, String field) {
+ return parseBinary(node.get(field));
+ }
+
+ private Supplier<InputStream> parseBinary(final JsonNode node) {
+ return new Supplier<InputStream>() {
+
+ @Override
+ public InputStream get() {
+ return new ByteArrayInputStream(Base64.decode(node.asText()).getBytes());
+ }
+
+ };
+ }
+
+ private Iterable<Supplier<InputStream>> parseBinaryArrayField(JsonNode node, String field) {
+ return parseBinaryArray(node.get(field));
+ }
+
+ private Iterable<Supplier<InputStream>> parseBinaryArray(JsonNode node) {
+ List<Supplier<InputStream>> result = new ArrayList<Supplier<InputStream>>();
+
+ for (JsonNode element : node) {
+ result.add(parseBinary(element));
+ }
+
+ return result;
+ }
+
+ private Iterable<String> parseStringArrayField(JsonNode node, String field) {
+ return parseStringArray(node.get(field));
+ }
+
+ private String parseStringField(JsonNode node, String field) {
+ return parseString(node.get(field));
+ }
+
+ private Iterable<String> parseStringArray(JsonNode node) {
+ List<String> result = new ArrayList<String>();
+
+ for (JsonNode element : node) {
+ result.add(parseString(element));
+ }
+
+ return result;
+ }
+
+ private String parseString(JsonNode node) {
+ return node.asText();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchSpecificRevisionHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchSpecificRevisionHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchSpecificRevisionHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PatchSpecificRevisionHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class PatchSpecificRevisionHandler extends PatchRevisionHandler {
+
+ private static final Pattern REQUEST_PATTERN = Pattern.compile("^/revisions/([^/]+)/tree$");
+
+ @Override
+ protected RemoteRevision readRevision(HttpServletRequest request, RemoteSession session) {
+ Matcher matcher = REQUEST_PATTERN.matcher(request.getPathInfo());
+
+ if (matcher.matches()) {
+ return session.readRevision(matcher.group(1));
+ }
+
+ throw new IllegalStateException("handler bound at the wrong path");
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PostBinaryHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PostBinaryHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PostBinaryHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/PostBinaryHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import org.apache.jackrabbit.oak.remote.RemoteBinaryId;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendInternalServerError;
+
+class PostBinaryHandler implements Handler {
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ RemoteSession session = (RemoteSession) request.getAttribute("session");
+
+ if (session == null) {
+ sendInternalServerError(response, "session not found");
+ return;
+ }
+
+ RemoteBinaryId binaryId = session.writeBinary(request.getInputStream());
+
+ response.setStatus(HttpServletResponse.SC_CREATED);
+ response.setContentType("application/json");
+
+ ServletOutputStream stream = response.getOutputStream();
+
+ JsonGenerator generator = new JsonFactory().createJsonGenerator(stream, JsonEncoding.UTF8);
+ generator.writeStartObject();
+ generator.writeStringField("binaryId", binaryId.asString());
+ generator.writeEndObject();
+ generator.flush();
+
+ stream.close();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/RemoteValues.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/RemoteValues.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/RemoteValues.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/RemoteValues.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.google.common.io.BaseEncoding;
+import com.google.common.io.ByteStreams;
+import org.apache.jackrabbit.oak.remote.RemoteValue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+
+class RemoteValues {
+
+ private RemoteValues() {
+ // Prevent instantiation
+ }
+
+ public static void renderJsonOrNull(JsonGenerator generator, RemoteValue value) throws IOException {
+ if (value == null) {
+ generator.writeNull();
+ } else {
+ renderJson(generator, value);
+ }
+ }
+
+ public static void renderJson(JsonGenerator generator, RemoteValue value) throws IOException {
+ if (value.isBinary()) {
+ renderValue(generator, "binary", value.asBinary(), getBinaryWriter());
+ }
+
+ if (value.isMultiBinary()) {
+ renderMultiValue(generator, "binaries", value.asMultiBinary(), getBinaryWriter());
+ }
+
+ if (value.isBinaryId()) {
+ renderValue(generator, "binaryId", value.asBinaryId(), getStringWriter());
+ }
+
+ if (value.isMultiBinaryId()) {
+ renderMultiValue(generator, "binaryIds", value.asMultiBinaryId(), getStringWriter());
+ }
+
+ if (value.isBoolean()) {
+ renderValue(generator, "boolean", value.asBoolean(), getBooleanWriter());
+ }
+
+ if (value.isMultiBoolean()) {
+ renderMultiValue(generator, "booleans", value.asMultiBoolean(), getBooleanWriter());
+ }
+
+ if (value.isDate()) {
+ renderValue(generator, "date", value.asDate(), getLongWriter());
+ }
+
+ if (value.isMultiDate()) {
+ renderMultiValue(generator, "dates", value.asMultiDate(), getLongWriter());
+ }
+
+ if (value.isDecimal()) {
+ renderValue(generator, "decimal", value.asDecimal(), getDecimalWriter());
+ }
+
+ if (value.isMultiDecimal()) {
+ renderMultiValue(generator, "decimals", value.asMultiDecimal(), getDecimalWriter());
+ }
+
+ if (value.isDouble()) {
+ renderValue(generator, "double", value.asDouble(), getDoubleWriter());
+ }
+
+ if (value.isMultiDouble()) {
+ renderMultiValue(generator, "doubles", value.asMultiDouble(), getDoubleWriter());
+ }
+
+ if (value.isLong()) {
+ renderValue(generator, "long", value.asLong(), getLongWriter());
+ }
+
+ if (value.isMultiLong()) {
+ renderMultiValue(generator, "longs", value.asMultiLong(), getLongWriter());
+ }
+
+ if (value.isName()) {
+ renderValue(generator, "name", value.asName(), getStringWriter());
+ }
+
+ if (value.isMultiName()) {
+ renderMultiValue(generator, "names", value.asMultiName(), getStringWriter());
+ }
+
+ if (value.isPath()) {
+ renderValue(generator, "path", value.asPath(), getStringWriter());
+ }
+
+ if (value.isMultiPath()) {
+ renderMultiValue(generator, "paths", value.asMultiPath(), getStringWriter());
+ }
+
+ if (value.isReference()) {
+ renderValue(generator, "reference", value.asReference(), getStringWriter());
+ }
+
+ if (value.isMultiReference()) {
+ renderMultiValue(generator, "references", value.asMultiReference(), getStringWriter());
+ }
+
+ if (value.isText()) {
+ renderValue(generator, "string", value.asText(), getStringWriter());
+ }
+
+ if (value.isMultiText()) {
+ renderMultiValue(generator, "strings", value.asMultiText(), getStringWriter());
+ }
+
+ if (value.isUri()) {
+ renderValue(generator, "uri", value.asUri(), getStringWriter());
+ }
+
+ if (value.isMultiUri()) {
+ renderMultiValue(generator, "uris", value.asMultiUri(), getStringWriter());
+ }
+
+ if (value.isWeakReference()) {
+ renderValue(generator, "weakReference", value.asWeakReference(), getStringWriter());
+ }
+
+ if (value.isMultiWeakReference()) {
+ renderMultiValue(generator, "weakReferences", value.asMultiWeakReference(), getStringWriter());
+ }
+ }
+
+ private static GeneratorWriter<RemoteValue.Supplier<InputStream>> getBinaryWriter() {
+ return new GeneratorWriter<RemoteValue.Supplier<InputStream>>() {
+
+ @Override
+ public void write(JsonGenerator generator, RemoteValue.Supplier<InputStream> value) throws IOException {
+ generator.writeString(BaseEncoding.base64().encode(ByteStreams.toByteArray(value.get())));
+ }
+
+ };
+ }
+
+ private static GeneratorWriter<String> getStringWriter() {
+ return new GeneratorWriter<String>() {
+
+ @Override
+ public void write(JsonGenerator generator, String value) throws IOException {
+ generator.writeString(value);
+ }
+
+ };
+ }
+
+ private static GeneratorWriter<Boolean> getBooleanWriter() {
+ return new GeneratorWriter<Boolean>() {
+
+ @Override
+ public void write(JsonGenerator generator, Boolean value) throws IOException {
+ generator.writeBoolean(value);
+ }
+
+ };
+ }
+
+ private static GeneratorWriter<Long> getLongWriter() {
+ return new GeneratorWriter<Long>() {
+
+ @Override
+ public void write(JsonGenerator generator, Long value) throws IOException {
+ generator.writeNumber(value);
+ }
+
+ };
+ }
+
+ private static GeneratorWriter<BigDecimal> getDecimalWriter() {
+ return new GeneratorWriter<BigDecimal>() {
+
+ @Override
+ public void write(JsonGenerator generator, BigDecimal value) throws IOException {
+ generator.writeString(value.toString());
+ }
+
+ };
+ }
+
+ private static GeneratorWriter<Double> getDoubleWriter() {
+ return new GeneratorWriter<Double>() {
+
+ @Override
+ public void write(JsonGenerator generator, Double value) throws IOException {
+ generator.writeNumber(value);
+ }
+
+ };
+ }
+
+ private static <T> void renderValue(JsonGenerator generator, String type, T value, GeneratorWriter<T> writer) throws IOException {
+ generator.writeStartObject();
+ generator.writeStringField("type", type);
+ generator.writeFieldName("value");
+
+ writer.write(generator, value);
+
+ generator.writeEndObject();
+ }
+
+ private static <T> void renderMultiValue(JsonGenerator generator, String type, Iterable<T> values, GeneratorWriter<T> writer) throws IOException {
+ generator.writeStartObject();
+ generator.writeStringField("type", type);
+ generator.writeArrayFieldStart("value");
+
+ for (T value : values) {
+ writer.write(generator, value);
+ }
+
+ generator.writeEndArray();
+ generator.writeEndObject();
+ }
+
+
+ private interface GeneratorWriter<T> {
+
+ void write(JsonGenerator generator, T value) throws IOException;
+
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/ResponseUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/ResponseUtils.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/ResponseUtils.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/ResponseUtils.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+class ResponseUtils {
+
+ private ResponseUtils() {
+ }
+
+ private static void send(HttpServletResponse response, int code, String message) throws IOException {
+ send(response, code, new HashMap<String, String>(), message);
+ }
+
+ private static void send(HttpServletResponse response, int code, Map<String, String> headers, String message) throws IOException {
+ response.setStatus(code);
+ response.setContentType("application/json");
+
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ response.setHeader(entry.getKey(), entry.getValue());
+ }
+
+ ServletOutputStream stream = response.getOutputStream();
+
+ JsonGenerator generator = new JsonFactory().createJsonGenerator(stream, JsonEncoding.UTF8);
+ generator.writeStartObject();
+ generator.writeStringField("error", message);
+ generator.writeEndObject();
+ generator.flush();
+
+ stream.close();
+ }
+
+ public static void sendBadRequest(HttpServletResponse response, String message) throws IOException {
+ send(response, HttpServletResponse.SC_BAD_REQUEST, message);
+ }
+
+ public static void sendInternalServerError(HttpServletResponse response, String message) throws IOException {
+ send(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+ }
+
+ public static void sendGone(HttpServletResponse response, String message) throws IOException {
+ send(response, HttpServletResponse.SC_GONE, message);
+ }
+
+ public static void sendNotFound(HttpServletResponse response, String message) throws IOException {
+ send(response, HttpServletResponse.SC_NOT_FOUND, message);
+ }
+
+ public static void sendNotFound(HttpServletResponse response, Map<String, String> headers, String message) throws IOException {
+ send(response, HttpServletResponse.SC_NOT_FOUND, headers, message);
+ }
+
+ public static void sendUnauthorized(HttpServletResponse response, String message) throws IOException {
+ send(response, HttpServletResponse.SC_UNAUTHORIZED, message);
+ }
+
+ public static void sendUnauthorized(HttpServletResponse response, Map<String, String> headers, String message) throws IOException {
+ send(response, HttpServletResponse.SC_UNAUTHORIZED, headers, message);
+ }
+
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchLastRevisionHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchLastRevisionHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchLastRevisionHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchLastRevisionHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.http.HttpServletRequest;
+
+class SearchLastRevisionHandler extends SearchRevisionHandler {
+
+ @Override
+ protected RemoteRevision readRevision(HttpServletRequest request, RemoteSession session) {
+ return session.readLastRevision();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchRevisionHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchRevisionHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchRevisionHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchRevisionHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import org.apache.jackrabbit.oak.remote.RemoteQueryParseException;
+import org.apache.jackrabbit.oak.remote.RemoteResult;
+import org.apache.jackrabbit.oak.remote.RemoteResults;
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static org.apache.jackrabbit.oak.remote.http.handler.RemoteValues.renderJson;
+import static org.apache.jackrabbit.oak.remote.http.handler.RemoteValues.renderJsonOrNull;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendBadRequest;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendGone;
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendInternalServerError;
+
+abstract class SearchRevisionHandler implements Handler {
+
+ protected abstract RemoteRevision readRevision(HttpServletRequest request, RemoteSession session);
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ RemoteSession session = (RemoteSession) request.getAttribute("session");
+
+ if (session == null) {
+ sendInternalServerError(response, "session not found");
+ return;
+ }
+
+ RemoteRevision revision = readRevision(request, session);
+
+ if (revision == null) {
+ sendGone(response, "unable to read the revision");
+ return;
+ }
+
+ String query = readQuery(request);
+
+ if (query == null) {
+ sendBadRequest(response, "query not specified");
+ return;
+ }
+
+ String language = readLanguage(request);
+
+ if (language == null) {
+ sendBadRequest(response, "language not specified");
+ return;
+ }
+
+ Long offset = readOffset(request);
+
+ if (offset == null) {
+ sendBadRequest(response, "offset not specified");
+ return;
+ }
+
+ Long limit = readLimit(request);
+
+ if (limit == null) {
+ sendBadRequest(response, "limit not specified");
+ return;
+ }
+
+ RemoteResults results;
+
+ try {
+ results = session.search(revision, query, language, offset, limit);
+ } catch (RemoteQueryParseException e) {
+ sendBadRequest(response, "malformed query");
+ return;
+ }
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setHeader("Oak-Revision", revision.asString());
+ response.setContentType("application/json");
+
+ ServletOutputStream stream = response.getOutputStream();
+
+ JsonGenerator generator = new JsonFactory().createJsonGenerator(stream, JsonEncoding.UTF8);
+ renderResponse(generator, results);
+ generator.flush();
+
+ stream.close();
+ }
+
+ private String readQuery(HttpServletRequest request) {
+ return readStringParameter(request, "query");
+ }
+
+ private String readLanguage(HttpServletRequest request) {
+ return readStringParameter(request, "language");
+ }
+
+ private String readStringParameter(HttpServletRequest request, String name) {
+ return request.getParameter(name);
+ }
+
+ private Long readOffset(HttpServletRequest request) {
+ return readLongParameter(request, "offset");
+ }
+
+ private Long readLimit(HttpServletRequest request) {
+ return readLongParameter(request, "limit");
+ }
+
+ private Long readLongParameter(HttpServletRequest request, String name) {
+ String value = readStringParameter(request, name);
+
+ if (value == null) {
+ return null;
+ }
+
+ try {
+ return Long.parseLong(value, 10);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ private void renderResponse(JsonGenerator generator, RemoteResults results) throws IOException {
+ generator.writeStartObject();
+ generator.writeFieldName("total");
+ generator.writeNumber(results.getTotal());
+ generator.writeFieldName("columns");
+ renderStrings(generator, results.getColumns());
+ generator.writeFieldName("selectors");
+ renderStrings(generator, results.getSelectors());
+ generator.writeFieldName("results");
+ renderResults(generator, results);
+ generator.writeEndObject();
+ }
+
+ private void renderStrings(JsonGenerator generator, Iterable<String> elements) throws IOException {
+ generator.writeStartArray();
+
+ for (String element : elements) {
+ generator.writeString(element);
+ }
+
+ generator.writeEndArray();
+ }
+
+ private void renderResults(JsonGenerator generator, RemoteResults results) throws IOException {
+ generator.writeStartArray();
+
+ for (RemoteResult result : results) {
+ renderResult(generator, results, result);
+ }
+
+ generator.writeEndArray();
+ }
+
+ private void renderResult(JsonGenerator generator, RemoteResults results, RemoteResult result) throws IOException {
+ generator.writeStartObject();
+ generator.writeFieldName("columns");
+ renderColumns(generator, results, result);
+ generator.writeFieldName("selectors");
+ renderSelectors(generator, results, result);
+ generator.writeEndObject();
+ }
+
+ private void renderColumns(JsonGenerator generator, RemoteResults results, RemoteResult result) throws IOException {
+ generator.writeStartObject();
+
+ for (String name : results.getColumns()) {
+ generator.writeFieldName(name);
+ renderJsonOrNull(generator, result.getColumnValue(name));
+ }
+
+ generator.writeEndObject();
+ }
+
+ private void renderSelectors(JsonGenerator generator, RemoteResults results, RemoteResult result) throws IOException {
+ generator.writeStartObject();
+
+ for (String name : results.getSelectors()) {
+ generator.writeFieldName(name);
+ generator.writeString(result.getSelectorPath(name));
+ }
+
+ generator.writeEndObject();
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchSpecificRevisionHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchSpecificRevisionHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchSpecificRevisionHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/SearchSpecificRevisionHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import org.apache.jackrabbit.oak.remote.RemoteRevision;
+import org.apache.jackrabbit.oak.remote.RemoteSession;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SearchSpecificRevisionHandler extends SearchRevisionHandler {
+
+ private static final Pattern REQUEST_PATTERN = Pattern.compile("^/revisions/([^/]+)/tree$");
+
+ @Override
+ protected RemoteRevision readRevision(HttpServletRequest request, RemoteSession session) {
+ Matcher matcher = REQUEST_PATTERN.matcher(request.getPathInfo());
+
+ if (matcher.matches()) {
+ return session.readRevision(matcher.group(1));
+ }
+
+ throw new IllegalStateException("handler bound at the wrong path");
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/UnauthorizedHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/UnauthorizedHandler.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/UnauthorizedHandler.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/handler/UnauthorizedHandler.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.handler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.apache.jackrabbit.oak.remote.http.handler.ResponseUtils.sendUnauthorized;
+
+class UnauthorizedHandler implements Handler {
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ sendUnauthorized(response, Collections.singletonMap("WWW-Authenticate", "Basic realm=\"Oak\""), "unable to authenticate");
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/AllMatcher.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/AllMatcher.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/AllMatcher.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/AllMatcher.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.matcher;
+
+import javax.servlet.http.HttpServletRequest;
+
+class AllMatcher implements Matcher {
+
+ private final Matcher[] matchers;
+
+ public AllMatcher(Matcher... matchers) {
+ this.matchers = matchers;
+ }
+
+ @Override
+ public boolean match(HttpServletRequest request) {
+ for (Matcher matcher : matchers) {
+ if (!matcher.match(request)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matcher.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matcher.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matcher.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matcher.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.matcher;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * A predicate over an HTTP request. This predicate can be used to check if some
+ * preconditions on the request are met.
+ */
+public interface Matcher {
+
+ /**
+ * Check if the preconditions on the given request are met.
+ *
+ * @param request Request to check.
+ * @return {@code true} if the preconditions are met, {@code false}
+ * otherwise.
+ */
+ boolean match(HttpServletRequest request);
+
+}
Added: jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matchers.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matchers.java?rev=1684861&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matchers.java (added)
+++ jackrabbit/oak/trunk/oak-remote/src/main/java/org/apache/jackrabbit/oak/remote/http/matcher/Matchers.java Thu Jun 11 12:09:15 2015
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.remote.http.matcher;
+
+import java.util.regex.Pattern;
+
+/**
+ * Collection of matchers for HTTP requests.
+ */
+public class Matchers {
+
+ private Matchers() {
+ }
+
+ /**
+ * Create a matcher that will be satisfied when given requests have a method
+ * matching the one provided as a parameter.
+ *
+ * @param method Method that requests must have for the matcher to be
+ * satisfied.
+ * @return An instance of {@code Matcher}.
+ */
+ public static Matcher matchesMethod(String method) {
+ if (method == null) {
+ throw new IllegalArgumentException("method not provided");
+ }
+
+ return new MethodMatcher(method);
+ }
+
+ /**
+ * Create a matcher that will be satisfied when given requests have a patch
+ * matching the pattern provided as a parameter.
+ *
+ * @param pattern The pattern to use when checking the requests given to the
+ * matcher.
+ * @return An instance of {@code Matcher}.
+ */
+ public static Matcher matchesPath(String pattern) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("pattern not provided");
+ }
+
+ return new PathMatcher(Pattern.compile(pattern));
+ }
+
+ /**
+ * Create a matcher that will be satisfied when the given requests satisfies
+ * every matcher provided as parameters. Calling this method is equivalent
+ * as checking every provided matcher individually and chaining each result
+ * as a short-circuit and.
+ *
+ * @param matchers The matchers that have to be satisfied for the returned
+ * matcher to be satisfied.
+ * @return An instance of {@code Matcher}.
+ */
+ public static Matcher matchesAll(Matcher... matchers) {
+ if (matchers == null) {
+ throw new IllegalArgumentException("matchers not provided");
+ }
+
+ for (Matcher matcher : matchers) {
+ if (matcher == null) {
+ throw new IllegalArgumentException("invalid matcher");
+ }
+ }
+
+ return new AllMatcher(matchers);
+ }
+
+ /**
+ * Create a matcher that will be satisifed when the given requests match the
+ * provided method and path.
+ *
+ * @param method The method that requests must have for the matcher to be
+ * satisfied.
+ * @param path The pattern to use when checking the requests given to the
+ * matcher.
+ * @return An instance of {@code Matcher}.
+ */
+ public static Matcher matchesRequest(String method, String path) {
+ return matchesAll(matchesMethod(method), matchesPath(path));
+ }
+
+}