@Override
 public ChannelPipeline getPipeline() throws Exception {
   ChannelPipeline pipeline = Channels.pipeline();
   if (sslFactory != null) {
     pipeline.addLast("ssl", new SslHandler(sslFactory.createSSLEngine()));
   }
   pipeline.addLast("decoder", new HttpRequestDecoder());
   pipeline.addLast("aggregator", new HttpChunkAggregator(1 << 16));
   pipeline.addLast("encoder", new HttpResponseEncoder());
   pipeline.addLast("chunking", new ChunkedWriteHandler());
   pipeline.addLast("shuffle", PullServer);
   return pipeline;
   // TODO factor security manager into pipeline
   // TODO factor out encode/decode to permit binary shuffle
   // TODO factor out decode of index to permit alt. models
 }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    if (!(e.getMessage() instanceof HttpRequest)) {
      super.messageReceived(ctx, e);
    }

    HttpRequest request = (HttpRequest) e.getMessage();
    URI uri = entityManager.normalizeURI(getEntityManager().getURIBase() + request.getUri());
    String path = uri.getPath();

    System.out.println("# received request: " + uri);

    /*
     * TODO:
     * - if GET "$base/entities/create", return entity creation form
     * - if GET "$base/entities/" || GET "$base/.well-known/servers" return entity list
     * - if POST "$base/entities/", call createEntity($postdata)
     *
     * - if GET "$base/sources/", return sources list
     * - if GET "$base/sources/edit" return sources edit form
     * - if POST "$base/sources/", call setSources($postdata)
     */

    if (uri.equals(entityManager.normalizeURI(pathPrefix + "/list-entities"))) {
      if (request.getMethod() == HttpMethod.GET) {
        StringBuffer sb = new StringBuffer();
        sb.append("<html><head><title>SLSE List</title></head><body><h1>SLSE List</h1><ol>");

        for (ServiceLevelSemanticEntity slse : this.slseCache.getAll()) {
          sb.append("<li>");
          sb.append(slse.getURI() + "<pre>" + slse.getDescribes() + "</pre>");
          sb.append("</li>");
        }

        sb.append("</ol></body></html>");

        Channels.write(ctx.getChannel(), Answer.create(sb.toString()));
      }
    } else if (uri.equals(entityManager.normalizeURI(pathPrefix + "/create-entity"))) {
      if (request.getMethod() == HttpMethod.GET) {
        // copy into
        // HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(),
        // HttpResponseStatus.OK);
        // response.setContent(ChannelBuffers.wrappedBuffer(htmlContent));
        Channels.write(ctx.getChannel(), Answer.create(new String(htmlContent)));
        //				Channels.write(ctx.getChannel(),
        //						Answer.create(new File("data/slse/ui/create_entity_form.html")));
      } else if (request.getMethod() == HttpMethod.POST) {
        QueryStringDecoder qsd =
            new QueryStringDecoder(
                "http://blub.blah/?" + request.getContent().toString(Charset.defaultCharset()));

        String elementsQuery = "";
        String name = "";
        boolean dependsOnSensorValues = false;
        boolean multiNodeQuery = false;

        for (Map.Entry<String, List<String>> entry : qsd.getParameters().entrySet()) {
          String key = entry.getKey();
          for (String value : entry.getValue()) {
            if (entry.getKey().equals("elementsQuery")) {
              elementsQuery = value;
            } else if (entry.getKey().equals("name")) {
              name = value;
            } else if (key.equals("dependsOnSensorValues") && value.equals("yes")) {
              dependsOnSensorValues = true;
            } else if (key.equals("multiNodeQuery") && value.equals("yes")) {
              multiNodeQuery = true;
            }
          }
        }

        System.out.println(
            "# adding rule: name="
                + name
                + " dependsOnSensorValues="
                + dependsOnSensorValues
                + " multiNodeQuery="
                + multiNodeQuery);

        slseBuilder.addRule(name, elementsQuery, dependsOnSensorValues, multiNodeQuery);

        Channels.write(
            ctx.getChannel(),
            Answer.create(
                "<html><head><meta http-equiv=\"REFRESH\" content=\"0;url=/\"></head></html>"));
      }
    } else {
      uri = entityManager.toThing(uri);
      Model r = ModelFactory.createDefaultModel();

      if (waitForPolling) {
        //    System.out.println("# waiting for esecache: " + uri);
        synchronized (eseCache) {
          while (!eseCache.isPollComplete()) {
            try {
              eseCache.wait(1000);
            } catch (InterruptedException ex) {
              ex
                  .printStackTrace(); // To change body of catch statement use File | Settings |
                                      // File Templates.
            }
          }
        }
      }

      //  System.out.println("# waiting for slseCache: " + uri);
      synchronized (slseCache) {
        if (slseCache.get(uri.toString()) == null) {
          System.out.println(
              "! SLSE not found in cache: " + uri.toString() + " returning empty model");
        } else {
          r.add(slseCache.get(uri.toString()).getModel());
        }
      }
      ChannelFuture future = Channels.write(ctx.getChannel(), r);
      if (!HttpHeaders.isKeepAlive(request)) {
        future.addListener(ChannelFutureListener.CLOSE);
      }
      // System.out.println("# done: " + uri);

    }
  }