Restlete Client :: how to add filters?

I am suffering from a lack of documentation on using Restlet on the client side. I am getting the resource on the server via ClientResource:

new ClientResource(url).get();

      

But the server can return an ETag header. To handle this, I want to save the ETag on checkout and send it back to the server using the same url. I am currently doing it like this:

ClientResource clientResource = new ClientResource(url);
addEtag(url, clientResource); // add the cached ETag to the query if any
clientResource.get();
saveEtag(url, clientResource); // cache the ETag if any

      

I would like to do this using the Restlet environment. I search for days without understanding the missing link. I can extend the application, overwrite the createOutboundRoot () method and return the filter:

public class RestLetClient extends Application {

    private Client client;

    // instantiation of the client and other things here

    @Override
    public Restlet createOutboundRoot() {
        return new Filter(getContext(), client){

            @Override
            protected int beforeHandle(Request request, Response response) {
                addEtag(request);
                return super.doHandle(request, response);
            }

            @Override
            protected void afterHandle(Request request, Response response) {
                saveEtag(request, reponse);
                return super.afterHandle(request, response);
            }
        };
    }
}

      

BUT how can I use this filtering around the Restlet client from my business code?

EDIT

The best I could work so far is:

Request request = new Request(Method.GET, uri);
//the filter created in original post
filter.handle(request).getEntity();

      

It works, but it is not integrated into the framework. What I intend to do is on the client side what is only documented for the server side. On the server, you will do:

public class ServerApplication extends Application {

    @Override
    public Restlet createInboundRoot() {
        Router router = new Router(getContext());
        router.attach(GET_URL, GetResource.class);
        return router;
    }
}

      

and then start the server. The application will be initiated when it receives a GET request for a URL.
What is the client side equivalent? How can I call the client application? If I have an application running on the client side, I can add filters where they belong to the REST application.

EDIT 2

When trying to run my client in my application, I get the error: The filter org.restlet.engine.application.RangeFilter@f372a7a was executed without the following Restlet attached to it.

This is how I get the error. I have a class extension that is called from a JUnit test:

public class RestLetClient extends Application {

    private final Client client;

    Logger logger = LoggerFactory.getLogger(getClass());

    public RestLetClient() {
        this.client = new Client(Protocol.HTTP);
    }

    public Representation get(final String uri) throws Exception {

        Request request = new Request(Method.GET, uri);
        Response response = handle(request);
        return response.getEntity();
    }

    @Override
    public Restlet createOutboundRoot() {
        return new Filter(getContext(), client) {
            @Override
            protected int beforeHandle(Request request, Response response) {
                addEtagFilter(request);
                return super.beforeHandle(request, response);
            }

            @Override
            protected void afterHandle(Request request, Response response) {
                saveEtagFilter(request, response);
                super.afterHandle(request, response);
            }
        };
    }

    private void saveEtagFilter(Request request, Response response) {
        logger.debug("saving etag");
    }

    private void addEtagFilter(Request request) {
        logger.debug("adding etag");
    }
}

      

and a device with one test method:

public class RestLetClientTest {

    public static final String URL = "http://localhost:8123/resource";

    private RestLetClient instance;

    private Server server;

    @Before
    public void setUp() throws Exception {
        server = new Server(Protocol.HTTP, 8123, new TestApplication());

        server.start();

        instance = new RestLetClient();
        instance.start();
    }

    @After
    public void tearDown() throws Exception {
        instance.stop();
    }

    @Test
    public void testGet() throws Exception {
        Representation representation = instance.get(URL);
        System.out.println(representation.getText());
    }

    private class TestApplication extends Application {
        @Override
        public Restlet createInboundRoot() {
            return new Router().attach(RestLetClientTest.URL, GetResource.class);
        }
    }

    private class GetResource extends ServerResource {
        @Get
        public Representation getResource() {
            return new StringRepresentation("hello world");
        }
    }
}

      

What am I doing wrong?

+3


source to share


2 answers


I had a nicer answer from a colleague. I am posting it here for documentation.

The solution is to use ClientResource, filter and client. The filter becomes the next () of the ClientResource, and the Client becomes the next () of the filter.



public class ETagFilter extends Filter {

    @Override
    protected int beforeHandle(Request request, Response response) {
        addEtag(request);
        return super.beforeHandle(request, response);
    }

    @Override
    protected void afterHandle(Request request, Response response) {
        saveEtag(request, reponse);
        super.afterHandle(request, response);
    }
}

public class RestLetClient extends Application {

    public Representation get(final String uri) throws Exception {

        Client client = new Client(Protocol.HTTP);
        ETagFilter eTagFilter = new ETagFilter();
        clientResource = new ClientResource(uri);

        clientResource.setNext(eTagFilter);
        eTagFilter.setNext(client);

        return clientResource.get(halMediaType);
    }
}

      

For information. In my OP, I was trying to convert the code meant for server side to client side. This approach was wrong. A colleague of mine pointed out that the approach is much more like using Apache HttpClient for similar needs.

+2


source


To work with the client you need to extract the application from the picture as it is server oriented according to the javadoc.

You need a component, a client router and a custom ClientRoute.

  • Component control connectors. The Restlete client is a Connector.
  • ClientRouter dispatches client connectors.
  • ClientRoute extends filter to allow you to add filters around your client's handling.

My solution:
Component

public class RestLetComponent extends Component {

    public RestLetComponent(Client client) {
        getClients().add(client);
    }
}

      



Client router

public class RestLetClientRouter extends ClientRouter {

    public RestLetClientRouter(final Client client) {
        super(new RestLetComponent(client));
        ClientRoute clientRoute = new RestLetClientRoute(this, client);
        //forcing to use only our custom route
        getRoutes().clear();
        getRoutes().add(clientRoute);
    }

    public Representation get(final String uri) throws Exception {
        Request request = new Request(Method.GET, uri);
        Response response = handle(request);
        return response.getEntity();
    }
}

      

And a custom ClientRoute that will add filters

public class RestLetClientRoute extends ClientRoute {

    Logger logger = LoggerFactory.getLogger(getClass());

    public RestLetClientRoute(Router router, Client client) {
        super(router, client);
    }

    //the filters
    @Override
    protected int beforeHandle(Request request, Response response) {
        addEtagFilter(request);
        return super.beforeHandle(request, response);
    }

    @Override
    protected int doHandle(Request request, Response response) {
        logger.debug("handling request: " + request.getMethod() + " - " + request.getResourceRef());
        return super.doHandle(request, response);
    }

    @Override
    protected void afterHandle(Request request, Response response) {
        saveEtagFilter(request, response);
        super.afterHandle(request, response);
    }

    private void saveEtagFilter(Request request, Response response) {
        logger.debug("saving etag");
    }

    private void addEtagFilter(Request request) {
        logger.debug("adding etag");
    }
}

      

Last but not least, we apologize to the registry authors , there is documentation in there. I read the book "Restlet in Action" but the answer is in the very well documented javadoc.

+1


source







All Articles