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
Related
The last couple of days, I have been struggling with an issue. I've created a rest service hosted by a Grizzly server inside an OSGi container. Everything is working perfectly at this point.
Now, I want to add a header in every response.Not so complex or illogical right? Yet, I can't find a way to do it.
I have tried to:
1) Get the response object inside the rest functions as this question suggests (pretty textbook when you are not under OSGi).
2) Add a handler using the code above (in this case the service method is never called)
server.getServerConfiguration().addHttpHandler(
new HttpHandler() {
#Override
public void service(Request arg0, Response arg1)
throws Exception {
arg1.setHeader("Access-Control-Allow-Origin", "*");
}
});
I am using jersey-server/client/core 1.18.1 and grizzly2-server 1.18.1, hence i prefer a solution that can be applied in this version, but I am willing to update jar versions if it cannot be done in 1.18.x.
You could give a try to Jersey filters.
In a nutshell, you should create class implementing ContainerResponseFilter:
public class MyFilter implements ContainerResponseFilter {
#Override
public void filter(
ContainerRequest request,
ContainerResponse response
) throws IOException {
request.getHttpHeaders().add(<header name>, <header value>);
}
}
Then, you should register this filter in your Jersey server configuration.
Please, note, that this filter would be invoked on every response. To bind it only to specific resources, you could use annotation-binding, that is described here.
All other information you could find here.
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
My first attempt at developing a simple authentication based REST services. I am trying to develop a RESTful web application using Jersey on Tomcat 8. I am using Apache Shiro for session management and authorization. Only HTTPS is supported.
All services require authentication, neither guest nor anonymous access is allowed. The request can be authenticated two ways.
If the user belongs to the list of users in web application, then the user logs in from a Web browser and Shiro simply validates if the current user is logged in and allows request to proceed. This is for the custom UI provided by the application itself.
If the request is from third party application, the username/password token are passed into the HTTP header authorization field for every service request. The users are managed by third party app and the app uses a common username/password for its users to access the web service. Such common users are prevented from logging in.
All service requests are filtered (web.xml):
<servlet>
<servlet-name>REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.unisys.cpf.ffm.filter.AuthenticationFilter</param-value>
</init-param>
</servlet>
<servlet-mapping>`enter code here`
<servlet-name>REST Service</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
The AuthenticationFilter class implements ContainerRequestFilter for authentication:
#Override
public ContainerRequest filter(ContainerRequest cr) {
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
//User is not logged in so get the authorization from header and authenticate
String auth = cr.getHeaderValue("authorization");
//Do Shiro authentication here.
}
return cr;
}
I have a web service which accepts form parameters and creates a resource. The Form parameters are dynamic based on what user selects. So I cannot use #FormParam to get all the parameters. Also there may be more contents to form as new features are added so I do not want to touch the Service again for each new/removed parameter.
I am using the Chrome Advanced REST Client plugin to simulate third party requests. Any browser is fine for the first scenario (logged in user).
Now I know just two ways of accessing the form parameters.
First method is to use MultivaluedMap.
#POST
#Path("/create")
public String createResource(MultivaluedMap<String, String> parameters) {
System.out.println("Name of the resource: " + parameters.getFirst("resourceName"));
}
But trying to get the parameters using MultivaluedMap works only when a logged in user submits the form. If I submit from REST Client plugin the same form values, then all parameters return null.
Second method is to use #Context HttpServletRequest
#POST
#Path("/create")
public String createResource(#Context HttpServletRequest request) {
System.out.println("Name of the resource: " + request.getParameter("resourceName"));
}
This works for REST Client but does not work if a logged in user submits form. All request.getParameter return null.
If anybody knows how to fix the problem or better way to do authentication, then please let me know.
I've got a problem while developing a rather simple app. I have absolutely no idea from where it comes from.
Basically, while trying to load a page from my java application, I get a 404 error from Tomcat when I enable a listener which aims at initializing app-wide data (My DAO). When I disable the listener by commenting the lines out in web.xml, I get a 500 on servlet call (triggered by NPE in init() method due to lack of initialisation through the listener class).
Any idea from where it could come ?
Here are extracts of code
web.xml
...
<listener>
<listener-class>com.mypackage.InitialisationDAOFactory</listener-class>
</listener>
...
<servlet>
<servlet-name>NewBooking</servlet-name>
<servlet-class>com.mypackages.NewBooking</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>NewBooking</servlet-name>
<url-pattern>/index</url-pattern>
</servlet-mapping>
...
InitialisationDAOFactory.java
public class InitialisationDAOFactory implements ServletContextListener
{
private static final String ATT_DAO_FACTORY = "daofactory";
private DAOFactory daoFactory;
...
#Override
public void contextInitialized(ServletContextEvent event)
{
ServletContext context = event.getServletContext();
this.daoFactory = DAOFactory.getInstance();
context.setAttribute(ATT_DAO_FACTORY, daoFactory);
}
}
NewBooking.java
public class NewBooking extends HttpServlet
{
private static final String CONF_DAO_FACTORY = "daofactory";
...
private BookingDAO = daoBooking;
private TripDAO = daoTrip;
public void init()
{
this.daoBooking = ( (DAOFactory) getServletContext().getAttribute(CONF_DAO_FACTORY)) .getBookingDAO();
this.daoBooking = ( (DAOFactory) getServletContext().getAttribute(CONF_DAO_FACTORY)) .getBookingDAO();
}
...
}
The 500 happens when the listener is not active (commented out inside web.xml) and thus daofactory not in servletContext, then trying to reach it returns null, and hence an NPU on .getBookingDAO() call.
However, I have absolutely no idea as to where the 404 comes from.
Anyone has an idea as to its origin, and potential corrections ? Thanks
Edit: the app runs on TomCat 7
Edit 2: As stated in comments, I try to access the page by using indifferently http://localhost/AppName/index or http://localhost/AppName as index is declared a welcome file in web.xml. The method called should be doGet(request, response) which passes the data to the JSP with this.getRequestDispatcher("/WEB-INF/index.jsp").forward(request,response);
I did check that the file existed and was properly named and it might be worth mentionning that another servlet, which behaved properly (both with doGet and doPost) before that does not respond any more when the filter is active
The listener is running before context starts. If the listener throws an exception your context fails and you see just 404 because there is really no application on the requested URI. See catalina.out enable logging to see what's happen.
As pointed by David Levesque and Martin Strejc, the webapp failed to start because of an exception causing the context to fail.
Through log exploration I found that it was caused by the database driver not being loaded properly thus the DAOFactory.getInstance() method to fail and propagating an exception.
Since this was entirely due to not properly setting up my project in the first place, I'm not sure the question si relevant any more.
I am using jersey for a REST WS. How do I enable jersey logs at server side?
Long story:
I get a clientside exception - but I don't see anything in tomcat logs [It doesn't even reach my method]. Since the stack trace is saying "toReturnValue" it did get something from server. But I don't know what the server said.
Exception in thread "main" java.lang.IllegalArgumentException: source parameter must not be null
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:98)
at com.sun.xml.internal.ws.message.AbstractMessageImpl.readPayloadAsJAXB(AbstractMessageImpl.java:100)
**at com.sun.xml.internal.ws.client.dispatch.JAXBDispatch.toReturnValue(JAXBDispatch.java:74)**
at com.sun.xml.internal.ws.client.dispatch.DispatchImpl.doInvoke(DispatchImpl.java:191)
at com.sun.xml.internal.ws.client.dispatch.DispatchImpl.invoke(DispatchImpl.java:195)
If you want to turn on logging on the server side, you need to register the LoggingFilter Jersey filter (on the container side).
This filter will log request/response headers and entities.
Here's what you need to add to your ResourceConfig class:
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
// Resources.
packages(MyResource.class.getPackage().getName());
register(LoggingFilter.class);
}
}
Note that the same filter also works on the client side.
Client client = Client.create();
client.addFilter(new LoggingFilter());
Jersey 2 has deprecated LoggingFilter and you now need to use LoggingFeature. In order to use it with a client you can use the following snipette:
this.client = ClientBuilder
.newBuilder()
.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT, LoggingFeature.Verbosity.PAYLOAD_ANY)
.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT, "WARNING")
.build();
and on the server side:
ResourceConfig config = new ResourceConfig(HelloWorldResource.class);
config.register(LoggingFeature.class);
Jersey 2.0 uses org.glassfish.jersey.filter.LoggingFilter
You can connect it with help of web.xml
<!-- Register my custom provider (not needed if it's in my.package) AND LoggingFilter. -->
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter</param-value>
</init-param>
More explanations can be found here
upd:
After version 2.23 LoggingFilter is deprecated and LoggingFeature should be used.
More info can be found in official documentation
For Jersey 1.2 add the following entry into web.xml inside the servlet tag:
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
</init-param>
Could you show us your client code and tell us about the request as well?
This exception seems to point at the JAXB unmarshalling step. Apparently you received some XML from your REST API, but you don't get what you're waiting for.
Maybe the XSD you're using for marshalling/unmarshalling is outdated or just plain wrong.
Maybe you're trying to get the wrong entity from the response.
Try these steps and give us some more details about your problem:
Get the XML from the response
Using a REST client like Client REST simple (a chrome extension), or your code:
Builder builder = webResource.path("/yourapi/").accept("application/xml");
// get the client response
ClientResponse response = builder.get(ClientResponse.class);
// log the HTTP Status
logger.log("HTTP Status: " + response.getStatus());
// bypass the jaxb step and get the full response
// MyResource myResource = response.getEntity(MyResource.class);
String myResource = response.getEntity(String.class);
logger.log(myResource);
Validate this XML with the XSD you're using
This test should fail (if I'm right).