Closed ansell closed 10 years ago
Would that make it easier using LinkedDataServer in a Servlet? I would prefer a way to use LinkedDataServer inside some sort of container allowing me start/stop it e.g. together with Tomcat.
Note: I did try getting rid of that singleton and accessing LinkedDataServer via getApplication from within the Resource classes. Unfortunately, the class is not reachable from there (through any chain of method calls I am aware of); only a generic org.restlet.Application
is retrieved. W.r.t. deploying LinkedDataServer as a servlet, there is an adapter for that; I may even have used it at some point. IIRC, it's just a matter of adding the dependency to your classpath and some configuration to your web.xml.
ServerServlet: http://restlet.org/learn/javadocs/snapshot/gae/ext/org/restlet/ext/servlet/ServerServlet.html and an example: http://danilogurovich.wordpress.com/2008/09/23/a-simple-restlet-demo-application/ but I see only 1.x dependencies here: http://maven.restlet.org/com/noelios/restlet/com.noelios.restlet.ext.servlet
thanks @joshsh
The pattern I have used in the past involves linking resources into the Application, and then linking the Application into the Component. The current pattern here is to link both the resources and Application into the Component, so it isn't surprising that the resources can't see the Application, as they are siblings, but that design seems to be necessary for extensibility here, so this is probably as good as it can be here.
There are 2.x dependencies for the servlet extension btw, they just changed the naming scheme.
http://maven-repository.com/artifact/org.restlet.jee/org.restlet.ext.servlet/2.2.0
I noticed that and put the Component under the Application:
https://github.com/joshsh/sesametools/commit/74da5cc3b379545b42334e9f48dc4e9d05c53e1a
i.e.
LinkedDataServer server = new LinkedDataServer(
sail,
"http://example.org",
"http://localhost:8001");
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8001);
component.getDefaultHost().attach("/person", WebResource.class);
component.getDefaultHost().attach("/graph", GraphResource.class);
component.getDefaultHost().attach("/sparql", new SparqlResource());
server.setInboundRoot(component);
server.start();
However, the Resources still saw a different Application. You're suggesting the opposite: Application under Component. Can you give an example?
The way I have it working in the main application I am developing for work here is defined in the following files.
I define an abstract subclass of Restlet Application with the accessor methods that the resources need:
I instantiate that subclass and link in the resources in the createInboundRoot method:
Then I created a default implementation of the component which should work for most people and link into an instance of that application:
Then I have published an example web.xml file that uses the default Component, however, others are free to use their own implementations of component as this isn't published in the main library, and all of the third party users of my application need to define some configuration files anyway, so this is only one extra.
https://github.com/podd/podd-examples/blob/master/webapp-example/src/main/webapp/WEB-INF/web.xml
To use that workflow here, the calls to component.getDefaultHost().attach("/person", WebResource.class), would need to be replaced with code in LinkedDataServer.createInboundRoot, which you could programmatically define with a Map that was sent to LinkedDataServer.
Ie:
Map<String, Class> paths = new HashMap<>();
paths.put("/person", WebResource.class);
paths.put("/graph", GraphResource.class);
paths.put("/sparql", SparqlResource.class);
LinkedDataServer server = new LinkedDataServer(sail, "http://example.org", "http://localhost:8001", paths);
Then in LinkedDataServer.createInboundRoot you would use the paths as:
final Router router = new Router(this.getContext());
for(Entry<String, Class> nextPath : paths.entrySet) {
router.attach(nextPath.getKey(), nextPath.getValue());
}
// Could also attach a CORS filter here, although I think this is my own implementation of it, so may need to find another or create a new one
// Ditto for authenticator at this point
final CrossOriginResourceSharingFilter corsFilter = new CrossOriginResourceSharingFilter();
corsFilter.setNext(router);
return corsFilter;
All of the resource classes in that method must subclass ServerResource
Then inside the resources, you can access the Application instance and cast to get access to its accessor methods:
And voila, you are rid of the singleton pattern!
I was looking into creating a test case for the fix that Roland has submitted in #39 but it is a little difficult due to the use of singletons right now, and further the reliance on Component which is slightly harder to test compared to Application. Application can be embedded inside of Component for testing, or embedded within other applications to use Linked-Data-Server as a library.
The calls to the singleton can be replaced by extending Application, and calling Resource.getApplication() from within Resources, casting it to the extended Application class to see the accessor methods such as getDatasetURI and getSail.