BMTD 's Yard of Fun

Technology, Sports, Music, Chinese Essays

Browsing Posts in Technology

One recent problem I encountered was that I had to write a PERL client for an existing document/literal web service. The service is using polymorphism– there are two methods:

Product[] getProducts1(Products[] products1);
Product[] getProducts2();

“Product” is only an interface. Product1 and Product2 are concret classes that implement the “product’ interface. and the objects in the products array are either Product1 objects or Product2 objects;

Interface Product {
    public String getName();
    public void setName(String name);
    public void setIndex( int index);
    public int getIndex();

}

class Product1:Product{
...
}

class Product2:Product{
...
}

By default Soap::lite sends RPC/Encoding messages to the web services. Fortunately there are some resources for how to call a document/literal services such as this MSDN article . The client perl snippet I have below can call the second method “getProducts2” and retrieve the products succesfully:

#!perl -w
  use SOAP::Lite +trace => 'debug';

  my $soap_response = SOAP::Lite
    -> uri('http://localhost:2372/jaxrpc-simple/types')
   -> on_action( sub { join '/', 'http://localhost:2372/jaxrpc-simple/types', $_[1] } )
    -> proxy('http://mmpower:2372/jaxrpc-simple/simple')
    ->getProducts2();

if ($soap_response->fault) {
    print $soap_response->faultcode, " ", $soap_response->faultstring, "\n";
}    

  print $soap_response;
  $results =   $soap_response->result;

for my $t ($soap_response->valueof('//getProducts2Response/result')) {
  while ( my ($key, $value) = each(%$t) ) {
        print "$key => $value\n";
    }
}    

#use custom deserializer to deserialzie it ro objects if necessary
...

But still I don’t know how to call the first method since I need to pass an array of “Products” as a parameter; As suggested in OO Perl packages are used as classes, and objects are normally blessed references of arrays or hashes. This is not straight forward though. After try and error multiple times finally the following code works:

use Tie::IxHash;

{
package Product2;
    sub new {
        my $class = $_[0];
        my %objref;
        $t = tie(%objref, Tie::IxHash);
        %objref = (
                     index    => $_[1],
                     name  => $_[2],
                     ppp => $_[3]
                 );

    bless \%objref, $class;
    return \%objref;
    }

}

{
package Product1;

    sub new {
        my $class = $_[0];
        my %objref;
        $t = tie(%objref, Tie::IxHash);
        %objref = (
                     index    => $_[1],
                     name  => $_[2],
                     ooo => $_[3],
                 );
        @keys = keys %objref;
    @values = values %objref;
    bless \%objref, $class;
    return \%objref;
    }

}

use SOAP::Lite ( +trace => 'debug', maptype => {} );

my $service1 = SOAP::Lite
    -> uri('http://localhost:2372/jaxrpc-simple/types')
   ->maptype({Product1=>'http://localhost:2372/jaxrpc-simple/types', Product2=>'http://localhost:2372/jaxrpc-simple/types', SOAPStruct => 'http://localhost:2372/jaxrpc-simple/types'})
   -> on_action( sub { join '/', 'http://localhost:2372/jaxrpc-simple/types', $_[1] } )
    -> proxy('http://localhost:2372/jaxrpc-simple/simple');

    $service1->serializer->namespaces({"http://schemas.xmlsoap.org/soap/encoding/"=>"SOAP-ENC",
                                        "http://schemas.xmlsoap.org/soap/envelope/"=>"SOAP-ENV","http://www.w3.org/2001/XMLSchema"=>"xsd",
                                        "http://www.w3.org/2001/XMLSchema-instance"=>"xsi"});

my @products;

@products[0] = Product1->new(2,'pro1','ooo1');
@products[1] = Product2->new(3,'pro2','ppp1');
@products[2] = Product1->new(4,'pro3','ooo3');
@products[3] = Product2->new(5,'poro4','pppll4');

my @params = ( SOAP::Data->name("arrayOfProduct_1" => @products)->attr({xmlns => ''}));

my $method = SOAP::Data->name('getProducts')-> attr({xmlns => 'http://localhost:2372/jaxrpc-simple/types'});

$soap_response = $service1->call($method => @params);

if ($soap_response->fault) {
    print $soap_response->faultcode, " ", $soap_response->faultstring, "\n";
}    

for my $t ($soap_response->valueof('//getProductsResponse/result')) {
  while ( my ($key, $value) = each(%$t) ) {
        print "$key => $value\n";
    }
}

Several things to note in the above code:

  • needs to use the “maptype()” method to map the namespace for the Product1 and Product2.
  • need to change the XSD and XSI namespaces to 2001 version. by default soap::lite sets them to “http://www.w3.org/1999/XMLSchema” and “http://www.w3.org/1999/XMLSchema-instance”;
  • since object instance variable is stored in a hash. In perl the default Hash does not gurantee hash key order, so when a “Product1” object is passed as a parameter, the generated soap message is like:
            1
           oooooo
         prodcut1
    
    

    but the server side expects the elements of a product to be in the strict order “index”, “name” and “ooo”, not “index”, “ooo” and “name”. So I have to use a special hash that preserves the key order.

continue reading…

In Spring IOC framework you can define bean properties of some collection types, such as List, Set, Propertie and Map. For example, for a bean that has a property “theList” of type “java.util.ArrayList”, you can specify the value as below:

<bean id="exampleBean" class="examples.ExampleBean">
    <property name="theList">
              <list>
                     <value type="java.lang.String">a String</value>
                     <value type="java.lang.Interger">100</value>
              </list>
       </property>
</bean>

This is fine. But if the “theList” is a java.util.Vector then the above won’t work because by default the List FactoryBean uses an ArrayList and can’t convert a java.util.ArrayList to java.util.Vector– you will get a conversion exception.

It seems Spring does not support “Vector” property type directly. You have to either define a custom PropertyEditor for Vector, or, work around it with something like below:

<property name="theList" >
                 <bean class="java.util.Vector">
                            <constructor-arg >
                                     <value type="int">2</value>
                            </constructor-arg>
                  </bean>
  </property>
  <property name="theList[0]" >
                <value type="java.lang.String">a String</value>
  </property>
  <property name="theList[1]" >
                <value type="java.lang.Integer">100</value>
  </property>

Or a better way like this:

<property name="theList" >
                 <bean class="java.util.Vector">
                            <constructor-arg >
                                     <list>
                                            <value type="java.lang.String"> a String</value>
                                            <value type="java.lang.Integer"> 100  </value>
                                     </list>
                            </constructor-arg>
                  </bean>
  </property>

刚写了个小工具可用于将escaped unicode中文乱码(中文字变成好像舵那样的)还原成中文。在非中文操作系统上用yahoo 之类的web mail client发中文邮件时接受方经常会收到这样的乱码;用此工具就可以方便地将其还原成中文显示了。

“转换器”在这里: http://www.smartpeer.net/jiescripts/decode.php.

I tried to import my firefox bookmarks into blogrolling and found that it only accepts OPML but not html. So i wrote a small utility that converts html to opml.

html2opml is a php script that simply converts html to a opml file, and every URL in the HTML input will become an entry in the generated OPML. Since most entries in my bookmarks does not have RSS feeds only “link” type opml outlines with “Url” attribute are created.

The html2opml online utlility is at http://www.smartpeer.net/jiescripts/html2opml.php

Ganux simulates a linux terminal through a browser. According to the author: “I have changed it into a hacking-game. The objective of this game is to gain root of this “machine”. I can assure you that this’s not easy! A surprise will be given to those who can hack into it!”

So this is a minimum operating system running on the browser– quite interesting. I spent some time to look into the javascript code to find the secret there. Apparently it’s not difficult– basically it uses javascript to encrypt the passwords. We just need to get the password file (that’s easy if you understand the code) — the file is in unix password format and encrypted using crypt(3) algorithm. Then use a password cracker such as John the Ripper to crack the root password– that may need several days or longer depends on your machine speed and dictionary size.

The author of Ganux is also the authour of the open source PHP gmail lib, a very useful library– combining ganux and gmail will be cool– imagine we have an OS running on the web browsers and the underlying file sytem is using GMail as the storage…