[OLINGO-266] ODataHandler
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/f92ab0a0 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/f92ab0a0 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/f92ab0a0 Branch: refs/heads/master Commit: f92ab0a0ec447733fc1dcbcee56febbd05ed8f1f Parents: a8f8d52 Author: Stephan Klevenz <[email protected]> Authored: Wed May 14 14:34:21 2014 +0200 Committer: Stephan Klevenz <[email protected]> Committed: Mon May 19 14:27:04 2014 +0200 ---------------------------------------------------------------------- .../olingo/commons/api/http/HttpMethod.java | 33 +++++++ .../apache/olingo/server/api/ODataServer.java | 7 +- .../org/apache/olingo/server/core/Decoder.java | 90 ++++++++++++++++++++ .../olingo/server/core/ODataHandlerImpl.java | 81 +++++++++++++++--- .../apache/olingo/server/core/ODataRequest.java | 74 ++++++++++++++++ .../olingo/server/core/ODataResponse.java | 23 +++++ .../olingo/server/core/ODataServerImpl.java | 13 ++- .../olingo/server/tecsvc/TechnicalServlet.java | 14 +-- .../serializer/json/ServiceDocumentTest.java | 2 +- .../serializer/xml/MetadataDocumentTest.java | 8 +- 10 files changed, 317 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpMethod.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpMethod.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpMethod.java new file mode 100644 index 0000000..f7d7c45 --- /dev/null +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/http/HttpMethod.java @@ -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.olingo.commons.api.http; + +/** + * Supported HTTP methods. + */ +public enum HttpMethod { + + GET, + POST, + PUT, + PATCH, + MERGE, + DELETE; + +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataServer.java ---------------------------------------------------------------------- diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataServer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataServer.java index 6ab0270..2d35100 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataServer.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataServer.java @@ -19,6 +19,7 @@ package org.apache.olingo.server.api; import org.apache.olingo.commons.api.ODataRuntimeException; +import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.server.api.edm.provider.EdmProvider; import org.apache.olingo.server.api.serializer.ODataFormat; import org.apache.olingo.server.api.serializer.ODataSerializer; @@ -45,8 +46,10 @@ public abstract class ODataServer { } } - public abstract ODataSerializer getSerializer(ODataFormat format); + public abstract ODataSerializer createSerializer(ODataFormat format); - public abstract ODataHandler getHandler(EdmProvider edmProvider); + public abstract ODataHandler createHandler(Edm edm); + + public abstract Edm createEdm(EdmProvider edmProvider); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java new file mode 100644 index 0000000..e3eb5e9 --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * 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.olingo.server.core; + +import java.io.UnsupportedEncodingException; + +/** + * Decodes a Java String containing a percent-encoded UTF-8 String value + * into a Java String (in its internal UTF-16 encoding). + * + */ +public class Decoder { + + /** + * Decodes a percent-encoded UTF-8 String value into a Java String + * (in its internal UTF-16 encoding). + * @param value the encoded String + * @return the Java String + * @throws IllegalArgumentException if value contains characters not representing UTF-8 bytes + * or ends with an unfinished percent-encoded character + * @throws NumberFormatException if the two characters after a percent character + * are not hexadecimal digits + */ + public static String decode(final String value) throws IllegalArgumentException, NumberFormatException { + if (value == null) { + return value; + } + + // Use a tiny finite-state machine to handle decoding on byte level. + // There are only three states: + // -2: normal bytes + // -1: a byte representing the percent character has been read + // >= 0: a byte representing the first half-byte of a percent-encoded byte has been read + // The variable holding the state is also used to store the value of the first half-byte. + byte[] result = new byte[value.length()]; + int position = 0; + byte encodedPart = -2; + for (final char c : value.toCharArray()) { + if (c <= Byte.MAX_VALUE) { + if (c == '%') { + if (encodedPart == -2) { + encodedPart = -1; + } else { + throw new IllegalArgumentException(); + } + } else if (encodedPart == -1) { + encodedPart = (byte) c; + } else if (encodedPart >= 0) { + final int i = Integer.parseInt(String.valueOf(new char[] { (char) encodedPart, c }), 16); + if (i >= 0) { + result[position++] = (byte) i; + } else { + throw new NumberFormatException(); + } + encodedPart = -2; + } else { + result[position++] = (byte) c; + } + } else { + throw new IllegalArgumentException(); + } + } + + if (encodedPart >= 0) { + throw new IllegalArgumentException(); + } + + try { + return new String(result, 0, position, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java index b4e7bab..a516689 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java @@ -18,42 +18,68 @@ */ package org.apache.olingo.server.core; -import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.olingo.commons.api.ODataRuntimeException; +import org.apache.olingo.commons.api.edm.Edm; +import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.server.api.ODataHandler; import org.apache.olingo.server.api.ODataServer; -import org.apache.olingo.server.api.edm.provider.EdmProvider; import org.apache.olingo.server.api.serializer.ODataFormat; import org.apache.olingo.server.api.serializer.ODataSerializer; -import org.apache.olingo.server.core.edm.provider.EdmProviderImpl; public class ODataHandlerImpl implements ODataHandler { - private EdmProvider edmProvider; + private Edm edm; private ODataServer server; - - public ODataHandlerImpl(ODataServer server, EdmProvider edmProvider) { - this.edmProvider = edmProvider; + + public ODataHandlerImpl(ODataServer server, Edm edm) { + this.edm = edm; this.server = server; } @Override public void process(HttpServletRequest request, HttpServletResponse response) { + ODataRequest odRequest = createODataRequest(request); + ODataResponse odResponse; + + // odResponse = process(odRequest); +// convertToHttp(response, odResponse); + } + + private ODataRequest createODataRequest(HttpServletRequest request) { try { - EdmProviderImpl edm = new EdmProviderImpl(edmProvider); + ODataRequest odRequest = new ODataRequest(); + odRequest.setBody(request.getInputStream()); + odRequest.setHeaders(extractHeaders(request)); + odRequest.setQueryParameters(extractQueryParameters(request.getQueryString())); + odRequest.setMethod(HttpMethod.valueOf(request.getMethod())); + + return odRequest; + } catch (Exception e) { + throw new ODataRuntimeException(e); + } + } + + public void processx(HttpServletRequest request, HttpServletResponse response) { + try { InputStream responseEntity = null; if (request.getPathInfo().contains("$metadata")) { - ODataSerializer serializer = server.getSerializer(ODataFormat.XML); + ODataSerializer serializer = server.createSerializer(ODataFormat.XML); responseEntity = serializer.metadataDocument(edm); } else { - ODataSerializer serializer = server.getSerializer(ODataFormat.JSON); + ODataSerializer serializer = server.createSerializer(ODataFormat.JSON); responseEntity = serializer.serviceDocument(edm, "http//:root"); } @@ -78,4 +104,39 @@ public class ODataHandlerImpl implements ODataHandler { throw new ODataRuntimeException(e); } } + + private Map<String, String> extractQueryParameters(final String queryString) { + Map<String, String> queryParametersMap = new HashMap<String, String>(); + if (queryString != null) { + // At first the queryString will be decoded. + List<String> queryParameters = Arrays.asList(Decoder.decode(queryString).split("\\&")); + for (String param : queryParameters) { + int indexOfEqualSign = param.indexOf("="); + if (indexOfEqualSign < 0) { + queryParametersMap.put(param, ""); + } else { + queryParametersMap.put(param.substring(0, indexOfEqualSign), param.substring(indexOfEqualSign + 1)); + } + } + } + return queryParametersMap; + } + + private Map<String, List<String>> extractHeaders(final HttpServletRequest req) { + Map<String, List<String>> requestHeaders = new HashMap<String, List<String>>(); + for (Enumeration<String> headerNames = req.getHeaderNames(); headerNames.hasMoreElements();) { + String headerName = headerNames.nextElement(); + List<String> headerValues = new ArrayList<String>(); + for (Enumeration<String> headers = req.getHeaders(headerName); headers.hasMoreElements();) { + String value = headers.nextElement(); + headerValues.add(value); + } + if (requestHeaders.containsKey(headerName)) { + requestHeaders.get(headerName).addAll(headerValues); + } else { + requestHeaders.put(headerName, headerValues); + } + } + return requestHeaders; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataRequest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataRequest.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataRequest.java new file mode 100644 index 0000000..daea101 --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataRequest.java @@ -0,0 +1,74 @@ +/* + * 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.olingo.server.core; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.olingo.commons.api.http.HttpMethod; + +public class ODataRequest { + private HttpMethod method; + private Map<String, List<String>> headers = new HashMap<String, List<String>>(); + private InputStream body; + private Map<String, String> queryParameters; + private String contentType; + + public HttpMethod getMethod() { + return method; + } + + public void setMethod(HttpMethod method) { + this.method = method; + } + + public Map<String, List<String>> getHeaders() { + return headers; + } + + public void setHeaders(Map<String, List<String>> headers) { + this.headers = headers; + } + + public InputStream getBody() { + return body; + } + + public void setBody(InputStream body) { + this.body = body; + } + + public Map<String, String> getQueryParameters() { + return queryParameters; + } + + public void setQueryParameters(Map<String, String> queryParameters) { + this.queryParameters = queryParameters; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataResponse.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataResponse.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataResponse.java new file mode 100644 index 0000000..7bcf7d3 --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataResponse.java @@ -0,0 +1,23 @@ +/* + * 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.olingo.server.core; + +public class ODataResponse { + +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataServerImpl.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataServerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataServerImpl.java index 4827fa5..5ac9d37 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataServerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataServerImpl.java @@ -19,18 +19,20 @@ package org.apache.olingo.server.core; import org.apache.olingo.commons.api.ODataRuntimeException; +import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.server.api.ODataHandler; import org.apache.olingo.server.api.ODataServer; import org.apache.olingo.server.api.edm.provider.EdmProvider; import org.apache.olingo.server.api.serializer.ODataFormat; import org.apache.olingo.server.api.serializer.ODataSerializer; +import org.apache.olingo.server.core.edm.provider.EdmProviderImpl; import org.apache.olingo.server.core.serializer.ODataJsonSerializer; import org.apache.olingo.server.core.serializer.ODataXmlSerializerImpl; public class ODataServerImpl extends ODataServer { @Override - public ODataSerializer getSerializer(final ODataFormat format) { + public ODataSerializer createSerializer(final ODataFormat format) { ODataSerializer serializer; switch (format) { case JSON: @@ -47,10 +49,13 @@ public class ODataServerImpl extends ODataServer { } @Override - public ODataHandler getHandler(EdmProvider edmProvider) { - return new ODataHandlerImpl(this, edmProvider); + public ODataHandler createHandler(Edm edm) { + return new ODataHandlerImpl(this, edm); } - + @Override + public Edm createEdm(EdmProvider edmProvider) { + return new EdmProviderImpl(edmProvider); + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java index 21d1ae3..1f6b6bf 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java @@ -25,6 +25,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.server.api.ODataHandler; import org.apache.olingo.server.api.ODataServer; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; @@ -36,16 +37,15 @@ public class TechnicalServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(TechnicalServlet.class); - + @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { LOG.debug("ReferenceServlet:service() called"); - - - ODataHandler handler = ODataServer.newInstance().getHandler(new EdmTechProvider()); - + + ODataServer server = ODataServer.newInstance(); + Edm edm = server.createEdm(new EdmTechProvider()); + + ODataHandler handler = server.createHandler(edm); handler.process(req, resp); - } - } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java ---------------------------------------------------------------------- diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java index 8713348..95ccfe9 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ServiceDocumentTest.java @@ -111,7 +111,7 @@ public class ServiceDocumentTest { ODataServer server = ODataServer.newInstance(); assertNotNull(server); - ODataSerializer serializer = server.getSerializer(ODataFormat.JSON); + ODataSerializer serializer = server.createSerializer(ODataFormat.JSON); assertNotNull(serializer); InputStream result = serializer.serviceDocument(edm, serviceRoot); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f92ab0a0/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentTest.java ---------------------------------------------------------------------- diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentTest.java index 17ac957..c17ed1f 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/MetadataDocumentTest.java @@ -65,20 +65,20 @@ public class MetadataDocumentTest { @Test(expected = ODataRuntimeException.class) public void metadataOnJsonResultsInException() { - ODataSerializer serializer = ODataServer.newInstance().getSerializer(ODataFormat.JSON); + ODataSerializer serializer = ODataServer.newInstance().createSerializer(ODataFormat.JSON); serializer.metadataDocument(mock(Edm.class)); } @Test public void writeMetadataWithEmptyMockedEdm() { - ODataSerializer serializer = ODataServer.newInstance().getSerializer(ODataFormat.XML); + ODataSerializer serializer = ODataServer.newInstance().createSerializer(ODataFormat.XML); Edm edm = mock(Edm.class); serializer.metadataDocument(edm); } @Test public void writeMetadataWithLocalTestEdm() throws Exception { - ODataSerializer serializer = ODataServer.newInstance().getSerializer(ODataFormat.XML); + ODataSerializer serializer = ODataServer.newInstance().createSerializer(ODataFormat.XML); Edm edm = new EdmProviderImpl(new TestMetadataProvider()); InputStream metadata = serializer.metadataDocument(edm); assertNotNull(metadata); @@ -147,7 +147,7 @@ public class MetadataDocumentTest { @Test public void writeMetadataWithTechnicalScenario() { - ODataSerializer serializer = ODataServer.newInstance().getSerializer(ODataFormat.XML); + ODataSerializer serializer = ODataServer.newInstance().createSerializer(ODataFormat.XML); EdmProviderImpl edm = new EdmProviderImpl(new EdmTechProvider()); InputStream metadata = serializer.metadataDocument(edm); assertNotNull(metadata);
