Zzirconium
Zzirconium

Reputation: 471

Posting with jetty client gives a null Representation in restlet

I have been stuck a couple of hours on the following issue :

I witness the following behavior:

So my question is : what are the differences between the two POST requests that trigger these behaviors ?

Here is the output (we can see first the POST made by jetty, then a get from the navigator for the html form and finally the POST from the navigator

11:26:33.140 [main] INFO  org.sample.Sample - launching server on port 8082
2015-07-29 11:26:33.203:INFO::main: Logging initialized @359ms
2015-07-29 11:26:33.375:INFO:oejs.Server:Thread-0: jetty-9.2.7.v20150116
2015-07-29 11:26:33.437:INFO:oejsh.ContextHandler:Thread-0: Started o.e.j.s.ServletContextHandler@24cca73f{/,null,AVAILABLE}
2015-07-29 11:26:33.437:INFO:oejs.ServerConnector:Thread-0: Started ServerConnector@746ab811{HTTP/1.1}{0.0.0.0:8082}
2015-07-29 11:26:33.437:INFO:oejs.Server:Thread-0: Started @609ms
11:26:35.312 [main] INFO  org.sample.Sample - now posting
2015-07-29 11:26:35.687:INFO:/:qtp115342900-21: org.restlet.ext.servlet.ServerServlet-27a1f635: [Restlet] ServerServlet: component class is null
2015-07-29 11:26:35.734:INFO:/:qtp115342900-21: org.restlet.ext.servlet.ServerServlet-27a1f635: [Restlet] Attaching application: org.sample.MyApplication@6e47c1bf to URI: 
11:26:35.828 [qtp115342900-21] INFO  org.sample.Sample - proceeding POST
11:26:35.828 [qtp115342900-21] WARN  org.sample.Sample - entity is null !
11:26:35.828 [qtp115342900-21] INFO  org.sample.Sample - param p : toto
juil. 29, 2015 11:26:35 AM org.restlet.engine.log.LogFilter afterHandle
INFO: 2015-07-29    11:26:35    127.0.0.1   -   127.0.0.1   8082    POST    /model  p=toto  204 0   0   63  http://localhost:8082   Jetty/9.2.7.v20150116   -
juil. 29, 2015 11:26:39 AM org.restlet.engine.log.LogFilter afterHandle
INFO: 2015-07-29    11:26:39    127.0.0.1   -   127.0.0.1   8082    GET /model  -   200 172 0   0   http://localhost:8082   Mozilla/5.0 (Windows NT 5.2; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0    -
11:26:43.515 [qtp115342900-22] INFO  org.sample.Sample - proceeding POST
11:26:43.515 [qtp115342900-22] INFO  org.sample.Sample - entity exists : [application/x-www-form-urlencoded,UTF-8]
11:26:43.515 [qtp115342900-22] INFO  org.sample.Sample - param p : toto
juil. 29, 2015 11:26:43 AM org.restlet.engine.log.LogFilter afterHandle
INFO: 2015-07-29    11:26:43    127.0.0.1   -   127.0.0.1   8082    POST    /model  -   204 0   6   0   http://localhost:8082   Mozilla/5.0 (Windows NT 5.2; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0    http://localhost:8082/model

Here is my project: pom.xml

<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sample</groupId>
<artifactId>simple</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Jetty Server with Restlet Sample</name>

<properties>
    <junit.version>4.12</junit.version>
    <slf4j.version>1.7.7</slf4j.version>
    <logback.version>1.1.2</logback.version>
    <jdk.version>1.7</jdk.version>
    <jetty.version>9.2.7.v20150116</jetty.version>
    <restlet.version>2.2.2</restlet.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

</properties>

<build>
    <!-- <finalName>atgm</finalName> -->
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.2</version>
            <configuration>
                <source>${jdk.version}</source>
                <target>${jdk.version}</target>
            </configuration>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>${logback.version}</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>${logback.version}</version>
    </dependency>
    <dependency>
        <groupId>org.restlet.jee</groupId>
        <artifactId>org.restlet</artifactId>
        <version>${restlet.version}</version>
    </dependency>
    <dependency>
        <groupId>org.restlet.jee</groupId>
        <artifactId>org.restlet.ext.spring</artifactId>
        <version>${restlet.version}</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>${jetty.version}</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>${jetty.version}</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-client</artifactId>
        <version>${jetty.version}</version>
    </dependency>

</dependencies>

src/main/java/org/sample/Sample.java

package org.sample;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.restlet.ext.servlet.ServerServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Sample {
    private static final Logger LOGGER = LoggerFactory.getLogger(Sample.class);

    private static final int PORT=8082;

    private static Server server;


    public static void main (String []args) throws Exception {
        LOGGER.info("launching server on port "+PORT);
        new Thread() {
            @Override
            public void run() {
                try {
                    // now create the web server
                    server = new Server(PORT);

                    final ServletContextHandler servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
                    servletContext.setContextPath("/");
                    servletContext.setInitParameter("org.restlet.application", MyApplication.class.getName());
                    servletContext.addServlet(ServerServlet.class, "/*");
                    servletContext.addServlet(DefaultServlet.class, "/");

                    server.setHandler(servletContext);
                    server.start();
                    server.join();

                } catch (Exception ex) {
                    LOGGER.info("Failed to start server", ex);
                }
            }
        }.start();

        HttpClient client = new HttpClient();
        client.start();

        // waiting for the server to be online
        final int lapse = 2000;
        Thread.sleep(lapse);

        LOGGER.info("now posting");
        client.POST("http://localhost:"+PORT+"/model")
        .param("p", "toto")
        .send();
    }
}

src/main/java/org/sample/MyApplication.java

package org.sample;

import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.routing.Router;

public class MyApplication extends Application {
    public MyApplication () {
        super();
    }

    public MyApplication (Context parentContext) {
        super(parentContext);
    }

    @Override
    public Restlet createInboundRoot() {
        Router router = new Router(getContext());
        router.attach("/model", MyResource.class);
        return router;
    }
}

src/main/java/org/sample/MyResource.java

package org.sample;

import org.restlet.data.Form;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyResource extends ServerResource {
    private static final Logger LOGGER = LoggerFactory.getLogger(Sample.class);

    @Post
    public Representation acceptItem(Representation entity) throws Exception {
        Representation result = null;
        LOGGER.info("proceeding POST");
        Form form;
        if (null != entity) {
            LOGGER.info("entity exists : "+entity.toString());
            form = new Form(entity);
        } else {
            LOGGER.warn("entity is null !");
            form = getReference().getQueryAsForm();
        }
        LOGGER.info("param p : "+form.getFirstValue("p"));
        return result;
    }

    @Get("html")
    public String represent() {
        return "<html>"+
                "<head><script src=\"http://code.jquery.com/jquery-1.11.3.min.js\"></script></head>"+
                "<body>"+
                "<button onclick=\"$.post('model',{p:'toto'});\">POST</button>"+
                "</form>"+
                "</body>"+
                "</html>";
    }
}

Upvotes: 1

Views: 764

Answers (1)

Thierry Templier
Thierry Templier

Reputation: 202256

I don't know exactly how you made your POST request from the browser but here are some hints:

  • getQuery() corresponds to the elements provided within the query string. What probably bothers you is that such data can be displayed as a form. In fact the class Form is similar to a form and doesn't correspond necessarily to the payload. So if you use URL like this: http://localhost:8082/model?p=toto, the parameter p will be present in query parameters
  • the received representation (similar to getEntity()) corresponds to the payload. It can be a form if you use the content type application/x-www-form-urlencoded but generally it's not actually a form. In the first case, you can create a Form instance from the representation / entity. So if you use request like this, you will have an entry with name p in your representation / entity:

    POST /model
    Content-Type:application/x-www-form-urlencoded
    
    p=toto
    

If you want to create such request with the Jetty client, you need to update your code like this:

Field p = new Field("p", "toto");
Fields fields = new Fields();
fields.put(p);

client.POST("http://localhost:"+PORT+"/model")
      .content(new FormContentProvider(fields))
      .send();

Hope it helps you, Thierry

Upvotes: 1

Related Questions