Issue passing context attributes to ServerResource
Asked Answered
D

2

6

My application attempts to set context attributes:

    final Router router = new Router();
    router.attachDefault(HttpListener.class);

    org.restlet.Application myApp = new org.restlet.Application() {
        @Override
        public org.restlet.Restlet createInboundRoot() {
            getContext().getAttributes().put("mysharedobj", new MySharedObj());
            return router;
        };
    };
    Component component = new Component();
    component.getDefaultHost().attach("/", myApp);

    new Server(Protocol.HTTP, port, component).start();

In my HttpListener I assert the context is not null:

public class HttpListener extends ServerResource {

    public MySharedObj mysharedobj;

    public HttpListener() { }  

    @java.lang.Override
    public void init(Context context, Request request, Response response) {

        assert context != null;  // throws java.lang.AssertionError

        // my end goal is to pass a shared object to my listener
        mysharedobj = context.getAttributes().get("mysharedobj");
    }
    ...
}

However, a java.lang.AssertionError is thrown because the context is null. My end goal is to pass a shared object to my listener. Is there another way I can do this?

Where am I going wrong? Note: I'm using Restlet 2.1.7. My application always run from an android app, so no server context is available.


Update:

I've also tried using the Application Context:

    final Router router = new Router();
    router.attachDefault(HttpListener.class);

    Component component = new Component();

    final Context ctx = component.getApplication().getContext().createChildContext();
    ctx.getAttributes().put("mysharedobj", new MySharedObj());

    org.restlet.Application myApp = new org.restlet.Application(ctx) {
        @Override
        public org.restlet.Restlet createInboundRoot() {
            return router;
        };
    };

And ..

public HttpListener() {
    Context ctx = getApplication().getContext();
    assert ctx.getAttributes().size() > 0;  // Throws AssertionError
    ...     
}

In this approach, I am able to access the Application context, but the attributes are not set on it for some reason.

Diarmuid answered 7/6, 2016 at 13:15 Comment(0)
D
0

The best solution I have at the moment is to use a singleton java class with a factory method for creating my object and a singleton getter for retrieving that object, e.g.

final Router router = new Router();
router.attachDefault(HttpListener.class);

MySharedObj myobj = MySharedObj.newInstance();

org.restlet.Application myApp = new org.restlet.Application() {
    @Override
    public org.restlet.Restlet createInboundRoot() {
        return router;
    };
};
Component component = new Component();
component.getDefaultHost().attach("/", myApp);

new Server(Protocol.HTTP, port, component).start();

// in a different thread
MySharedObj myobj = MySharedObj.get();
myobj.doStuff()

and within my HttpListner:

public HttpListener() {
    MySharedObj myobj = MySharedObj.get();
    myobj.doStuff()       
    ...     
}
Diarmuid answered 14/6, 2016 at 12:26 Comment(0)
T
0

From your updated section remove final, then it will work. Because you can set final variable only in a constructor or in an initializer. In regular methods cannot change the value of variables which is declared final.

So, your code will be

 Router router = new Router(); // Remove final from this.
    router.attachDefault(HttpListener.class);

    Component component = new Component();

    Context ctx = component.getApplication().getContext().createChildContext(); // Remove final
    ctx.getAttributes().put("mysharedobj", new MySharedObj());

    org.restlet.Application myApp = new org.restlet.Application(ctx) {
        @Override
        public org.restlet.Restlet createInboundRoot() {
            return router;
        };
    };

You can find a full source code from here.

Resource Link:

  1. Restlet Framework – Hello World Example
  2. Restlet Authorization

UPDATE1:

From Restlet documentation and sample code, I got some useful areas. Hope it will help you.

public class MyApiWithRoleAuthorization extends Application {
    @Override
    public Restlet createInboundRoot() {
        Router router = createRouter();
        return router;
    }
    private Router createRouter() {
        //Attach Server Resources to given URL
        Router router = new Router(getContext());
        router.attach("/resource1/", Resource1.class);
        router.attach("/resource2/", Resource2.class);
        return router;
    }
      public static void main(String[] args) throws Exception {
        //Attach application to http://localhost:9000/v1
        Component c = new Component();
        c.getServers().add(Protocol.HTTP, 9000);
        c.getDefaultHost().attach("/v1", new MyApiWithRoleAuthorization());
        c.start();
    }
}

Resources classes, call them Resource1, Resource2 etc... and copy-paste their content from here:

Resource0.java

public class Resource0 extends ServerResource{

    @Get
    public String represent() throws Exception {
        return this.getClass().getSimpleName() + " found !";
    }

    @Post
    public String add() {
        return this.getClass().getSimpleName() + " posted !";
    }

    @Put
    public String change() {
        return this.getClass().getSimpleName() + " changed !";
    }

    @Patch
    public String partiallyChange() {
        return this.getClass().getSimpleName() + " partially changed !";
    }

    @Delete
    public String destroy() {
        return this.getClass().getSimpleName() + " deleted!";
    }
}
Thrift answered 10/6, 2016 at 17:15 Comment(6)
removing final results in the following compilation error Cannot refer to the non-final local variable router defined in an enclosing scope at the line return router;Diarmuid
@SHC Would you please share your code through github? If possible, I can make a try.Thrift
The code I would like to use context attributes in is here: github.com/ibm-cds-labs/sync-android-p2p/blob/master/src/main/…Diarmuid
@SHC Please check the updated portion. Hope it will help you. And also go through the link.Thrift
Thanks, but it doesn't show me how I can share an object from the class instantiating the Server with the ServerResource.Diarmuid
@SHC Have you check the tutorial restlet.com/technical-resources/restlet-framework/guide/2.3/…Thrift
D
0

The best solution I have at the moment is to use a singleton java class with a factory method for creating my object and a singleton getter for retrieving that object, e.g.

final Router router = new Router();
router.attachDefault(HttpListener.class);

MySharedObj myobj = MySharedObj.newInstance();

org.restlet.Application myApp = new org.restlet.Application() {
    @Override
    public org.restlet.Restlet createInboundRoot() {
        return router;
    };
};
Component component = new Component();
component.getDefaultHost().attach("/", myApp);

new Server(Protocol.HTTP, port, component).start();

// in a different thread
MySharedObj myobj = MySharedObj.get();
myobj.doStuff()

and within my HttpListner:

public HttpListener() {
    MySharedObj myobj = MySharedObj.get();
    myobj.doStuff()       
    ...     
}
Diarmuid answered 14/6, 2016 at 12:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.