简体   繁体   English

Restlet Client ::如何添加过滤器?

[英]Restlet Client :: how to add filters?

I suffering of a lack of documentation on the use of Restlet at the client side. 我缺乏在客户端使用Restlet的文档。 I am getting a resource on server via a ClientResource: 我通过ClientResource在服务器上获取资源:

new ClientResource(url).get();

But the server can return an ETag header. 但是服务器可以返回ETag标头。 To handle this I want to save the ETag when returned and send it back to the server when using the same url. 为了解决这个问题,我想在返回时保存ETag,并在使用相同的url时将其发送回服务器。 Currently I am 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 framework. 我想使用Restlet框架来做到这一点。 I am searching for days wihtout understanding the missing link. 我正在寻找没有理解缺失环节的日子。 I can extend an application, overwrite the createOutboundRoot() method and return a filter: 我可以扩展一个应用程序,覆盖createOutboundRoot()方法并返回一个过滤器:

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? 但是如何从我的业务代码中对Restlet客户端使用此过滤?

EDIT 编辑

The best I could get to work until now is this: 到目前为止我能够工作的最好的是:

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

This works but it is not integrated in the framework. 这有效,但它没有集成在框架中。 What I am achieving to do is at the client side what is only documented for the server side. 我要做的是在客户端,只有服务器端记录的内容。 On the server you would 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 the be triggered on the reception of a GET request on the url. 应用程序将在URL上接收GET请求时触发。
What is the equivalent on the client side? 客户端的等价物是什么? How can I trigger a Client Application? 如何触发客户端应用程序? If I have an Application running at the client side I can nicely add filters where they belong in a REST application 如果我在客户端运行了一个应用程序,我可以很好地添加它们属于REST应用程序的过滤器

EDIT 2 编辑2

When trying to run my client within an Application I get the error: The filter org.restlet.engine.application.RangeFilter@f372a7a was executed without a next Restlet attached to it. 当尝试在应用程序中运行我的客户端时,我得到错误: 过滤器org.restlet.engine.application.RangeFilter@f372a7a在没有附加下一个Restlet的情况下执行。

Here is how I am getting the error. 以下是我收到错误的方法。 I have a class extending Application that is called from a JUnit test: 我有一个扩展Application的类,它从JUnit测试中调用:

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 the unit with a single 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? 我究竟做错了什么?

I had a much nicer answer from a colleague. 我从一位同事那里得到了更好的回答。 I post it here for the documentation. 我在这里发布文档。

The solution is to use a ClientResource, a Filter and a Client. 解决方案是使用ClientResource,Filter和Client。 The Filter becomes the next() of the ClientResource and the Client the next() of the Filter. Filter成为ClientResource的next(),Client成为Filter的next()。

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 info. 有关信息。 In my OP I was trying to transform code meant for server side into client side. 在我的OP中,我试图将服务器端的代码转换为客户端。 That approach was wrong. 这种做法是错误的。 My colleague pointed that the approach is much more like the use Apache HttpClient for similar needs 我的同事指出,这种方法更像是使用Apache HttpClient来满足类似的需求

To have a client working you need to take the Application out of the picture since it is Server oriented according to the javadoc. 要让客户端工作,您需要将应用程序从图片中取出,因为它是根据javadoc面向服务器的。

What you need is a Component, a ClientRouter and a custom ClientRoute. 您需要的是Component,ClientRouter和自定义ClientRoute。

  • Component manage connectors. 组件管理连接器。 A Restlet Client is a Connector. Restlet Client是一个连接器。
  • ClientRouter dispatches to client connectors. ClientRouter调度到客户端连接器。
  • ClientRoute extends Filter allowing to add filters around your client handeling. ClientRoute扩展了Filter,允许在您的客户端周围添加过滤器。

My solution: 我的解决方案
The Component 组件

public class RestLetComponent extends Component {

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

The ClientRouter ClientRouter

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 the custom ClientRoute that will add the filters 以及将添加过滤器的自定义ClientRoute

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");
    }
}

And last but not least, I apologize to the Restlet authors , the documentation is there. 最后但并非最不重要的是, 我向Restlet的作者道歉 ,文档就在那里。 I was reading the Restlet in Action book but the answer is in the very well documented javadoc. 我正在阅读Restlet in Action一书,但答案是在记录良好的javadoc中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM