/*
 * Copyright 2014 Cask, Inc.
 *
 * Licensed 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 co.cask.cdap.internal.app.runtime.service.http;

import co.cask.cdap.api.service.http.AbstractHttpServiceHandler;
import co.cask.cdap.api.service.http.HttpServiceContext;
import co.cask.cdap.api.service.http.HttpServiceRequest;
import co.cask.cdap.api.service.http.HttpServiceResponder;
import co.cask.cdap.api.service.http.HttpServiceSpecification;
import co.cask.http.HttpHandler;
import co.cask.http.NettyHttpService;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import org.junit.Assert;
import org.junit.Test;

import java.net.InetSocketAddress;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

/**
 *
 */
public class HttpHandlerGeneratorTest {

  @Path("/v1")
  public abstract static class BaseHttpHandler extends AbstractHttpServiceHandler {

    @GET
    @Path("/handle")
    public void process(HttpServiceRequest request, HttpServiceResponder responder) {
      responder.sendString("Hello World");
    }
  }

  @Path("/v2")
  public static final class MyHttpHandler extends BaseHttpHandler {

    @Path("/echo/{name}")
    @POST
    public void echo(HttpServiceRequest request, HttpServiceResponder responder, @PathParam("name") String name) {
      responder.sendString(Charsets.UTF_8.decode(request.getContent()).toString() + " " + name);
    }

    @Override
    public void configure() {

    }
  }

  @Test
  public void testHttpHandlerGenerator() throws Exception {
    HttpHandlerFactory factory = new HttpHandlerFactory("/prefix");
    HttpHandler httpHandler = factory.createHttpHandler(new MyHttpHandler(), new HttpServiceContext() {
      @Override
      public HttpServiceSpecification getSpecification() {
        return null;
      }

      @Override
      public Map<String, String> getRuntimeArguments() {
        return null;
      }
    });

    NettyHttpService service = NettyHttpService.builder().addHttpHandlers(ImmutableList.of(httpHandler)).build();
    service.startAndWait();
    try {
      InetSocketAddress bindAddress = service.getBindAddress();

      // Make a GET call
      URLConnection urlConn = new URL(String.format("http://%s:%d/prefix/v2/handle",
                                                    bindAddress.getHostName(), bindAddress.getPort())).openConnection();
      urlConn.setReadTimeout(2000);

      Assert.assertEquals("Hello World", new String(ByteStreams.toByteArray(urlConn.getInputStream()), Charsets.UTF_8));

      // Make a POST call
      urlConn = new URL(String.format("http://%s:%d/prefix/v2/echo/test",
                                      bindAddress.getHostName(), bindAddress.getPort())).openConnection();
      urlConn.setReadTimeout(2000);
      urlConn.setDoOutput(true);
      ByteStreams.copy(ByteStreams.newInputStreamSupplier("Hello".getBytes(Charsets.UTF_8)),
                       urlConn.getOutputStream());

      Assert.assertEquals("Hello test",
                          new String(ByteStreams.toByteArray(urlConn.getInputStream()), Charsets.UTF_8));
    } finally {
      service.stopAndWait();
    }
  }
}

@@ -2126,16 +2126,413 @@
  %7D%0A%0A
+  // Omit class-level PATH annotation, to verify that prefix is still prepended to handled path.%0A  public static final class HandlerWithoutAnnotation extends AbstractHttpServiceHandler %7B%0A%0A    @Path(%22/ping%22)%0A    @GET%0A    public void echo(HttpServiceRequest request, HttpServiceResponder responder) %7B%0A      responder.sendString(%22OK%22);%0A    %7D%0A%0A    @Override%0A    public void configure() %7B%0A%0A    %7D%0A  %7D%0A%0A%0A
   @Test%0A
   pu
@@ -2527,16 +2527,16 @@
   @Test%0A
-
   public
@@ -2971,24 +2971,445 @@
  %7D%0A    %7D);%0A%0A
+    HttpHandler httpHandlerWithoutAnnotation = factory.createHttpHandler(new HandlerWithoutAnnotation(),%0A                                                                         new HttpServiceContext() %7B%0A      @Override%0A      public HttpServiceSpecification getSpecification() %7B%0A        return null;%0A      %7D%0A%0A      @Override%0A      public Map%3CString, String%3E getRuntimeArguments() %7B%0A        return null;%0A      %7D%0A    %7D);%0A%0A
     NettyHtt
@@ -3453,16 +3453,23 @@
 uilder()
+%0A      
 .addHttp
@@ -3505,16 +3505,46 @@
 pHandler
+, httpHandlerWithoutAnnotation
 )).build
@@ -3543,24 +3543,29 @@
 )).build();%0A
+    %0A
     service.
@@ -4502,24 +4502,24 @@
 ello test%22,%0A
-
             
@@ -4611,16 +4611,500 @@
 UTF_8));
+%0A%0A      // Ensure that even though the handler did not have a class-level annotation, we still prefix the path that it%0A      // handles by %22/prefix%22%0A      urlConn = new URL(String.format(%22http://%25s:%25d/prefix/ping%22,%0A                                                    bindAddress.getHostName(), bindAddress.getPort())).openConnection();%0A      urlConn.setReadTimeout(2000);%0A%0A      Assert.assertEquals(%22OK%22, new String(ByteStreams.toByteArray(urlConn.getInputStream()), Charsets.UTF_8));
 %0A    %7D f

Test to ensure that a handler without a class-level path annotation is still handling prefixed-paths (prefixed by the HttpHandlerGenerator.