Pages

Showing posts with label tips & tricks. Show all posts
Showing posts with label tips & tricks. Show all posts

Wednesday, May 21, 2014

How to use the WS-Addressing in OneWay method with JAX-WS

It is a continuation of the previous post about WS-Addressing where I describe how to enable the WS-Addressing in client . Here I am going to show you how to make use of it. In this example I will create the Web Service with two one way methods. Here is my SEI:

import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

@WebService(wsdlLocation = "wsdlWithoutReplyToHeadr.wsdl")
public interface Hello {

    @WebMethod
    @Oneway
    public void callbackMessage(String msg);

    @WebMethod
    @Oneway
    public void sayHello(String name,
            @WebParam(header = true,
                    name = "ReplyTo",
                    targetNamespace = "http://www.w3.org/2005/08/addressing")
                    W3CEndpointReference w3cEpr);
}

The first doesn't required explanation. But there is an interesting thing in the second one. The special class W3CEndpointReference is used as the parameter of that method. From the WebParam annotation you see that this class will be created from the {http://www.w3.org/2005/08/addressing}ReplyTo header, which is the one defined in WS-Addressing recommendation which is pointing to the endpoint to which the response should be send to. There is one little problem with this SEI. If we generate the WSDL from it then there would be included this ReplyTo header explicitly. WS-Addressing should be described as a Policy, so this is not acceptable. To handle this we need to create our own WSDL without ReplayTo header in it and set it in wsdlLocation parameter. From such an WSDL we can generate the valid SEI for client. I will not bother with that and I will just create it. I will name it HelloClient:
import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService(name = "Hello")
public interface HelloClient {

    @WebMethod
    @Oneway
    public void callbackMessage(String msg);

    @WebMethod
    @Oneway
    public void sayHello(String name);
}

Now lets take a look at the implementation of the service:
import javax.jws.WebService;
import javax.xml.ws.soap.Addressing;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

@Addressing(required = true)
@WebService(endpointInterface = "com.example.Hello")
public class HelloImpl implements Hello {

    @Override
    public void sayHello(String name,
            W3CEndpointReference w3cEpr) {
        HelloClient proxy = w3cEpr.getPort(HelloClient.class);
        proxy.callbackMessage("Hello "+name);
    }

    @Override
    public void callbackMessage(String msg) {
        System.out.println(msg);
    }

}

The method callbackMessage is simply print the message which it gets. And yes, I am going to call it from the sayHello method, but not directly but as the call to the service. I am using SEI HelloClient create before to create the proxy to the service which implements it. The endpoint address, WSDL and another information required to create it would be get from the W3CEndpointReference provided to this method, which would be build from ReplayTo header from SOAP request. And the last part, lets see the client, which initiates the message exchange:
import com.sun.xml.ws.api.addressing.OneWayFeature;
import com.sun.xml.ws.api.addressing.WSEndpointReference;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;


public class Client {

    public static void main(String[] args) throws Exception {               
        System.setProperty("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", "true");
        URL url = new URL("http://localhost:8080/ws/HelloService?wsdl");
        QName qname = new QName("http://com.example/", "HelloImplService");

        Service service = Service.create(url, qname);
        W3CEndpointReferenceBuilder builder = new W3CEndpointReferenceBuilder();
        builder.address("http://localhost:8080/ws/HelloService");
        builder.serviceName(qname);
        builder.interfaceName(new QName("http://com.example/","HelloImpl"));
        builder.endpointName(new QName("http://com.example/","HelloImplPort"));
        builder.wsdlDocumentLocation("http://localhost:8080/ws/HelloService?wsdl");
         WSEndpointReference replyTo =  
        new WSEndpointReference(builder.build());  
        
        HelloClient hello = service.getPort(new QName("http://com.example/","HelloImplPort"),
                HelloClient.class,
                new AddressingFeature(),
                new OneWayFeature(true,replyTo));        
        hello.sayHello("Michal");
    }
}
The JAX-WS doesn't provide a way to set the header directly in client (you need to use SOAPHandlers to achive this), so I've used an Metro specific API, which is WSEndpointReference and OneWayFeature. This will cause to set the create EPR to be set as ReplyTo header.

When you publish the service and run the client then the message would look like:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Header>
      <To xmlns="http://www.w3.org/2005/08/addressing">http://localhost:8080/ws/HelloService</To>
      <Action xmlns="http://www.w3.org/2005/08/addressing">http://com.example/Hello/sayHello</Action>
      <ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
         <Address>http://localhost:8080/ws/HelloService</Address>
         <ReferenceParameters />
         <Metadata xmlns:wsdli="http://www.w3.org/ns/wsdl-instance" wsdli:wsdlLocation="http://localhost:8080/ws/HelloService?wsdl">
            <wsam:InterfaceName xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsns="http://com.example/">wsns:HelloImpl</wsam:InterfaceName>
            <wsam:ServiceName xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsns="com.example/" EndpointName="HelloImplPort">wsns:HelloImplService</wsam:ServiceName>
         </Metadata>
      </ReplyTo>
      <MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:f1928b28-73b3-41e1-bc95-1a0757af9f19</MessageID>
   </S:Header>
   <S:Body>
      <ns2:sayHello xmlns:ns2="http://com.example/">
         <arg0>Michal</arg0>
      </ns2:sayHello>
   </S:Body>
</S:Envelope>
The EPR would be parsed and provide to service method in w3cEpr parameter and then all the information about the service will be used to create the new client in service (which only for simplicity points to itself) and make a call. And the result will be:
Hello Michal

Tuesday, September 17, 2013

How to print 3 PowerPoint slides with notes on one sheet

Quite popular problem with power point is to print multiple slides one sheet of paper, and when you want print them with notes then you have only one option - one slide per sheet.

In this post I show you the trick and prepare documents with 3 slides on one sheet with notes and without exporting it to word! To do this you will need the virtual PDF printer (I am using the Bullzip PDF Printer here) and Acrobat Reader.

UPDATE: Now I would recommend doPDF as the virtual printer software. It has not only more features but you are able to define custom paper size in its Advanced settings. There is no need to perform the first step described here.  

Let's start. I am using PP 2010 so in other version it may look differently. First what we need to do is to define new printing page size. To do so go: 

Control Panel ->  Device and Printers  

now click any of your printer. After this you will see the Print server properties at the top of the window. Click it, then select A4 page check the Create a new form and name the new form Half A4. In boxes Width and Height set 3.94in 8.15in. You should see on your screen something like this:

Click OK. And open your presentation. The first thing what you need to do is set your new printing page. Open the File -> Print ->  Print Properties. Now you need to set your page page size to Half A4. It depends on what printer you use. In my case this is virtual printer Bullzip PDF Printer and my settings looks like this:


OK, now you see on the print preview that your page doesn't look good. Especially when you select the Notes Pages. To correct the layout open View -> Notes Master: 
   
Fix the layout look like this below:
Close the view, add you notes to your slides. And we may start printing. The first step is to print to PDF, that is why I use the virtual printer. Just print your slides with notes to PDF one per sheet. When you open your this PDF in Acrobat Reader you should see your slides with notes each printed on wide envelope sheet: 

And the last step is printing this 3 pages on one A4 sheet. Open Adobe Reader's printing panel and set Page Scaling to Multiple Pages per sheet, then set Pages per sheet to Custom 1 by 3. 


And you can print your document. Three slides with notes on one sheet of paper.