package solutions.digamma.damas.rs.provider;

import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.RuntimeDelegate;
import solutions.digamma.damas.config.Configuration;
import solutions.digamma.damas.config.Fallback;
import solutions.digamma.damas.logging.Logbook;

/**
 * HTTP Server bootstrapper.
 *
 * @author Ahmad Shahwan
 */
@Singleton
public class HttpServerBootstrapper {

    @Inject
    @Configuration({"http.port", "HTTP_PORT"}) @Fallback("8080")
    private Integer port;

    @Inject
    private Instance<Application> applications;

    @Inject
    private Logbook logger;

    private HttpServer server;

    /**
     * Allow eager initialization.
     *
     * @param event         application initialization event
     */
    public void onAppInitialization(
            @Observes @Initialized(ApplicationScoped.class) Object event) {
    }

    @PostConstruct
    public void init() {
        /* Only one application is expected to be found */
        boolean found = this.applications
                .stream()
                .sequential()
                .anyMatch(this::register);
        if (!found) {
            this.logger.severe("No Web applications with context path found.");
            return;
        }
        logger.info("Starting HTTP server.");
        this.server.start();
        logger.info("HTTP server started on port %d.", this.port);
    }

    private boolean register(Application application) {
        ApplicationPath annotation = application
                .getClass()
                .getAnnotation(ApplicationPath.class);
        if (annotation == null) {
            return false;
        }
        HttpHandler restHandler = RuntimeDelegate.getInstance()
                .createEndpoint(application, HttpHandler.class);
        try {
            this.server = HttpServer
                    .create(new InetSocketAddress(this.port), 0);
        } catch (IOException e) {
            this.logger.severe(e,
                    "Error while creating http server on port %d.", this.port);
            return false;
        }
        String path = annotation.value();
        String mapping = path.startsWith("/") ? path : "/".concat(path);
        this.server.createContext(mapping, restHandler);
        return true;
    }

    @PreDestroy
    public void dispose() {
        if (this.server != null) {
            logger.info("Shutting down HTTP server.");
            this.server.stop(0);
        }
    }
}

@@ -187,16 +187,74 @@
 ddress;%0A
+import java.util.Map;%0Aimport java.util.stream.Collectors;%0A
 import j
@@ -1467,80 +1467,195 @@
     
-/* Only one application is expected to be found */%0A        boolean found
+Map%3CString, HttpHandler%3E handlers;%0A        try %7B%0A            /* Collect applications that have path annotation as a path-handler%0A             * pairs.%0A             */%0A            handlers
  = t
@@ -1687,16 +1687,20 @@
         
+ 
+   
 .stream(
@@ -1701,16 +1701,20 @@
 tream()%0A
+    
         
@@ -1755,210 +1755,875 @@
     
-.anyMatch(this::register);%0A        if (!found) %7B%0A            this.logger.severe(%22No Web applications with context path found.%22);%0A            return;%0A        %7D%0A        logger.info(%22Starting HTTP server.%22
+    .filter(this::accept)%0A                    .collect(Collectors.toMap(this::mapping, this::handler));%0A        %7D catch (IllegalStateException e) %7B%0A            this.logger.severe(%22More than one application share same path.%22);%0A            return;%0A        %7D%0A        if (handlers.isEmpty()) %7B%0A            this.logger.severe(%22No Web applications with context path found.%22);%0A            return;%0A        %7D%0A        logger.info(%22%25d HTTP application(s) collected.%22, handlers.size());%0A        try %7B%0A            this.server = HttpServer.create();%0A            this.server.bind(new InetSocketAddress(this.port), 0);%0A        %7D catch (IOException e) %7B%0A            this.logger.severe(e,%0A                    %22Error while binding http server on port %25d.%22, this.port);%0A        %7D%0A        /* Add collected handlers to server%0A         */%0A        handlers.forEach(this.server::createContext
 );%0A 
@@ -2748,16 +2748,14 @@
 ean 
-register
+accept
 (App
@@ -2790,35 +2790,21 @@
     
-ApplicationPath annotation 
+return null !
 = ap
@@ -2904,63 +2904,113 @@
     
+%7D%0A%0A
     
-if (annotation == null) %7B%0A            return false;
+private String mapping(Application application) %7B%0A        ApplicationPath annotation = application
 %0A   
@@ -3014,26 +3014,24 @@
         
-%7D%0A
         
 HttpHand
@@ -3026,120 +3026,66 @@
     
-HttpHandler restHandler = RuntimeDelegate.getInstance()%0A                .createEndpoint(application, HttpHandler
+.getClass()%0A                .getAnnotation(ApplicationPath
 .cla
@@ -3101,290 +3101,201 @@
     
+S
 tr
-y %7B%0A            this.server = HttpServer%0A                    .create(new InetSocketAddress(this.port), 0);%0A        %7D catch (IOException e) %7B%0A            this.logger.severe(e,%0A                    %22Error while creating http server on port %25d.%22, this.port);%0A            return false;
+ing path = annotation.value();%0A        return path.startsWith(%22/%22) ? path : %22/%22.concat(path);%0A    %7D%0A%0A    private HttpHandler handler(Application application) %7B%0A        return RuntimeDelegate
 %0A   
@@ -3299,26 +3299,24 @@
         
-%7D%0A
         
 String p
@@ -3311,41 +3311,22 @@
     
-String path = annotation.valu
+.getInstanc
 e()
-;
 %0A   
@@ -3334,149 +3334,63 @@
     
-String mapping = path.startsWith(%22/%22) ? path : %22/%22.concat(path);%0A        this.server.createContex
+        .createEndpoin
 t(
-m
 app
-ing, restHandler);%0A        return true
+lication, HttpHandler.class)
 ;%0A  

Allow multiple JAX-RS Application