Pages

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.

Thursday, May 30, 2013

SOAP client on Android using JiBX

Android has no native support for SOAP web services or even XML binding. Sometimes however, your application may be required to utilize web services. In this post I will show you how to consume SOAP web service using JiBX on Android device. First what we need is JiBX (link). You need to download core library and jibx-ws.

Next step is to generate classes form schema (xsd file) of service with witch you want comunicate. You may find the link to schema in WSDL file or you may be required to extract the schema from WSDL file. Now we can use the code generator which you can find in jibx/lib directory of downloaded achieves. Copy schema.xsd extracted from the service definition file (WSDL) to the jibx/lib directory and run the following command:
java -cp jibx-tools.jar org.jibx.schema.codegen.CodeGen schema.xsd
The generated code will appear. Next you need to compile those files. You may do this using javac compiler or import it into your IDE. The last thing is to add binding information to those class. Generator besides the java source code was generate the binding.xml file. Copy this file to the root of your compilation output folder (where the *.class files are). Open this location in command window and run the command:
[pathToYourClassOutputFolder]>java -jar [pathToJiBXlib]\lib\jibx-bind.jar binding.xml
That's it. You are ready to start developing your android application. The above instructions requires the less configuration of all the known to me methods of creating the bindings with JiBX and doesn't bind to any IDE. You can find more information here and here.
Let's return to Android app. You need to add the binded classes to your project (don't add source java files if you not going to add step to run the binding operation with every compilation). You need also add the following jars (and only them) to your project library:
jibx-run.jar from jibx core
jibx-ws.jar from jibx-ws
The last step is the activity code. Lets assume that the QueryRequest is a class representing the root of one of the operation (it comes from classes generated from schema) and QueryResponse is the class representing the root of response to QueryRequest.
public class MyActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        new RunWSCommand().execute();
    }

    private class RunWSCommand extends AsyncTask {        

        @Override
        protected Object doInBackground(Object... objects) {
            IBindingFactory fact = null;
            try {
                fact = BindingDirectory.getFactory(QueryRequest.class);
                Client client = new SoapClient("http://web.adress.to.web.service.com/", fact); //client will build the SOAP envelope for us
                QueryRequest query=new QueryRequest();
                query.setName("Mike"); // add the parameter to request.
                return (QueryResponse) client.call(query);
            } catch (Exception e) {
                e.printStackTrace(); 
                return null;
            }
        }
    }
}
No network operation can be run in main thread hence I use the AsyncTask here. The INTERNET permission request must also be find in AndroidManifest.xml file to run this code.

Saturday, March 30, 2013

Using WS-Adressing in JAX-WS 2.x client

This is quick code example presented how to setup WS-Addressing policy in JAX-WS applications.

Let's start form server side code. The addressing is enabled by default, so if client will send the message with addresing header the sever will reply correctly, but the policy is not included into generated WSDL. To explicite enable the support of WS-Addressing you need to annoted your service implementation bean (SIB) wih @Addressing. So example webservice implementation code may looks like this:
@WebService
@Addressing(required = true)
public class HelloWorld {

  @WebMethod
  public String sayHelloWorldFrom(String from) {
    String result = "Hello, world, from " + from;
    return result;
  }
}
And that is all. The binding element of JAX-WS generated WSDL will have UsingAddressing element:
<definitions xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
....
name="HelloWorldService">

<!--types, messages, portType are ommited for readability-->
    <binding name="HelloWorldPortBinding" type="tns:HelloWorld">
        <wsaw:UsingAddressing required="true"/>
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding>
        <operation name="sayHelloWorldFrom">
            <soap:operation soapAction=""></soap:operation>
            <input>
                <soap:body use="literal"></soap:body>
            </input>
            <output>
                <soap:body use="literal"></soap:body>
            </output>
        </operation>
    </binding>
    <service name="HelloWorldService">
        <port name="HelloWorldPort" binding="tns:HelloWorldPortBinding">
            <soap:address location="http://127.0.0.1:9000/HelloWorldService"></soap:address>
        </port>
    </service>
</definitions>
Now, what need you to do enable addressing feature on client? It depends if you use the wsimport service and port artifacts then the answer is: absolutly nothing! Even if you generate it from WSDL without UsingAddresing element as there is no changes in JAXB classes. Only runtime artifacts are affected. Here is the client code:
public class JaxWsClient {
    public static void main(String[] args){
        HelloWorldService service=new HelloWorldService();
        HelloWorld port=service.getHelloWorldPort();
        System.out.println(port.sayHelloWorldFrom("JaxWxClient"));
    }
}
After running it the following messages will be exchanged:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <To xmlns="http://www.w3.org/2005/08/addressing">http://127.0.0.1:9000/HelloWorld</To>
        <Action xmlns="http://www.w3.org/2005/08/addressing">http://example/HelloWorld/sayHelloWorldFromRequest</Action>
        <ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
            <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
        </ReplyTo>
        <MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:d54cb478-fdd1-4495-84df-2fde515a4591</MessageID>
    </S:Header>
    <S:Body>
        <ns2:sayHelloWorldFrom xmlns:ns2="http://example/">
            <arg0>JaxWxClient</arg0>
        </ns2:sayHelloWorldFrom>
    </S:Body>
</S:Envelope>
and response:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <To xmlns="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/anonymous</To>
        <Action xmlns="http://www.w3.org/2005/08/addressing">http://example/HelloWorld/sayHelloWorldFromResponse</Action>
        <MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:a95c9cff-7b9f-4f23-9608-fe1ca9ce1d75</MessageID>
        <RelatesTo xmlns="http://www.w3.org/2005/08/addressing">uuid:d54cb478-fdd1-4495-84df-2fde515a4591</RelatesTo>
    </S:Header>
    <S:Body>
        <ns2:sayHelloWorldFromResponse xmlns:ns2="http://example/">
            <return>Hello, world, from JaxWxClient</return>
        </ns2:sayHelloWorldFromResponse>
    </S:Body>
</S:Envelope>

However if you try to develop dynamic client using dispacher, for example:
public class JaxWsClient {
    public static void main(String[] args) throws SOAPException {
        QName serviceName=new QName("http://example/","HelloWorldService");
        QName portName=new QName("http://example/","HelloWorldPortBinding");
        Service service = Service.create(serviceName);
        service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING,"http://localhost:9000/HelloWorld");
        Dispatch dispatch = service.createDispatch(portName,SOAPMessage.class,Service.Mode.MESSAGE);
        MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
        SOAPMessage request = mf.createMessage();
        SOAPPart part = request.getSOAPPart();
        SOAPEnvelope env = part.getEnvelope();
        SOAPBody body = env.getBody();
        SOAPBodyElement element = body.addBodyElement(new QName("http://example/","sayHelloWorldFrom"));
        SOAPElement arg=element.addChildElement(new QName("http://example/","arg"));
        arg.addTextNode("JaxWxClient");
        request.saveChanges();
        SOAPMessage response=dispatch.invoke(request);
    }
}
Then when you try to run it you will receive the SOAP fault:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <FaultDetail xmlns="http://www.w3.org/2005/08/addressing">
            <ProblemHeaderQName>{http://www.w3.org/2005/08/addressing}Action</ProblemHeaderQName>
        </FaultDetail>
        <To xmlns="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/anonymous</To>
        <Action xmlns="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/fault</Action>
        <MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:713f84a8-2dbf-44a7-936c-d445bfb890df</MessageID>
    </S:Header>
    <S:Body>
        <SOAP-ENV:Fault xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
            <faultcode xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
                       xmlns:ns0="http://www.w3.org/2005/08/addressing" xmlns="">ns0:InvalidCardinality</faultcode>
            <faultstring xmlns="">A header representing a Message Addressing Property 
                is not valid and the message cannot be processed</faultstring>
        </SOAP-ENV:Fault>
    </S:Body>
</S:Envelope>
It is required to enable the addressing support on created dispatcher and set required correct SOAPAction. To do this you need to change the client code to:
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,SOAPMessage.class,Service.Mode.MESSAGE,new AddressingFeature());
and add:
dispatch.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY,true);
dispatch.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY,"http://example/HelloWorld/sayHelloWorldFromRequest");
The value of Action used here is the default one which is created in case of absence the custom one. It is build by appending together: target namspace, service name and operation name and string "Response" or "Request". You may find it in WSDL in Action attribute of the input/output/fault element in binding section. After those changes the request will look like the previously presented. You not required to create the address header by yourself. But wait a moment! SOAPAction HTTP Header and WS-Addressing Action header are two different things! Yes, they are. Moreover SOAPAction is set for the operation, and WSA Action may be different for each message in that specific operation. But when it comes to request where we use the SOAPAction and WSA Action then the recommendation requires that both of them are equal or SOAPAction was set to empty string - "". 


Float to double conversion in Java

The first thing what we learn about representation of real number in computer systems is that it is only an approximation. Some of the real numbers cannot be expressed as floating point number (see this converter). How accurate our approximation is depends how many bytes we use to represent it. That is why you may be surprised about the result of the flowing code:
float fvar=0.1f;
double dvar=(double)fvar;
System.out.print("Are these number equal? ");
System.out.println(dvar==fvar);
System.out.println("Really?");
System.out.println("Float: "+fvar);
System.out.println("Double: "+dvar);
Are these number equal? true
Really?
Float: 0.1
Double: 0.10000000149011612
So if you need to convert some floats number to double and you would like to be sure that you won't scare your customer by charging her $99.99999998989 (quite easy to miss the dot) you need to convert floats to doubles by other means.

There are a three popular ways of doing this:
float fvar=0.1f;

//1. Convert float variable to string and then parse it as a double 
Double.parseDouble(new Float(fvar).toString());

//2. Use FloatingDecimal class
new sun.misc.FloatingDecimal(fvar).doubleValue();

//3. Use BigDecimal class 
new BigDecimal(String.valueOf(fvar)).doubleValue();
All of them do the work. The question is which one is the fastest? I've used the Brent Boyer's microbenchmark to answer this question. Here is the result. As you can see the method uses the FloatingDecimal class is the quickest one.


Sunday, October 7, 2012

Performance of string comparison in Java

Have you ever wonder how fast Java can compare two strings? Which method is the best? The answer is.... it depends what you are compare. Let's do some tests. We will try to compare the intern strings and dynamic created by both '==' and equals methods. Here is the code which do the checking:
String s1 = "test";
String s2 = "test";
String s3 = s1 + "";
String s4 = s3 + "";
String s5 = s4;
long iterations = 100000000;
long time = System.currentTimeMillis();

for (int i = 0; i < iterations; i++) {
    if (s1 == s2);
}
System.out.println("s1==s2: " + (System.currentTimeMillis() - time));

time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s1 == s3.intern());
}
System.out.println("s1==s3.intern(): " + (System.currentTimeMillis() - time));

for (int i = 0; i < iterations; i++) {
    if (s1.equals(s3.intern()));
}
System.out.println("s1.equals(s3.intern()): " + (System.currentTimeMillis() - time));

time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s1.equals(s2));
}
System.out.println("s1.equals(s2): " + (System.currentTimeMillis() - time));

time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s1.equals(s3));
}
System.out.println("s1.equals(s3): " + (System.currentTimeMillis() - time));
time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s3.equals(s1));
}
System.out.println("s3.equals(s1): " + (System.currentTimeMillis() - time));

time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s3.equals(s4));
}
System.out.println("s3.equals(s4): " + (System.currentTimeMillis() - time));

time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s3.intern() == s4.intern());
}
System.out.println("s3.intern()==s4.intern(): " + (System.currentTimeMillis() - time));
time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s3.intern().equals(s4.intern()));

}
System.out.println("s3.intern().equals(s4.intern()): " + (System.currentTimeMillis() - time));
time = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
    if (s5 == s4);
}
System.out.println("s5==s4: " + (System.currentTimeMillis() - time));
}
And the result is:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
s1==s2: 95
s1==s3.intern(): 12925
s1.equals(s3.intern()): 25778
s1.equals(s2): 88
s1.equals(s3): 90
s3.equals(s1): 89
s3.equals(s4): 314
s3.intern()==s4.intern(): 26148
s3.intern().equals(s4.intern()): 26083
s5==s4: 310

So as you can see there is no big difference in comparison strings using reference comparison nd equals method (test 1 and  4 for intern strings, 7 and 10 for dynamically created). What is interesting that comparing two dynamically created string is takes nearly 3.5 times longer than in case when at least of the arguments is intern string. As you can also see using the intern() method is really time consuming. The interesting result is also comparison of the second and third case. Why the time is more than doubled when equals is used?

Now, lets check how the results change when we use the longer string. The same tests but now s1 and s2 strings are 248 characters long.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
s1==s2: 135
s1==s3.intern(): 187042
s1.equals(s3.intern()): 374946
s1.equals(s2): 90
s1.equals(s3): 89
s3.equals(s1): 89
s3.equals(s4): 316
s3.intern()==s4.intern(): 373573
s3.intern().equals(s4.intern()): 374662
s5==s4: 311

The results are quite surprising. The equals() method doesn't depend on the length of its arguments! However the intern() method needs much more time.

Saturday, October 6, 2012

SvcUtils generates incorect code with multidimensional arrays

There may be situation when you need create .NET client for some webservice. The easiest way is to get the WSDL file and generates the clients using SvcUtils.exe tool. In most cases it everything goes fine and you can quickly finish your work. But there is a special case when the SvcUtils and its predecessor - wsdl.exe will fail.

Lets assume that schema contains such element:
<xs:element name="Description" minOccurs="0" maxOccurs="unbounded">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="Text" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
SvcUtils tries to be smart and generates:
private string[][] text;

[System.Xml.Serialization.XmlArrayAttribute(Order = 1)]
[System.Xml.Serialization.XmlArrayItemAttribute("Text", typeof(string), IsNullable = false)]
public string[][] Description {
    get {
        return this.text;
    }
    set {
        this.text = value;
    }
}
OK, nearly great. But when you try to use this code you experience the cast exception as there won't be possibility of casting string to string[]. The typeof parameter of XmlArrayItemAttribute is wrong! The attribute is an array of arrays, then the correct type is string[]!

Quick changes is enough to make the code work properly. But if you are the author of the service and wont to your user to avoid doing this there is one simple solution - just move the occurrences definition from Text element and place it in sequence node, that is:
<xs:element name="Describtion" minOccurs="0" maxOccurs="unbounded">
    <xs:complexType>
        <xs:sequence minOccurs="0" maxOccurs="unbounded">
            <xs:element name="Text" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
</xs:element>
After this SvcUtils will generate separate class for Description element and everything will work out of the box.