public S2RobotWebServer(final int port, final File docRoot) {
    this.port = port;
    this.docRoot = docRoot;

    server = new Server(port);

    final ResourceHandler resource_handler = new ResourceHandler();
    resource_handler.setWelcomeFiles(new String[] {"index.html"});
    resource_handler.setResourceBase(docRoot.getAbsolutePath());
    Log.info("serving " + resource_handler.getBaseResource());
    final HandlerList handlers = new HandlerList();
    handlers.setHandlers(new Handler[] {resource_handler, new DefaultHandler()});
    server.setHandler(handlers);
  }
  public ConduitServerMain(final Config config) throws Exception {
    this.log = LogFactory.getLog(getClass());
    this.config = config;
    this.path = config.path;
    this.publicHostname = config.publicHostname;
    this.tempDirPath = new File(this.path, "tmp");

    this.database =
        new Database() {
          KeyValueStore keysByUsername =
              new FilesOnDiskKeyValueStore(new File(config.path, "keys"));
          KeyValueStore passwordsByUsername =
              new FilesOnDiskKeyValueStore(new File(config.path, "credentials"));

          @Override
          public KeyValueStore trustedKeysByUsername() {
            return keysByUsername;
          }

          @Override
          public KeyValueStore passwordsByUsername() {
            return passwordsByUsername;
          }
        };

    mkDirs(this.tempDirPath);

    basePublicUrl = "http://" + config.publicHostname + ":" + config.port;
    log.info("My public url is " + basePublicUrl);

    p4Address = new P4DepotAddress(config.p4Address);

    jetty = new Server(config.port);
    ResourceHandler defaultHandler = new ResourceHandler();
    final VFSResource root = new VFSResource("/");
    defaultHandler.setBaseResource(root);
    defaultHandler.setWelcomeFiles(new String[] {"hi.txt"});
    final List<Handler> handlers = new ArrayList<Handler>();
    handlers.add(defaultHandler);

    allocator = new TempDirAllocatorImpl(tempDirPath);

    for (ConduitDiscoveryResult conduit : findConduits()) {
      if (conduit.localPath.listFiles().length == 0) {
        FileUtils.deleteDirectory(conduit.localPath);
      } else {
        conduits.add(startConduit(basePublicUrl, root, allocator, conduit));
      }
    }

    // Add shared bzr repository
    root.addVResource("/.bzr", new File(config.path, ".bzr"));

    HttpObject addConduitPage =
        new AddConduitResource(
            new AddConduitResource.Listener() {
              @Override
              public void addConduit(
                  final ConduitType type,
                  final String name,
                  final String p4Paths,
                  final Integer p4FirstCL) {
                final String[] excludePaths = p4Paths.split("\\r?\\n");

                final List<Tuple2<String, String>> e = new ArrayList<Tuple2<String, String>>();

                for (int x = 0; x < excludePaths.length; x++) {
                  final String line = excludePaths[x].trim();
                  final boolean isExclude = line.startsWith("-");

                  P4ClientSpecServerPath parsed = P4ClientSpecServerPath.parse(line);

                  final String serverSide =
                      (isExclude ? "-" : "") + "//" + parsed.depotName + parsed.path + "/...";

                  final String clientSide = parsed.path.isEmpty() ? "/..." : parsed.path + "/...";
                  System.out.println(serverSide + " -> " + clientSide);
                  e.add(tuple(serverSide, clientSide));
                }

                ConduitCreationThread thread =
                    new ConduitCreationThread(
                        config, type, name, p4FirstCL, root, e.toArray(new Tuple2[] {}));
                creationThreads.add(thread);
                thread.start();
              }
            });

    HttpObject depotHandler =
        new HttpObject("/{conduitName}/{remainder*}", null) {

          public HostableConduit findConduitForPath(String conduitName) {
            HostableConduit foundConduit = null;
            for (HostableConduit conduit : conduits) {
              final String next = conduit.httpResource.name;
              log.debug("name: " + next);
              if (conduitName.equals(next)) {
                foundConduit = conduit;
              }
            }
            return foundConduit;
          }

          public Response relay(Request req, final Method m) {
            String conduitName = "/" + req.pathVars().valueFor("conduitName");

            HostableConduit match = findConduitForPath(conduitName);
            if (match != null) {
              return HttpObjectUtil.invokeMethod(match.httpResource, m, req);
            } else {
              log.debug("There is no conduit at " + conduitName);
              return null;
            }
          }

          @Override
          public Response get(Request req) {
            return relay(req, Method.GET);
          }

          @Override
          public Response post(Request req) {
            return relay(req, Method.POST);
          }
        };

    final HttpObject conduitLogResource =
        new HttpObject("/api/conduits/{conduitName}/log") {
          @Override
          public Response get(Request req) {
            final String conduitName = req.pathVars().valueFor("conduitName");
            final HostableConduit conduit = conduitNamed(conduitName);
            if (conduit == null) {
              return NOT_FOUND();
            } else {
              try {
                final FileInputStream in = new FileInputStream(conduit.log.location);
                return OK(Bytes("text/plain", in));
              } catch (FileNotFoundException e) {
                return INTERNAL_SERVER_ERROR(e);
              }
            }
          }
        };

    final HttpObject conduitApiResource =
        new HttpObject("/api/conduits/{conduitName}") {

          @Override
          public Response get(Request req) {
            final String conduitName = req.pathVars().valueFor("conduitName");
            final HostableConduit conduit = conduitNamed(conduitName);
            if (conduit == null) {
              return NOT_FOUND();
            } else {
              return OK(JacksonJson(conduit.toDto()));
            }
          }

          @Override
          public Response delete(Request req) {
            final String conduitName = req.pathVars().valueFor("conduitName");
            final HostableConduit conduit = conduitNamed(conduitName);
            if (conduit == null) {
              return NOT_FOUND();
            } else {
              try {
                log.info("Deleting " + conduitName);
                conduits.remove(conduit);
                conduit.orchestrator.stop();
                conduit.orchestrator.delete();
                return OK(Text("deleted"));
              } catch (Exception e) {
                return INTERNAL_SERVER_ERROR(e);
              }
            }
          }
        };

    final HttpObject conduitsApiResource =
        new HttpObject("/api/conduits") {
          @Override
          public Response get(Request req) {
            ConduitsDto conduitsDto = new ConduitsDto();

            for (HostableConduit conduit : conduits) {
              conduitsDto.conduits.add(conduit.toDto());
            }

            for (ConduitCreationThread next : creationThreads) {
              ConduitInfoDto dto = new ConduitInfoDto();
              dto.name = next.name;
              if (next.pump == null) {
                dto.status = ConduitState.STARTING;
              } else {
                dto.status = ConduitState.BUILDING;
                dto.backlogSize = next.pump.backlogSize();
                dto.p4path = next.pump.p4Path();
                dto.type = next.type;
                dto.currentP4Changelist = next.pump.currentP4Changelist();
              }

              conduitsDto.conduits.add(dto);
            }

            return OK(JacksonJson(conduitsDto));
          }
        };

    final HttpObject userDataApiResource =
        new HttpObject("/api/users/{user}/secrets") {
          @Override
          public Response put(Request req) {
            final String username = req.pathVars().valueFor("user");
            final UserSecrets secrets = readJackson(req.representation(), UserSecrets.class);

            database.passwordsByUsername().put(username, secrets.password);
            database.trustedKeysByUsername().put(username, secrets.key);

            return CREATED(Location(""));
          }
        };

    handlers.add(
        new HttpObjectsJettyHandler(
            new ClasspathResourceObject("/", "index.html", getClass()),
            new ClasspathResourceObject("/submit.py", "submit.py", getClass()),
            new ClasspathResourcesObject("/{resource*}", getClass()),
            addConduitPage,
            depotHandler,
            conduitsApiResource,
            conduitApiResource,
            userDataApiResource,
            conduitLogResource));

    jetty.setHandlers(handlers.toArray(new Handler[handlers.size()]));
    jetty.start();
  }
  @BeforeClass
  @SuppressWarnings("unchecked")
  public static void setUpClass() throws Exception {

    URI webappUri = EmbeddedJettyServer.extractResourceDir("webapp", true);
    server = new Server(port);

    ServletHolder jerseyServletHolder = new ServletHolder(ServletContainer.class);
    jerseyServletHolder.setInitParameter(
        "com.sun.jersey.config.property.resourceConfigClass",
        "com.sun.jersey.api.core.PackagesResourceConfig");
    jerseyServletHolder.setInitParameter(
        "com.sun.jersey.config.property.packages", "fr.inria.edelweiss.kgramserver.webservice");
    Context servletCtx = new Context(server, "/kgram", Context.SESSIONS);
    servletCtx.addServlet(jerseyServletHolder, "/*");
    logger.info("----------------------------------------------");
    logger.info("Corese/KGRAM endpoint started on http://localhost:" + port + "/kgram");
    logger.info("----------------------------------------------");

    ResourceHandler resource_handler = new ResourceHandler();
    resource_handler.setWelcomeFiles(new String[] {"index.html"});
    resource_handler.setResourceBase(webappUri.getRawPath());
    ContextHandler staticContextHandler = new ContextHandler();
    staticContextHandler.setContextPath("/");
    staticContextHandler.setHandler(resource_handler);
    logger.info("----------------------------------------------");
    logger.info("Corese/KGRAM webapp UI started on http://localhost:" + port);
    logger.info("----------------------------------------------");

    HandlerList handlers_s1 = new HandlerList();
    handlers_s1.setHandlers(new Handler[] {staticContextHandler, servletCtx});
    server.setHandler(handlers_s1);

    try {
      server.start();
    } catch (Exception e) {
      e.printStackTrace();
    }

    ///// Data extraction
    humanData = File.createTempFile("human", ".rdf");
    FileWriter fw = new FileWriter(humanData);
    InputStream is =
        RDFS_entailmentsTest.class.getClassLoader().getResourceAsStream("human_2007_09_11.rdf");
    int c;
    while ((c = is.read()) != -1) {
      fw.write(c);
    }
    is.close();
    fw.close();

    humanOnt = File.createTempFile("humanOnt", ".rdfs");
    fw = new FileWriter(humanOnt);
    is = RDFS_entailmentsTest.class.getClassLoader().getResourceAsStream("human_2007_09_11.rdfs");
    while ((c = is.read()) != -1) {
      fw.write(c);
    }
    is.close();
    fw.close();

    ///// Data upload
    ClientConfig config = new DefaultClientConfig();
    Client client = Client.create(config);
    WebResource service = client.resource(new URI("http://localhost:" + port + "/kgram"));

    // entailments
    MultivaluedMap formData = new MultivaluedMapImpl();
    formData.add("entailments", "true");
    service.path("sparql").path("reset").post(formData);

    formData = new MultivaluedMapImpl();
    formData.add("remote_path", humanOnt.getAbsolutePath());
    service.path("sparql").path("load").post(formData);

    formData = new MultivaluedMapImpl();
    formData.add("remote_path", humanData.getAbsolutePath());
    service.path("sparql").path("load").post(formData);
  }