Want to know Restlet Routing basic concepts - java

I am using the restlet routing APIs like
http://localhost:8080/www.example.com/hello/ping
But I don't know how to use this type of method:
/{projectName}/{wallName}
that I have seen in
Restlet routing nightmare?
Could anyone tell me
1.What is the best practice of using Restlet Routing?
2.How to implement /{projectName}/{wallName} in java?
3.How to get the value of projectName from this API?

In fact, there are several part within a Restlet application. Classically, this application is accessible through a Restlet component that can be created as described below:
Standalone mode (outside an application server)
Component component = new Component();
component.setName("My component");
component.getServers().add(Protocol.HTTP, 8182);
MyApplication application = new MyApplication();
// To attach application on /www.example.com
component.getDefaultHost().attach("www.example.com", application);
// To attach application on /
component.getDefaultHost().attachDefault(application);
component.start();
Container mode (servlet support). You can use the extension ext.servlet for this use case. A front servlet is provided that automatically wraps a component. You only have to specify the class of your application implementation, as described below:
<!-- Application class name -->
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>
packageName.MyApplication
</param-value>
</context-param>
<!– Restlet adapter –>
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>
org.restlet.ext.servlet.ServerServlet
</servlet-class>
</servlet>
<!– Catch all requests –>
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/*</url-pattern>
<!-- or -->
<!-- url-pattern>/www.example.com/*</url-pattern -->
</servlet-mapping>
You can now implement the Restlet application. For this implement, a class that extends Application. The routing must be defined within its method createInboudRoot, as described below:
public MyApplication extends Application {
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/{projectName}/{wallName}", MyServerResource.class);
return router;
}
}
As you can see, a server resource is attached for the path /{projectName}/{wallName}. This server resource is responsible to handle the request. A sample of implementation is described below:
public class MyServerResource extends ServerResource {
#Get
public Representation handleGet() {
String projectName = getAttribute("projectName");
String wallName = getAttribute("wallName");
(...)
}
}
Hope it helps you,
Thierry

Related

How do I get config paramerters from my web.xml in Jersey?

I have been trying to get parameters from my web.xml file from within my Jakarta JAX-RS resource. My web.xml is as follows:
<web-app>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>terrible.package.name</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/api/v1/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>max-customers-size</param-name>
<param-value>10</param-value>
</context-param>
</web-app>
In my test setup, I am running my web app with Jetty:
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
WebAppContext ctx = new WebAppContext("target/the-finished-servlet.war", "/");
server.setHandler(ctx);
server.start();
}
And I have the following user resource defined using jakarta:
#Path("user")
public class UserResource {
ServletContext context;
#Context
public void setServletContext(ServletContext context) {
this.context = context;
System.out.println("setting to: " + context);
}
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public Response getListOfAllUsers(final #Context HttpHeaders hdrs) throws SQLException {
System.out.println(context.getInitParameter("max-customers-size"));
return Response.ok("{}").build();
}
}
The context is always null, which makes absolutely no sense. The setServletContext method is called, and the parameter is null. I've tried using #Context on a constructor parameter, I've tried it on my context field, and I've tried it in the getListOfAllUsers method. None of them work.
I just want to configure my servlet (for MySQL database path and user, in this example I'm testing with max-customers-size, which doesn't matter though, because my context is null either way). Is there an easier way to get custom config data into my servlet? I want the user of my resulting war file to be able to supply things like the database port. Why isn't ServletContext working, and if there is an easier way to make my servlet configurable, how do I do that?
Typically a database (DataSource) for Servlet is configured via JNDI (the definition exists on the server JNDI context, and the webapp JNDI context contains a hardcoded reference to the server level location)
Your server level will typically have an XML that defines the DataSource as a org.eclipse.jetty.plus.jndi.Resource against the server level context.
And your webapp's WEB-INF/web.xml contains the <resource-ref> back to that server level location.
Your code then uses the InitialContext on JNDI to access this already defined DataSource.
This has the added bonus that the datasource can be any JDBC compatible implementation, and even include complex configurations like a Connection pool implementation (eg: c3p0) in front of your JDBC DataSource.
For unit testing, you'll set it up like this ...
JNDI Lookup Failing For Embedded Jetty Server
For standard webapp deployment in a standalone Jetty container, you'll set it up like this ...
Declaring JNDI Resources

Jersey hides Spring framework and SockJS

We're trying to expose sockjs endpoints with Spring Framework WebSocket support.
This is the configuration on the server side where Jersey is managing the routes:
#Configuration
#EnableWebSocket
public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/sockjs").withSockJS()
.setStreamBytesLimit(512 * 1024)
.setHttpMessageCacheSize(1000)
.setDisconnectDelay(30 * 1000);
}
}
The problem is that we can't access /sockjs, the client code is:
List<Transport> transports = new ArrayList<>(2);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
transports.add(new RestTemplateXhrTransport());
SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.doHandshake(new MyHandler(), "ws://localhost:8080/sockjs");
(the code is from spring websockets tutorial)
Other resources in the same package would've configured under root/api/server, even though, not /sockjs nor /root/api/server/sockjs are accessible.
I know that this is quite ancient question, but lately I've bumped into the same problem and I've spent half a day to find a solution. As I've found one I'd like to share it, at least for future myself.
The problem was that I had only Jersey's servlet definition inside my WEB-INF.xml. The solution was to add Spring's DispatcherServlet and its mapping to the /* route.
So basically it looks like
<servlet>
<servlet-name>spring</servlet-mapping>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

Restlet web.xml config for new component

I have set up an App Engine Restlet Project (v 2.2.2) which returns a html or json response (web or android client) and different data from a db for different users. I have implemented HTTP basic authentication. It all works quite well.
my basic setup atm (I have simplified it ofc):
MyApplication.java
public class MyApplication extends Application {
private ChallengeAuthenticator authenticatior;
private ChallengeAuthenticator createAuthenticator() {...}
public boolean authenticate(Request request, Response response) {...}
#Override
public Restlet createInboundRoot() {
this.authenticatior = createAuthenticator();
Router router = new Router(getContext());
router.attachDefault(MyRestlet.class);
authenticatior.setNext(router);
return authenticatior;
}
MyRestlet.java
public class MyRestlet extends ServerResource {
#Get("json")
public Representation getJSON() {
MyApplication app = (MyApplication) getApplication();
if (!app.authenticate(getRequest(), getResponse())) {
// Not authenticated
return null;
}
else {
return data;
}
#Get("html")
public String getHTML() {...}
}
web.xml
<?xml ...>
<display-name>MyName</display-name>
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>x.MyApplication</param-value>
</context-param>
<servlet>
<servlet-name>MyRestlet</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyRestlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Now I want to add encryption and created keys/certificates. My guide was this tutorial. I wanted to try to add a simple component first, stay with HTTP and change the port to 8183 as done in this tutorial. I have now played around quite a bit and cannot seem to get my component to work. So my question is: Where would I put this main-Method (the following code is taken from the tutorial)? Into which class should I insert it or should I create a seperate server-class and what exactly would the required changes to the web.xml look like (I did not find much concerning this and I suspect that this is the central problem)? Any help is appreciated!
public static void main(String[] args) throws Exception {
// Create a new Restlet component and add a HTTP server connector to it
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
// Then attach it to the local host
component.getDefaultHost().attach("/trace", Part05.class);
// Now, let's start the component!
// Note that the HTTP server connector is also automatically started.
component.start();
}
Your question is slightly confusing, probably because of the path you have taken.
Your original plan creates a RESTlet web application, complete with web.xml to run inside a container, such as GAE, Jetty or Tomcat.
What you're proposing creates a component and starts a stand alone server (it starts an internal instance of Jetty). This won't work on Google App Engine.
You should continue with the web.xml approach and configure GAE to serve over https. See https://cloud.google.com/appengine/kb/general#https and https://cloud.google.com/appengine/docs/java/config/webxml#Secure_URLs for configuration instructions.
Also, another tip: return 403 status when something attempts to access a resource without authorisation.
So I was trying to convert a JavaSE RESTLET app to a JavaEE app. What I understood from the "Restlet in Action" book, Pg 72, is that we dont need to attach a server to the component as Servlet engine handles the incoming HTTP and HTTPS requests.
The tutorial also points to the component file an an INIT-PARAM or param-name in your web.xml. However for me, none of above 2 changes are working.
If I point to the application class as an INIT-PARAM and not use a HTTP connector as suggested in the book, i am able to access the APIs but not able to make any calls from the client class as I get the below error -
WARNING: The protocol used by this request is not declared in the list of client connectors. (HTTP/1.1). In case you are using an instance of the Component class, check its "clients" property.
Not Found (404) - The server has not found anything matching the request URI
Hope these info help you in some way
EDIT
I found the solution to the above problem -
I had to add the below piece of code
<init-param>
<param-name>org.restlet.clients</param-name>
<param-value>HTTP HTTPS FILE</param-value>
</init-param>
Also for your problem, you need to configure the Component via an XML. Below URLs will give more info -
http://restlet.com/learn/javadocs/2.1/jee/ext/org/restlet/ext/servlet/ServerServlet.html
http://restlet.com/learn/javadocs/2.1/jee/api/org/restlet/Component.html?is-external=true

Is there a way to change the output type for restful webservices by a parameter in java?

I wanna use the same restful webservice path to produce xml or json, or a xml with xsl header.
Is it possible using any framework(jersey or resteasy) in java?
Eg:
#Path("/person")
public class PersonService {
#GET
#Path("/find")
public Person find(#QueryParam("name") String name, #QueryParam("outputformat") String outputformat) {
// do some magic to change output format
return dao.findPerson(name);
}
}
Maybe you can write a servlet filter that takes the query string and uses it to set the request's accept header accordingly, then jersey should dispatch to whatever method is annotated with #Consumes that matches.
For example, servlet filter intercepts request "?outputFormat=xml" and sets the Accept header to "application/xml". Then, jersey should dispatch to whichever method in your resource is annotated with: #Consumes("application/xml")
This question might help: REST. Jersey. How to programmatically choose what type to return: JSON or XML?
You could also easily customize Jersey ServletContainer and you won't require another param to pass along. You could negotiate representation using .json or .xml in your URL.
public class MyServletContainer extends ServletContainer {
#Override
protected void configure(ServletConfig servletConfig, ResourceConfig resourceConfig, WebApplication webApplication) {
super.configure(servletConfig, resourceConfig, webApplication);
resourceConfig.getMediaTypeMappings().put("json", MediaType.APPLICATION_JSON_TYPE);
resourceConfig.getMediaTypeMappings().put("xml", MediaType.APPLICATION_XML_TYPE);
}
}
In your web.xml, you could define the custom servlet as shown below.
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.MyServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.sun.jersey.MyWebApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
You could use Jersey and use the annotation #Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}). You would need to add a mapping feature for POJOs in your application as well. The include in the web.xml file would be
<filter>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
</filter>
Other configurations would be necessary, but it is all in the documentation http://jersey.java.net/nonav/documentation/latest/user-guide.html

Start class right after deployment, not at session start for JSF

For a web application I make use of JSF 1.2 and Facelets.
The problem is that we now do the initialisation via a singleton pattern and that takes about 5-15 seconds because it read in data files (we are not using a database). This happens when the first user browses to the corresponding web page (the 2nd and other users don't have this delay).
I would like to have this singleton initialised right after deployment. How can I do this? I've tried to add an application bean but it does not get called. I've also tried to add a servlet as followings:
<servlet>
<description>MyApplicationContextListener Servlet</description>
<display-name>MyApplicationContextListener Servlet</display-name>
<servlet-name>MyApplicationContextListener</servlet-name>
<servlet-class>mydomain.beans.MyApplicationContextListener</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<listener>
<listener-class>mydomain.beans.MyApplicationContextListener</listener-class>
</listener>
with the following code:
package mydomain.beans;
import javax.servlet.ServletContextEvent;
public class MyApplicationContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("MyApplicationContextListener.contextInitialized started");
}
public void contextDestroyed(ServletContextEvent event) {
System.out.println("MyApplicationContextListener.contextInitialized stopped");
}
}
An example including changes needed in web.xml and/or faces-config.xml would be nice!
How about using a ServletContextListener ? Its contextInitialized(..) method will be called at the moment the context is initialized. It's mapped in web.xml like this:
<listener>
<listener-class>com.example.MyServletContextListener</listener-class>
</listener>
Also, (not sure this would work), you can configure your faces-servlet to be loaded on startup.:
<load-on-startup>1</load-on-startup>
Clarification: For the listener approach, your listener must implement the ServletContextListener:
public class MyServletContextListener implements ServletContextListener { .. }

Categories

Resources