asterixdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ti...@apache.org
Subject [1/5] asterixdb git commit: Replace Servlets with Netty Based HTTP Servers
Date Thu, 26 Jan 2017 15:29:28 GMT
Repository: asterixdb
Updated Branches:
  refs/heads/master 9d30640f2 -> 60e7f12b4


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/TestExecutor.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/TestExecutor.java b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/TestExecutor.java
index 80e8d09..ff30df3 100644
--- a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/TestExecutor.java
+++ b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/TestExecutor.java
@@ -48,7 +48,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.asterix.common.config.GlobalConfig;
-import org.apache.asterix.common.utils.ServletUtil.Servlets;
+import org.apache.asterix.common.utils.LetUtil.Lets;
 import org.apache.asterix.test.base.ComparisonException;
 import org.apache.asterix.test.server.ITestServer;
 import org.apache.asterix.test.server.TestServerProvider;
@@ -603,7 +603,7 @@ public class TestExecutor {
     }
 
     private InputStream getHandleResult(String handle, OutputFormat fmt) throws Exception {
-        final String url = getEndpoint(Servlets.QUERY_RESULT);
+        final String url = getEndpoint(Lets.QUERY_RESULT);
 
         // Create a method instance.
         HttpUriRequest request = RequestBuilder.get(url).addParameter("handle", handle)
@@ -744,9 +744,9 @@ public class TestExecutor {
         switch (ctx.getType()) {
             case "ddl":
                 if (ctx.getFile().getName().endsWith("aql")) {
-                    executeDDL(statement, getEndpoint(Servlets.AQL_DDL));
+                    executeDDL(statement, getEndpoint(Lets.AQL_DDL));
                 } else {
-                    InputStream resultStream = executeQueryService(statement, getEndpoint(Servlets.QUERY_SERVICE));
+                    InputStream resultStream = executeQueryService(statement, getEndpoint(Lets.QUERY_SERVICE));
                     ResultExtractor.extract(resultStream);
                 }
                 break;
@@ -756,9 +756,9 @@ public class TestExecutor {
                     statement = statement.replaceAll("nc1://", "127.0.0.1://../../../../../../asterix-app/");
                 }
                 if (ctx.getFile().getName().endsWith("aql")) {
-                    executeUpdate(statement, getEndpoint(Servlets.AQL_UPDATE));
+                    executeUpdate(statement, getEndpoint(Lets.AQL_UPDATE));
                 } else {
-                    InputStream resultStream = executeQueryService(statement, getEndpoint(Servlets.QUERY_SERVICE));
+                    InputStream resultStream = executeQueryService(statement, getEndpoint(Lets.QUERY_SERVICE));
                     ResultExtractor.extract(resultStream);
                 }
                 break;
@@ -812,16 +812,16 @@ public class TestExecutor {
                 OutputFormat fmt = OutputFormat.forCompilationUnit(cUnit);
                 if (ctx.getFile().getName().endsWith("aql")) {
                     if (ctx.getType().equalsIgnoreCase("query")) {
-                        resultStream = executeQuery(statement, fmt, getEndpoint(Servlets.AQL_QUERY),
+                        resultStream = executeQuery(statement, fmt, getEndpoint(Lets.AQL_QUERY),
                                 cUnit.getParameter());
                     } else if (ctx.getType().equalsIgnoreCase("async")) {
-                        resultStream = executeAnyAQLAsync(statement, false, fmt, getEndpoint(Servlets.AQL));
+                        resultStream = executeAnyAQLAsync(statement, false, fmt, getEndpoint(Lets.AQL));
                     } else if (ctx.getType().equalsIgnoreCase("asyncdefer")) {
-                        resultStream = executeAnyAQLAsync(statement, true, fmt, getEndpoint(Servlets.AQL));
+                        resultStream = executeAnyAQLAsync(statement, true, fmt, getEndpoint(Lets.AQL));
                     }
                 } else {
                     final String reqType = ctx.getType();
-                    final String url = getEndpoint(Servlets.QUERY_SERVICE);
+                    final String url = getEndpoint(Lets.QUERY_SERVICE);
                     final List<CompilationUnit.Parameter> params = cUnit.getParameter();
                     if (reqType.equalsIgnoreCase("query")) {
                         resultStream = executeQueryService(statement, fmt, url, params, true);
@@ -854,13 +854,13 @@ public class TestExecutor {
                 break;
             case "txnqbc": // qbc represents query before crash
                 resultStream = executeQuery(statement, OutputFormat.forCompilationUnit(cUnit),
-                        getEndpoint(Servlets.AQL_QUERY), cUnit.getParameter());
+                        getEndpoint(Lets.AQL_QUERY), cUnit.getParameter());
                 qbcFile = getTestCaseQueryBeforeCrashFile(actualPath, testCaseCtx, cUnit);
                 writeOutputToFile(qbcFile, resultStream);
                 break;
             case "txnqar": // qar represents query after recovery
                 resultStream = executeQuery(statement, OutputFormat.forCompilationUnit(cUnit),
-                        getEndpoint(Servlets.AQL_QUERY), cUnit.getParameter());
+                        getEndpoint(Lets.AQL_QUERY), cUnit.getParameter());
                 File qarFile = new File(actualPath + File.separator
                         + testCaseCtx.getTestCase().getFilePath().replace(File.separator, "_") + "_" + cUnit.getName()
                         + "_qar.adm");
@@ -870,7 +870,7 @@ public class TestExecutor {
                 break;
             case "txneu": // eu represents erroneous update
                 try {
-                    executeUpdate(statement, getEndpoint(Servlets.AQL_UPDATE));
+                    executeUpdate(statement, getEndpoint(Lets.AQL_UPDATE));
                 } catch (Exception e) {
                     // An exception is expected.
                     failed = true;
@@ -898,7 +898,7 @@ public class TestExecutor {
                 break;
             case "errddl": // a ddlquery that expects error
                 try {
-                    executeDDL(statement, getEndpoint(Servlets.AQL_DDL));
+                    executeDDL(statement, getEndpoint(Lets.AQL_DDL));
                 } catch (Exception e) {
                     // expected error happens
                     failed = true;
@@ -1136,11 +1136,11 @@ public class TestExecutor {
                         + cUnit.getName() + "_qbc.adm");
     }
 
-    protected String getPath(Servlets servlet) {
+    protected String getPath(Lets servlet) {
         return servlet.getPath();
     }
 
-    protected String getEndpoint(Servlets servlet) {
+    protected String getEndpoint(Lets servlet) {
         return "http://" + host + ":" + port + getPath(servlet).replaceAll("/\\*$", "");
     }
 
@@ -1152,7 +1152,7 @@ public class TestExecutor {
         try {
             ArrayList<String> toBeDropped = new ArrayList<>();
             InputStream resultStream = executeQueryService("select dv.DataverseName from Metadata.`Dataverse` as dv;",
-                    getEndpoint(Servlets.QUERY_SERVICE));
+                    getEndpoint(Lets.QUERY_SERVICE));
             String out = IOUtils.toString(resultStream);
             ObjectMapper om = new ObjectMapper();
             om.setConfig(om.getDeserializationConfig().with(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT));
@@ -1181,7 +1181,7 @@ public class TestExecutor {
                     dropStatement.append(dv);
                     dropStatement.append(";\n");
                 }
-                resultStream = executeQueryService(dropStatement.toString(), getEndpoint(Servlets.QUERY_SERVICE));
+                resultStream = executeQueryService(dropStatement.toString(), getEndpoint(Lets.QUERY_SERVICE));
                 ResultExtractor.extract(resultStream);
             }
         } catch (Throwable th) {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/asterixdb/asterix-server/src/test/java/org/apache/asterix/server/test/SampleLocalClusterIT.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-server/src/test/java/org/apache/asterix/server/test/SampleLocalClusterIT.java b/asterixdb/asterix-server/src/test/java/org/apache/asterix/server/test/SampleLocalClusterIT.java
index 83d421f..0991d4f 100644
--- a/asterixdb/asterix-server/src/test/java/org/apache/asterix/server/test/SampleLocalClusterIT.java
+++ b/asterixdb/asterix-server/src/test/java/org/apache/asterix/server/test/SampleLocalClusterIT.java
@@ -27,7 +27,7 @@ import java.io.StringWriter;
 import java.net.URL;
 import java.util.Collections;
 
-import org.apache.asterix.common.utils.ServletUtil.Servlets;
+import org.apache.asterix.common.utils.LetUtil.Lets;
 import org.apache.asterix.test.aql.TestExecutor;
 import org.apache.asterix.test.base.TestMethodTracer;
 import org.apache.asterix.test.common.TestHelper;
@@ -89,7 +89,7 @@ public class SampleLocalClusterIT {
     public void test1_sanityQuery() throws Exception {
         TestExecutor testExecutor = new TestExecutor();
         InputStream resultStream = testExecutor.executeQuery("1+1", OutputFormat.ADM,
-                "http://127.0.0.1:19002" + Servlets.AQL_QUERY.getPath(), Collections.emptyList());
+                "http://127.0.0.1:19002" + Lets.AQL_QUERY.getPath(), Collections.emptyList());
         StringWriter sw = new StringWriter();
         IOUtils.copy(resultStream, sw);
         Assert.assertEquals("2", sw.toString().trim());

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/asterixdb/pom.xml
----------------------------------------------------------------------
diff --git a/asterixdb/pom.xml b/asterixdb/pom.xml
index ea80127..3133231 100644
--- a/asterixdb/pom.xml
+++ b/asterixdb/pom.xml
@@ -825,6 +825,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.hyracks</groupId>
+        <artifactId>hyracks-http</artifactId>
+        <version>${hyracks.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.hyracks</groupId>
         <artifactId>hyracks-util</artifactId>
         <version>${hyracks.version}</version>
       </dependency>

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/pom.xml
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/pom.xml b/hyracks-fullstack/hyracks/hyracks-http/pom.xml
new file mode 100644
index 0000000..8dc57a2
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/pom.xml
@@ -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.
+ !-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.hyracks</groupId>
+    <artifactId>hyracks</artifactId>
+    <version>0.3.1-SNAPSHOT</version>
+  </parent>
+  <artifactId>hyracks-http</artifactId>
+  <dependencies>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-all</artifactId>
+      <version>4.1.6.Final</version>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java
new file mode 100644
index 0000000..22bbc50
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java
@@ -0,0 +1,69 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.util.concurrent.ConcurrentMap;
+
+public abstract class AbstractServlet implements IServlet {
+    protected final String[] paths;
+    protected final ConcurrentMap<String, Object> ctx;
+    private final int[] trims;
+
+    public AbstractServlet(ConcurrentMap<String, Object> ctx, String[] paths) {
+        this.paths = paths;
+        this.ctx = ctx;
+        trims = new int[paths.length];
+        for (int i = 0; i < paths.length; i++) {
+            String path = paths[i];
+            if (path.endsWith("/*")) {
+                trims[i] = path.indexOf("/*");
+            } else if (path.endsWith("/")) {
+                trims[i] = path.length() - 1;
+            } else {
+                trims[i] = path.length();
+            }
+        }
+    }
+
+    @Override
+    public String[] getPaths() {
+        return paths;
+    }
+
+    @Override
+    public ConcurrentMap<String, Object> ctx() {
+        return ctx;
+    }
+
+    public String path(IServletRequest request) {
+        int trim = -1;
+        if (paths.length > 1) {
+            for (int i = 0; i < paths.length; i++) {
+                String path = paths[i].indexOf('*') >= 0 ? paths[i].substring(0, paths[i].indexOf('*')) : paths[0];
+                if (request.getHttpRequest().uri().indexOf(path) == 0) {
+                    trim = trims[i];
+                    break;
+                }
+            }
+        } else {
+            trim = trims[0];
+        }
+        return request.getHttpRequest().uri().substring(trim);
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedNettyOutputStream.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedNettyOutputStream.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedNettyOutputStream.java
new file mode 100644
index 0000000..984122b
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedNettyOutputStream.java
@@ -0,0 +1,108 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.DefaultHttpContent;
+import io.netty.handler.codec.http.HttpResponseStatus;
+
+public class ChunkedNettyOutputStream extends OutputStream {
+
+    private final ChannelHandlerContext ctx;
+    private final ChunkedResponse response;
+    private ByteBuf buffer;
+
+    public ChunkedNettyOutputStream(ChannelHandlerContext ctx, int chunkSize,
+            ChunkedResponse response) {
+        this.response = response;
+        this.ctx = ctx;
+        buffer = ctx.alloc().buffer(chunkSize);
+    }
+
+    @Override
+    public synchronized void write(byte[] b, int off, int len) {
+        if ((off < 0) || (off > b.length) || (len < 0) ||
+                ((off + len) > b.length)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+
+        if (len > buffer.capacity()) {
+            flush();
+            flush(b, off, len);
+        } else {
+            int space = buffer.writableBytes();
+            if (space >= len) {
+                buffer.writeBytes(b, off, len);
+            } else {
+                buffer.writeBytes(b, off, space);
+                flush();
+                buffer.writeBytes(b, off + space, len - space);
+            }
+        }
+    }
+
+    @Override
+    public synchronized void write(int b) {
+        if (buffer.writableBytes() > 0) {
+            buffer.writeByte(b);
+        } else {
+            flush();
+            buffer.writeByte(b);
+        }
+    }
+
+    @Override
+    public synchronized void close() throws IOException {
+        flush();
+        buffer.release();
+        super.close();
+    }
+
+    @Override
+    public synchronized void flush() {
+        if (buffer.readableBytes() > 0) {
+            int size = buffer.capacity();
+            if (response.status() == HttpResponseStatus.OK) {
+                response.flush();
+                DefaultHttpContent content = new DefaultHttpContent(buffer);
+                ctx.write(content);
+            } else {
+                response.error(buffer);
+            }
+            buffer = ctx.alloc().buffer(size);
+        }
+    }
+
+    private synchronized void flush(byte[] buf, int offset, int len) {
+        ByteBuf aBuffer = ctx.alloc().buffer(len);
+        aBuffer.writeBytes(buf, offset, len);
+        if (response.status() == HttpResponseStatus.OK) {
+            response.flush();
+            ctx.write(new DefaultHttpContent(aBuffer));
+        } else {
+            response.error(aBuffer);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java
new file mode 100644
index 0000000..19c2664
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/ChunkedResponse.java
@@ -0,0 +1,113 @@
+/*
+ * 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.hyracks.http.server;
+
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.DefaultHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaderValues;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpUtil;
+import io.netty.handler.codec.http.LastHttpContent;
+
+public class ChunkedResponse implements IServletResponse {
+    private final ChannelHandlerContext ctx;
+    private final ChunkedNettyOutputStream outputStream;
+    private final PrintWriter writer;
+    private HttpResponse response;
+    private boolean headerSent;
+    private ByteBuf error;
+    private ChannelFuture future;
+
+    public ChunkedResponse(ChannelHandlerContext ctx, FullHttpRequest request) {
+        this.ctx = ctx;
+        outputStream = new ChunkedNettyOutputStream(ctx, 4096, this);
+        writer = new PrintWriter(outputStream);
+        response = new DefaultHttpResponse(HTTP_1_1, OK);
+        response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
+        if (HttpUtil.isKeepAlive(request)) {
+            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
+        }
+    }
+
+    @Override
+    public IServletResponse setHeader(CharSequence name, Object value) throws IOException {
+        if (headerSent) {
+            throw new IOException("Can't add more headers since the initial response was sent");
+        }
+        response.headers().set(name, value);
+        return this;
+    }
+
+    @Override
+    public ChannelFuture future() {
+        return future;
+    }
+
+    @Override
+    public PrintWriter writer() {
+        return writer;
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (error == null) {
+            writer.close();
+            future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
+        }
+    }
+
+    public HttpResponseStatus status() {
+        return response.status();
+    }
+
+    public void flush() {
+        if (!headerSent && response.status() == HttpResponseStatus.OK) {
+            ctx.writeAndFlush(response);
+            headerSent = true;
+        }
+    }
+
+    public void error(ByteBuf error) {
+        this.error = error;
+    }
+
+    @Override
+    public OutputStream outputStream() {
+        return outputStream;
+    }
+
+    @Override
+    public void setStatus(HttpResponseStatus status) {
+        // update the response
+        // close the stream
+        // write the response
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FullResponse.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FullResponse.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FullResponse.java
new file mode 100644
index 0000000..245f28a
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FullResponse.java
@@ -0,0 +1,96 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaderValues;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpUtil;
+import io.netty.handler.codec.http.HttpVersion;
+
+public class FullResponse implements IServletResponse {
+    private final ChannelHandlerContext ctx;
+    private final ByteArrayOutputStream baos;
+    private final PrintWriter writer;
+    private final FullHttpResponse response;
+    private final boolean keepAlive;
+    private ChannelFuture future;
+
+    public FullResponse(ChannelHandlerContext ctx, FullHttpRequest request) {
+        this.ctx = ctx;
+        baos = new ByteArrayOutputStream();
+        writer = new PrintWriter(baos);
+        response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
+        keepAlive = HttpUtil.isKeepAlive(request);
+        if (keepAlive) {
+            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        writer.close();
+        FullHttpResponse fullResponse = response.replace(Unpooled.copiedBuffer(baos.toByteArray()));
+        if (keepAlive && response.status() == HttpResponseStatus.OK) {
+            fullResponse.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, fullResponse.content().readableBytes());
+        }
+        future = ctx.writeAndFlush(fullResponse);
+        if (response.status() != HttpResponseStatus.OK) {
+            future.addListener(ChannelFutureListener.CLOSE);
+        }
+    }
+
+    @Override
+    public IServletResponse setHeader(CharSequence name, Object value) throws IOException {
+        response.headers().set(name, value);
+        return this;
+    }
+
+    @Override
+    public PrintWriter writer() {
+        return writer;
+    }
+
+    @Override
+    public ChannelFuture future() throws IOException {
+        return future;
+    }
+
+    @Override
+    public OutputStream outputStream() {
+        return baos;
+    }
+
+    @Override
+    public void setStatus(HttpResponseStatus status) {
+        response.setStatus(status);
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/GetRequest.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/GetRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/GetRequest.java
new file mode 100644
index 0000000..0b80a78
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/GetRequest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.util.List;
+import java.util.Map;
+
+import io.netty.handler.codec.http.FullHttpRequest;
+
+public class GetRequest implements IServletRequest {
+    private final FullHttpRequest request;
+    private final Map<String, List<String>> parameters;
+
+    public GetRequest(FullHttpRequest request, Map<String, List<String>> parameters) {
+        this.request = request;
+        this.parameters = parameters;
+    }
+
+    @Override
+    public FullHttpRequest getHttpRequest() {
+        return request;
+    }
+
+    @Override
+    public String getParameter(CharSequence name) {
+        return IServletRequest.getParameter(parameters, name);
+    }
+
+    @Override
+    public String getHeader(CharSequence name) {
+        return request.headers().get(name);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
new file mode 100644
index 0000000..f7f55bd
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
@@ -0,0 +1,225 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+
+public class HttpServer {
+    // Constants
+    private static final Logger LOGGER = Logger.getLogger(HttpServer.class.getName());
+    private static final int FAILED = -1;
+    private static final int STOPPED = 0;
+    private static final int STARTING = 1;
+    private static final int STARTED = 2;
+    private static final int STOPPING = 3;
+    // Final members
+    private final Object lock = new Object();
+    private final ConcurrentMap<String, Object> ctx;
+    private final List<IServlet> lets;
+    private final EventLoopGroup bossGroup;
+    private final EventLoopGroup workerGroup;
+    private final int port;
+    // Mutable members
+    private volatile int state = STOPPED;
+    private Channel channel;
+    private Throwable cause;
+
+    public HttpServer(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
+            int port) {
+        this.bossGroup = bossGroup;
+        this.workerGroup = workerGroup;
+        this.port = port;
+        ctx = new ConcurrentHashMap<>();
+        lets = new ArrayList<>();
+    }
+
+    public final void start() throws Exception { // NOSONAR
+        synchronized (lock) {
+            try {
+                if (state == STARTED || state == STARTING) {
+                    return;
+                }
+                setStarting();
+                doStart();
+                setStarted();
+            } catch (Throwable e) { // NOSONAR
+                LOGGER.log(Level.SEVERE, "Failure starting an Http Server", e);
+                setFailed(e);
+                throw e;
+            }
+        }
+    }
+
+    public final void stop() throws Exception { // NOSONAR
+        synchronized (lock) {
+            try {
+                if (state == STOPPING || state == STOPPED) {
+                    return;
+                }
+                setStopping();
+                doStop();
+                setStopped();
+            } catch (Throwable e) { // NOSONAR
+                LOGGER.log(Level.SEVERE, "Failure stopping an Http Server", e);
+                setFailed(e);
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * @return String representation of the State for this server
+     */
+    public String getState() {
+        switch (state) {
+            case FAILED:
+                return "FAILED";
+            case STARTING:
+                return "STARTING";
+            case STARTED:
+                return "STARTED";
+            case STOPPING:
+                return "STOPPING";
+            case STOPPED:
+                return "STOPPED";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    private void setStarting() {
+        state = STARTING;
+    }
+
+    private void setStarted() {
+        state = STARTED;
+    }
+
+    private void setStopping() {
+        state = STOPPING;
+    }
+
+    private void setStopped() {
+        state = STOPPED;
+    }
+
+    private void setFailed(Throwable th) {
+        state = FAILED;
+        cause = th;
+    }
+
+    public Throwable getCause() {
+        return cause;
+    }
+
+    public void setAttribute(String name, Object value) {
+        ctx.put(name, value);
+    }
+
+    public Object getAttribute(String name) {
+        return ctx.get(name);
+    }
+
+    public ConcurrentMap<String, Object> ctx() {
+        return ctx;
+    }
+
+    public void addLet(IServlet let) {
+        lets.add(let);
+    }
+
+
+    protected void doStart() throws InterruptedException {
+        /*
+         * This is a hacky way to ensure that ILets with more specific paths are checked first.
+         * For example:
+         * "/path/to/resource/"
+         * is checked before
+         * "/path/to/"
+         * which in turn is checked before
+         * "/path/"
+         * Note that it doesn't work for the case where multiple paths map to a single ILet
+         */
+        Collections.sort(lets, (l1, l2) -> l2.getPaths()[0].length() - l1.getPaths()[0].length());
+        ServerBootstrap b = new ServerBootstrap();
+        b.group(bossGroup, workerGroup)
+                .channel(NioServerSocketChannel.class)
+                .handler(new LoggingHandler(LogLevel.INFO))
+                .childHandler(new HttpServerInitializer(this));
+        channel = b.bind(port).sync().channel();
+    }
+
+
+    protected void doStop() throws InterruptedException {
+        channel.close();
+        channel.closeFuture().sync();
+    }
+
+    public IServlet getServlet(FullHttpRequest request) {
+        String uri = request.uri();
+        int i = uri.indexOf('?');
+        if (i >= 0) {
+            uri = uri.substring(0, i);
+        }
+        for (IServlet let : lets) {
+            for (String path : let.getPaths()) {
+                if (match(path, uri)) {
+                    return let;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static boolean match(String pathSpec, String path) {
+        char c = pathSpec.charAt(0);
+        if (c == '/') {
+            if (pathSpec.length() == 1 || pathSpec.equals(path)) {
+                return true;
+            }
+
+            if (isPathWildcardMatch(pathSpec, path)) {
+                return true;
+            }
+        } else if (c == '*') {
+            return path.regionMatches(path.length() - pathSpec.length() + 1,
+                    pathSpec, 1, pathSpec.length() - 1);
+        }
+        return false;
+    }
+    private static boolean isPathWildcardMatch(String pathSpec, String path) {
+        int cpl = pathSpec.length() - 2;
+        return (pathSpec.endsWith("/*") && path.regionMatches(0, pathSpec, 0, cpl))
+                && (path.length() == cpl || '/' == path.charAt(cpl));
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
new file mode 100644
index 0000000..c8ed937
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
@@ -0,0 +1,131 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.DefaultHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpUtil;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import io.netty.handler.codec.http.multipart.Attribute;
+import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
+import io.netty.handler.codec.http.multipart.InterfaceHttpData;
+import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
+import io.netty.handler.codec.http.multipart.MixedAttribute;
+
+public class HttpServerHandler extends SimpleChannelInboundHandler<Object> {
+
+    private static final Logger LOGGER = Logger.getLogger(HttpServerHandler.class.getName());
+    protected final HttpServer server;
+
+    public HttpServerHandler(HttpServer server) {
+        this.server = server;
+    }
+
+    @Override
+    public void channelReadComplete(ChannelHandlerContext ctx) {
+        ctx.flush();
+    }
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
+        try {
+            FullHttpRequest http = (FullHttpRequest) msg;
+            IServlet servlet = server.getServlet(http);
+            if (servlet == null) {
+                DefaultHttpResponse response = new DefaultHttpResponse(http.protocolVersion(),
+                        HttpResponseStatus.NOT_FOUND);
+                ctx.write(response).addListener(ChannelFutureListener.CLOSE);
+            } else {
+                if (http.method() != HttpMethod.GET && http.method() != HttpMethod.POST) {
+                    DefaultHttpResponse response = new DefaultHttpResponse(http.protocolVersion(),
+                            HttpResponseStatus.METHOD_NOT_ALLOWED);
+                    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
+                    return;
+                }
+                IServletRequest request = http.method() == HttpMethod.GET ? get(http) : post(http);
+                IServletResponse response = new FullResponse(ctx, http);
+                try {
+                    servlet.handle(request, response);
+                } catch (Throwable th) { // NOSONAR
+                    LOGGER.log(Level.WARNING, "Failure during handling of an IServLetRequest", th);
+                    response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
+                } finally {
+                    response.close();
+                }
+                ChannelFuture lastContentFuture = response.future();
+                if (!HttpUtil.isKeepAlive(http)) {
+                    lastContentFuture.addListener(ChannelFutureListener.CLOSE);
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.log(Level.SEVERE, "Failure handling HTTP Request", e);
+            ctx.close();
+        }
+    }
+
+    public static IServletRequest post(FullHttpRequest request) throws IOException {
+        List<String> names = new ArrayList<>();
+        List<String> values = new ArrayList<>();
+        HttpPostRequestDecoder decoder = null;
+        try {
+            decoder = new HttpPostRequestDecoder(request);
+        } catch (Exception e) {
+            //ignore. this means that the body of the POST request does not have key value pairs
+            LOGGER.log(Level.WARNING, "Failed to decode a post message. Fix the API not to have queries as POST body",
+                    e);
+        }
+        if (decoder != null) {
+            try {
+                List<InterfaceHttpData> bodyHttpDatas = decoder.getBodyHttpDatas();
+                for (InterfaceHttpData data : bodyHttpDatas) {
+                    if (data.getHttpDataType().equals(HttpDataType.Attribute)) {
+                        Attribute attr = (MixedAttribute) data;
+                        names.add(data.getName());
+                        values.add(attr.getValue());
+                    }
+                }
+            } finally {
+                decoder.destroy();
+            }
+        }
+        return new PostRequest(request, new QueryStringDecoder(request.uri()).parameters(), names, values);
+    }
+
+    public static IServletRequest get(FullHttpRequest request) throws IOException {
+        return new GetRequest(request, new QueryStringDecoder(request.uri()).parameters());
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+        LOGGER.log(Level.SEVERE, "Failure handling HTTP Request", cause);
+        ctx.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
new file mode 100644
index 0000000..3b32ee6
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.hyracks.http.server;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+
+public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
+
+    private static final int MAX_CHUNK_SIZE = 262144;
+    private static final int MAX_HEADER_SIZE = 262144;
+    private static final int MAX_INITIAL_LINE_LENGTH = 131072;
+    private HttpServer server;
+
+    public HttpServerInitializer(HttpServer server) {
+        this.server = server;
+    }
+
+    @Override
+    public void initChannel(SocketChannel ch) {
+        ChannelPipeline p = ch.pipeline();
+        p.addLast(new HttpRequestDecoder(MAX_INITIAL_LINE_LENGTH, MAX_HEADER_SIZE, MAX_CHUNK_SIZE));
+        p.addLast(new HttpResponseEncoder());
+        p.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));
+        p.addLast(new HttpServerHandler(server));
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java
new file mode 100644
index 0000000..5691fd9
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServlet.java
@@ -0,0 +1,92 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Represents a component that handles IServLet requests
+ */
+public interface IServlet {
+
+    public class Encoding {
+        public static final String UTF8 = "utf-8";
+
+        private Encoding() {
+        }
+    }
+
+    public class ContentType {
+        public static final String APPLICATION_ADM = "application/x-adm";
+        public static final String APPLICATION_JSON = "application/json";
+        public static final String CSV = "text/csv";
+        public static final String IMG_PNG = "image/png";
+        public static final String TEXT_HTML = "text/html";
+        public static final String TEXT_PLAIN = "text/plain";
+
+        private ContentType() {
+        }
+
+        /**
+         * Get the mime string representation from the extension
+         * @param extension
+         * @return
+         */
+        public static String mime(String extension) {
+            switch (extension) {
+                case ".png":
+                    return "image/png";
+                case ".eot":
+                    return "application/vnd.ms-fontobject";
+                case ".svg":
+                    return "image/svg+xml\t";
+                case ".ttf":
+                    return "application/x-font-ttf";
+                case ".woff":
+                case ".woff2":
+                    return "application/x-font-woff";
+                case ".html":
+                    return "text/html";
+                case ".css":
+                    return "text/css";
+                case ".js":
+                    return "application/javascript";
+                default:
+                    return null;
+            }
+        }
+    }
+
+    /**
+     * @return an array of paths associated with this IServLet
+     */
+    String[] getPaths();
+
+    /**
+     * @return the context associated with this IServlet
+     */
+    ConcurrentMap<String, Object> ctx();
+
+    /**
+     * handle the IServLetRequest writing the response in the passed IServLetResponse
+     * @param request
+     * @param response
+     */
+    void handle(IServletRequest request, IServletResponse response);
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java
new file mode 100644
index 0000000..8aebd07
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletRequest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.util.List;
+import java.util.Map;
+
+import io.netty.handler.codec.http.FullHttpRequest;
+
+/**
+ * An Http Request instance
+ */
+public interface IServletRequest {
+    /**
+     * @return the full http request
+     */
+    FullHttpRequest getHttpRequest();
+
+    /**
+     * Get a request parameter
+     * @param name
+     * @return the parameter or null if not found
+     */
+    String getParameter(CharSequence name);
+
+    /**
+     * Get a request header
+     * @param name
+     * @return the header or null if not found
+     */
+    String getHeader(CharSequence name);
+
+    static String getParameter(Map<String, List<String>> parameters, CharSequence name) {
+        List<String> parameter = parameters.get(name);
+        if (parameter == null) {
+            return null;
+        } else if (parameter.size() == 1) {
+            return parameter.get(0);
+        } else {
+            StringBuilder aString = new StringBuilder(parameter.get(0));
+            for (int i = 1; i < parameter.size(); i++) {
+                aString.append(",").append(parameter.get(i));
+            }
+            return aString.toString();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java
new file mode 100644
index 0000000..342e643
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/IServletResponse.java
@@ -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.hyracks.http.server;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpResponseStatus;
+
+/**
+ * A response to an instance of IServLetRequest
+ */
+public interface IServletResponse extends Closeable {
+
+    /**
+     * Set a response header
+     * @param name
+     * @param value
+     * @return
+     * @throws Exception
+     */
+    IServletResponse setHeader(CharSequence name, Object value) throws IOException;
+
+    /**
+     * Get the output writer for the response
+     * @return
+     * @throws Exception
+     */
+    PrintWriter writer();
+
+    /**
+     * Send the last http response if any and return the future
+     * @return
+     * @throws Exception
+     */
+    ChannelFuture future() throws IOException;
+
+    /**
+     * Set the status of the http response
+     * @param status
+     */
+    void setStatus(HttpResponseStatus status);
+
+    /**
+     * Get the output stream for the response
+     * @return
+     */
+    OutputStream outputStream();
+
+    public static void setContentType(IServletResponse response, String type, String charset) throws IOException {
+        response.setHeader(HttpHeaderNames.CONTENT_TYPE, type + "; charset=" + charset);
+    }
+
+    public static void setContentType(IServletResponse response, String type) throws IOException {
+        response.setHeader(HttpHeaderNames.CONTENT_TYPE, type);
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java
new file mode 100644
index 0000000..99f338c
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/PostRequest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.util.List;
+import java.util.Map;
+
+import io.netty.handler.codec.http.FullHttpRequest;
+
+public class PostRequest implements IServletRequest {
+    private final FullHttpRequest request;
+    private final List<String> names;
+    private final List<String> values;
+    private final Map<String, List<String>> parameters;
+
+    public PostRequest(FullHttpRequest request, Map<String, List<String>> parameters, List<String> names,
+            List<String> values) {
+        this.request = request;
+        this.parameters = parameters;
+        this.names = names;
+        this.values = values;
+    }
+
+    @Override
+    public FullHttpRequest getHttpRequest() {
+        return request;
+    }
+
+    @Override
+    public String getParameter(CharSequence name) {
+        for (int i = 0; i < names.size(); i++) {
+            if (name.equals(names.get(i))) {
+                return values.get(i);
+            }
+        }
+        return IServletRequest.getParameter(parameters, name);
+    }
+
+    @Override
+    public String getHeader(CharSequence name) {
+        return request.headers().get(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/60e7f12b/hyracks-fullstack/hyracks/pom.xml
----------------------------------------------------------------------
diff --git a/hyracks-fullstack/hyracks/pom.xml b/hyracks-fullstack/hyracks/pom.xml
index e2d5a95..fc7d8b5 100644
--- a/hyracks-fullstack/hyracks/pom.xml
+++ b/hyracks-fullstack/hyracks/pom.xml
@@ -130,5 +130,6 @@
     <module>hyracks-maven-plugins</module>
     <module>hyracks-hdfs</module>
     <module>hyracks-dist</module>
+    <module>hyracks-http</module>
   </modules>
 </project>


Mime
View raw message