Wednesday, January 26, 2011

caused by: javax.xml.ws.webserviceexception: wrong binding id: xxx

I noticed many (new getting started) people facing problem of wring binding id. exception cause look like  bellow
caused by: javax.xml.ws.webserviceexception: wrong binding id: http://jsonplugin.googlecode.com/json/ at com.sun.xml.ws.api.bindingid.parse(bindingid.java:260)" 

binding id can be any URL in above exception. It is surly caused by relevant jar (jsonwebservice-ri-jar in case of jsonwebservice) files not in class path of  webapp. Check you have jar in WEB-INF/lib or tomcat endorsed or other endorsed directory's. Or check is your downloaded jar file corrupted.

If your sure you have jar in path,
1) extract jar using any zip tool locate following file
/META-INF/services/com.sun.xml.ws.api.BindingIDFactory
2) Look content of above file. It contains codec binding ID provider.
3) In case of jsonwebservice binding id provider class is com.jaxws.json.codec.JSONBindingIDFactory
4) Provider specify binding URL. E.g : http://jsonplugin.googlecode.com/json/

If all above checks are true, relay something wrong.or it may bug from jax-ws or in coedc.

I will explain how actually it works.

Every web application developer aware of, your application starts with web.xml file. In JAX-WS your specifying listener class "com.sun.xml.ws.transport.http.servlet.WSServletContextListener" when loading this servlet listener, it look for sun-jaxws.xml file.
    private static final String JAXWS_RI_RUNTIME = "/WEB-INF/sun-jaxws.xml";

and start processing it.

sun-jaxws contains entry for endpoint, like

<endpoint name="ChartPortJSON"
implementation="com.googlecode.jsonwebservice.attachment.impl.ChartPortImpl"
binding="http://jsonplugin.googlecode.com/json/" url-pattern="/chart.json" />

Using binding id attribute, servlet listener look for binding provider using ServiceLocator pattern. If there is no such provider your getting exception.

You can simply check what are the provider available in your class path using Service locator.

for(BindingIDFactory provider : ServiceLoader.load(com.sun.xml.ws.api.BindingIDFactory.class)){
provider.parse("BindingId");// E.g: http://jsonplugin.googlecode.com/json/
System.out.println(provider.getClass());
}


Hope it helps.







Monday, January 24, 2011

JAX-WS and json attachment

In this post I am going to explain how create simple soap/http-json codec attachment call.

Assumption:  target user aware of wsimport, wsdl , soap and json.
1)   Create wsdl  with attachment messages

<wsdl:definitions name="Attachment" 
targetNamespace="http://jsonwebservice.googlecode.com/attachment"
  xmlns:tns="http://jsonwebservice.googlecode.com/attachment" 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:json="http://schemas.jsonsoap.org/wsdl/json/"
  xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

<wsdl:types>
    <xsd:schema elementFormDefault="qualified" targetNamespace="http://jsonwebservice.googlecode.com/attachment">
1.1)   Dummy input object for testing.


<xsd:complexType name="TestInput">
  <xsd:sequence>
     <xsd:element name="input" type="xsd:string"/>
   </xsd:sequence>  
 </xsd:complexType>
1.2) Response type definition "html" element is a attachment.  JAX-WS generate DataSource, Source or Image java type based on xmime contnet type.

<xsd:complexType name="HtmlStreamOutput">
   <xsd:sequence>
     <xsd:element name="outputFormates" type="xsd:string"/>
     <xsd:element name="html" type="xsd:base64Binary" xmime:expectedContentTypes="application/html"/>
   </xsd:sequence>
 </xsd:complexType>

 </xsd:schema>
  </wsdl:types>

1.3) Here is mime type with java type mapping.


public static final String JPEG_IMAGE_MIME_TYPE = "image/jpeg"; java Image
    //public static final String PNG_IMAGE_MIME_TYPE = "image/png";java Image
    public static final String GIF_IMAGE_MIME_TYPE = "image/gif";java Image
    public static final String TEXT_XML_MIME_TYPE = "text/xml"; Source
    public static final String TEXT_HTML_MIME_TYPE = "text/html"; DataHandler
    public static final String TEXT_PLAIN_MIME_TYPE = "text/plain"; String
    public static final String APPLICATION_XML_MIME_TYPE = "application/xml"; Source
    public static final String MULTIPART_MIME_TYPE = "multipart/*"; DataHandler
 

1.4) Then define all fancy wsdl message port and binding declarations.


<wsdl:message name="TestInputRequest">
    <wsdl:part name="testInput" type="tns:TestInput"/>
  </wsdl:message>
  <wsdl:message name="GetHtmlResponse">
    <wsdl:part name="getChartOutput" type="tns:HtmlStreamOutput"/>
  </wsdl:message>
<wsdl:portType name="ChartPort">

<wsdl:operation name="getHTMLStream">
      <wsdl:input message="tns:TestInputRequest"/>
      <wsdl:output message="tns:GetHtmlResponse"/>
    </wsdl:operation>

  </wsdl:portType>
<wsdl:binding name="SOAPChartBinding" type="tns:ChartPort">

<soap:binding transport="http://schemas.xmlsoap.org/wsdl/soap/" style="rpc"/>

<wsdl:operation name="getHTMLStream">
<soap:operation soapAction="http://jsonwebservice.googlecode.com/attachment/getHTMLStream"
style="rpc" />
<wsdl:input><soap:body use="literal" namespace="http://jsonwebservice.googlecode.com/attachment"/></wsdl:input>
 <wsdl:output>
  <mime:multipartRelated>
<mime:part>
<soap:body use="literal" namespace="http://jsonwebservice.googlecode.com/attachment"/>
</mime:part>
<mime:part>
<mime:content part="html" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
 </wsdl:output>
</wsdl:operation>

  </wsdl:binding>
<wsdl:binding name="ChartBinding" type="tns:ChartPort">
<json:binding transport="http://jsonplugin.googlecode.com/json/" style="rpc"/><wsdl:operation name="getHTMLStream">





<json:operation soapAction="http://jsonwebservice.googlecode.com/attachment/getHTMLStream"
style="rpc" />
<wsdl:input><json:body use="literal" namespace="http://code.google.com/json"/></wsdl:input>
<wsdl:output>
  <mime:multipartRelated>
<mime:part>
<json:body use="literal" namespace="http://code.google.com/json"/>
</mime:part>
<mime:part>
<mime:content part="html" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
 </wsdl:output>
</wsdl:operation>

</wsdl:binding>
  <wsdl:service name="ChartService">
    <wsdl:port name="ChartPortType"
               binding="tns:ChartBinding">
      <json:address location="http://localhost:8080/attachment/ChartService.json"/>
    </wsdl:port>
    <wsdl:port name="SOAPChartPortType"
               binding="tns:ChartBinding">
      <soap:address location="http://localhost:8080/attachment/ChartService.soap"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

2) Then run wsimport using jax-ws. It generate all necessaries interface and objects for the service.

3) Create implementation class
  @SOAPBinding(style = SOAPBinding.Style.RPC)
@WebService(name = "ChartPort", 
targetNamespace = "http://jsonwebservice.googlecode.com/attachment", 
endpointInterface = "com.googlecode.jsonwebservice.attachment.ChartPort")
public class ChartPortImpl implements ChartPort {

@Override
public HtmlStreamOutput getHTMLStream(TestInput arg0) {
HtmlStreamOutput html = new HtmlStreamOutput();
html.setOutputFormates("text/html");
try {
// Also look at 
//StreamingDataHandler
// Any html attachment 
html.setHtml(new DataHandler(new URLDataSource(new URL("http://code.google.com/p/jsonwebservice/wiki/GettingStarted"))));
} catch (MalformedURLException e) {
e.printStackTrace();
}
return html;
}

4) Create other war standard xml files (web.xml,sun-jaxws.xml) and run the app.

Sample end point look like http://localhost:8080/attachment/ChartService.json

That's it. Nothing special other then defining wsdl mime type.

My sample form for attachment call looks like bellow http://localhost:8080/attachment/chart.json?formgetHTMLStream#_output



When I submit I do get html attachment pop ed up.



If you have any problem or question feel free to contact or report issues in http://code.google.com/p/jsonwebservice/



For quick start you can download latest war file from http://code.google.com/p/jsonwebservice/source/browse/trunk/demos/attachment/attachment.war

also browse source in http://code.google.com/p/jsonwebservice/source/browse/#