Restlet and consuming/storing files - java

How would one handle consuming an attachment from a client POST/PUT request on the server side and store that file in a local folder, all using Restlet ?
My thoughts are as follows:
Setup Server as follows:
new MailServerComponenet.start();
public MailServer(){
getServers().add(Protocol.HTTP, 8111);
getDefaultHost().attachDefault(new MailServer());
server.getContext().getParameters().set("tracing", "true");
}
#Put
public void store(Form form){
// *And here is where I am not sure*
}
Thanks for any insight and help in advance.

Here are the following steps you should follow to implement your Restlet application:
Create a component
Component component = new Component();
Create an application and attach it on the component
component.getServers().add(Protocol.HTTP, 8182);
Application application = new MyApplication();
component.getDefaultHost().attachDefault(application);
component.start();
Configure the application within the method createInboundRoot (create a router and attach server resource on it)
public class MyApplication extends Application {
#Override
public Restlet createInboundRoot() {
Router router = new Router();
router.attach("/test", MyServerResource.class);
return router;
}
}
Implement the server resources
public class MyServerResource extends ServerResource {
#Post
public Representation handlePost(Representation repr) {
(...)
}
}
Now the global frame is implemented, I would wonder how you would send the content to Restlet. Is it simple binary content within the request payload or multi-part content?
Binary content
#Post
public Representation handlePost(FileRepresentation fileRepr) {
fileRepr.write(new FileOutputStream(
new File("/tmp/myfile.txt")));
return null;
}
Multipart content. You can have a look at this answer in this case: File Upload with Description in Restlet
Hope it helps you,
Thierry

Related

How to create a multipart form post request handler in vertx

Hello I am using vertx in java on a standalone app to read a port in my web app. I want to get the post data from a form.
My web app has a form with a post method that I am looking to read.
My logic is
Create verticle
Create http Server
Create handler request ( it does not take all the parameters in my
code)
Listen to httpServer
Expect Multipart Request in Handler
Multimap and get form attributes
I dont know what I am missing , I am new to vertx .
For some reason I cannot post code on here.
My code:
https://pastebin.com/A1hjXFb6
Make sure that your HTML form is having enctype="multipart/form-data" attribute.
Then in your vertx code:
public class loginLogic extends AbstractVerticle {
//Vertx vertx;
private HttpServer httpServer = null;
#Override
public void start() {
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create().setUploadsDirectory("uploads"));
router.post("/form").handler(ctx -> {
ctx.response().putHeader("Content-Type", "text/plain");
ctx.response().setChunked(true);
for (FileUpload f : ctx.fileUploads()) {
System.out.println("f");
ctx.response().write("Filename: " + f.fileName());
ctx.response().write("\n");
ctx.response().write("Size: " + f.size());
}
ctx.response().end();
});
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
}
}

Swagger not working

I'm having a bit of trouble making Swagger display API docs using Restlet. What Swagger shows is just these stuff:
And checking the api-docs it only shows this:
I wonder what is wrong with my code:
public class MyApplication extends SwaggerApplication {
private static final String ROOT_URI = "/";
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach(ROOT_URI, RootServerResource.class);
router.attach(ROOT_URI + "ping", PingServerResource.class);
router.attach(ROOT_URI + "ping/", PingServerResource.class);
// Some code omitted for simplicity
return router;
}
}
You could have a look at this article:
What can APISpark bring to your existing Web APIs (Part 2) -http://restlet.com/blog/2016/01/04/what-can-apispark-bring-to-your-existing-web-apis-part-2/
Both Swagger1 and 2 are supported by the Swagger extension of Restlet:
Swagger v1
public class ContactsApplication extends SwaggerApplication {
public Restlet createInboundRoot() {
Router router = new Router();
(...)
attachSwaggerSpecificationRestlet(router, "/docs");
return router;
}
}
Swagger v2
public class ContactsApplication extends Application {
public Restlet createInboundRoot() {
Router router = new Router();
(...)
Swagger2SpecificationRestlet swagger2SpecificationRestlet
= new Swagger2SpecificationRestlet(this);
swagger2SpecificationRestlet.setBasePath("http://myapp.org/");
swagger2SpecificationRestlet.attach(router, "/docs");
return router;
}
}
The solution is to add this code:
// Configuring Swagger 2 support
Swagger2SpecificationRestlet swagger2SpecificationRestlet
= new Swagger2SpecificationRestlet(this);
swagger2SpecificationRestlet.setBasePath("http://localhost:8080/api-docs");
swagger2SpecificationRestlet.attach(router);
And point the Swagger UI to /swagger.json
Swagger needs to find your API operations. I'm not sure about Restlet, in Jersey you annotate your REST resource classes with #Api and your methods with #ApiOperation. Read more here in the swagger docs.

Restlet URI Pattern

I work on 2.1-M7 version of Restlet (I have to update it but this is an another problem)
I use directly Restlet, without any webserver before it Starting a component. Adding some virtualhosts on it.
And in the host I add entrypoints with method attach(string uriPattern, Restlet entrypoint)
My problem is :
When I add with attach the uri "/test" with the entrypoint Test.class (with a method who print : "hello world") with a curl I can call "/testmeagain" and it's work (return "hello world") because it's a pattern?
So I use this : http://docs.oracle.com/javase/1.5.0/docs/api/java/util/regex/Pattern.html?is-external=true
And try "/test$" but in curl "/test" and "/testmeagain" return 404 now
Maybe I miss something?
Thank you if you have any suggestion or response to help me.
In fact, in Restlet, there is a matching mode for routes. Here is the behavior in the framework:
When you attach a route on a virtual, the default mode is "STARTS WITH". So with something like attach("/test", ...), URLs like /test and /testsomething will match.
When you attach a route on a router, the default mode is "EQUALS". So with something like attach("/test", ...), only URL /test will match.
The attach method returns a template route on which you can change this matching:
TemplateRoute route = component.getDefaultHost().attach(
"/test", new Restlet() {
#Override
public void handle(Request request, Response response) {
response.setEntity("test", MediaType.TEXT_PLAIN);
}
});
// Default matching mode
int defaultMatching = route.getMatchingMode();
// Set another matching mode
route.setMatchingMode(Template.MODE_EQUALS);
In fact, it's more usually to implement a Restlet application and attach it to a virtual host on the component. In this case, you will have exact matching.
Here is the way to do:
Component component = new Component();
(...)
MyRestletApplication application = new MyRestletApplication();
component.getDefaultHost().attachDefault(application);
Here is a sample content for the application:
public class MyRestletApplication extends Application {
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
TemplateRoute route = router.attach("/test", MyServerResource.class);
// Default matching mode
int defaultMatching = route.getMatchingMode();
return router;
}
}
And the content of the server resource:
public class MyServerResource extends ServerResource {
#Get
public String test() throws Exception {
return "test";
}
}
Hope it helps you,
Thierry

Retrieve a list of entities from a Restfull service (inside client app)

Im new to Rest web services and say Ive created this web service using Netbeans
#Path("browse")
#Stateless
public class ArticleBrowseResource {
#EJB
private ArticleSearcherLocal ejbRef;
#GET
#Produces(MediaType.APPLICATION_XML)
public List<Article> browse(#DefaultValue("") #QueryParam("username") String username,#QueryParam("sd") String sd) {
// convert sd string to date
List<Article> articles = ejbRef.search(username, date);
return articles;
}
}
where Article is an entity which is anotated with #XmlRootElement
Now how am I supossed to retreive this list of articles in my client which for simplicity lets just say it is a java standard application? In SOAP web services I know that these objects are automatically generated but not in Rest.
This is the client class generated for this service by Netbeans
public class ArticleBrowseClient {
private WebResource webResource;
private Client client;
private static final String BASE_URI = "http://localhost:8080/cityblog/rest";
public ArticleBrowseClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig();
client = Client.create(config);
webResource = client.resource(BASE_URI).path("browse");
}
public <T> T browse(Class<T> responseType, String username, String sd) throws UniformInterfaceException {
WebResource resource = webResource;
if (username != null) {
resource = resource.queryParam("username", username);
}
if (sd != null) {
resource = resource.queryParam("sd", sd);
}
return resource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public void close() {
client.destroy();
}
}
What is the best and simplest way to resolve this issue?
Any help is appreciated and
thx in advance
Please try fewer code generation and more understanding of what you are actually doing. On the server, you generate a XML message with help of JAXB. On the client side, you can consume this XML with a programming language and library you like. Just use tools like curl to see what is going actually over "the wire". Your generated client site looks fully reasonable. You just need your Article class from the server side on the client side. The generated code uses Jersey which can read XML messages per JAXB per default. So just drop your server side Article class in your client side classpath and use it. But please also have a look at the wire level protocol to understand the portability of your REST API.

Trace SOAP request/responses with JAX-WS on the client side

I'm using JAX-WS reference implementation (2.1.7) and I want to trace SOAP request/responses on the client side. Actually, what I need is to examine some Http headers when I receive the response.
Following these previous questions ( Tracing XML request/responses with JAX-WS and Java JAX-WS web-service client: how log request & response xml? ), I've created my own handler to log when I send a request and receive a response:
public class SHandler implements SOAPHandler<SOAPMessageContext>
{
private static final Logger log = Logger.getLogger(SHandler.class);
#Nullable
#Override
public Set<QName> getHeaders()
{
log.debug(">>>>>>>>>>> GetHeaders");
return null;
}
#Override
public boolean handleMessage(SOAPMessageContext soapMessageContext)
{
log.debug(">>>>>>>>>>> HandleMessage");
return true;
}
#Override
public boolean handleFault(SOAPMessageContext soapMessageContext)
{
log.debug(">>>>>>>>>>> HandleFault");
return true;
}
#Override
public void close(MessageContext messageContext)
{
log.debug(">>>>>>>>>>> Close");
}
}
and I add the handler to the handler chain during the service initialisation:
#WebServiceClient(name = "MyService", targetNamespace = "http://www.whatever.com/", wsdlLocation = "file:/path/to/wsdl")
public class MyService extends Service
{
public MyService(URL wsdlLocation) {
super(...);
initializeBinding();
}
#WebEndpoint(name = "MyOperation")
public MyPort getMyPort() {
return super.getPort(new QName("http://www.whatever.com/", "MyPort"), MyPort.class);
}
private void initializeBinding() {
MyPort port = getMyPort();
BindingProvider bindingProvider = ((BindingProvider) port);
List handlerChain = bindingProvider.getBinding().getHandlerChain();
handlerChain.add(new SHandler());
bindingProvider.getBinding().setHandlerChain(handlerChain);
}
...
}
The problem is that this doesn't work at all on the client side. I don't see any logs and my handler is never executed when I send a request and receive a response.
Notice that there is no specific WSDL related to this issue because I work on an MDA platform that generates client/server artifacts from any WSDL. In addition, I cannot do this at configuration level as all is generated, so I can only do it programmatically (I've been googling this and all the solutions that I find are either the one in the original post or using the handler-chain.xml configuration file).
Am I missing something? Is there any other way of doing this?
Thanks in advance.
If you only want to look at the SOAP messages run with
-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
VM argument.
Why not use #HandlerChain(file = "....") annotation?
From my pov, you can not mix constructor- and annotation-based configurations as on-deploy webservice initialization and creating new instance of your service class are performed in absolutely different contexts.
there are 2 tools that you can use to help with this:
soapui
Eclipse tcp/ip monitor
Both tools offer a proxy mode, which intercepts, logs and forwards requests and responses.

Categories

Resources