This is the third tutorial of Nano Tutorial Series, in first and second tutorials, I showed you how to use Nano with simple services, these services only support one or two calls, the request/response structures are fairly simple, supporting these simple services only can’t show the full power of Nano, so in this and later tutorials, I will show you how to use Nano with industrial grade services, let’s start with eBay Finding service, please review its official site if you are not familiar with this service, basically, it lets you search items on eBay. eBay Finding service supports SOAP 1.2, so I will also show you how to configure Nano to support SOAP 1.2 protocol, also I will show how to set service required HTTP headers on Nano client.
Depends on the network speed, you may need to wait a few moments to let the code generator download the wsdl and generate code, you may also download the wsdl and run the code generator with a local wsdl.
A few comments about the code generation:
I have added a special -ebaysoa codegen option, this is because eBay Finding service needs a per-call operation name HTTP header, I added this special flag in the code generator to let it generate the header for me, since I don’t want to add this header everytime I call an eBay Finding service, so this is just a special flag for eBay SOA services and for demo, or a hidden feature, not a generic codegen option.
By default, the code generator will derive package name from the target namespace in wsdl, you can use -p option to override this, for example, -p com.ebay.api.finding.
Step 2 - Create New Android Project, Add Nano Library and Generated Proxy into Your Project
Create a simple Android project called HelloeBayFinding in eclipse(or other IDE you prefer), then:
Now build the project to ensure it can build successfully.
You may now review the eBay Finding service SOAP interface generated from wsdl, to learn what kinds of functions are provided by eBay Finding service, and what kinds of parameters are needed to call the service, the interface is posted below:
// Generated by wsdl compiler for android/java// DO NOT CHANGE!packagecom.ebay.api.finding.client;importcom.leansoft.nano.ws.SOAPServiceCallback;importcom.leansoft.nano.ws.NanoSOAPClient;importcom.ebay.api.finding.FindItemsForFavoriteSearchResponse;importcom.ebay.api.finding.FindItemsByCategoryResponse;importcom.ebay.api.finding.FindItemsByProductResponse;importcom.ebay.api.finding.FindItemsByImageRequest;importcom.ebay.api.finding.GetSearchKeywordsRecommendationRequest;importcom.ebay.api.finding.FindItemsByCategoryRequest;importcom.ebay.api.finding.FindCompletedItemsResponse;importcom.ebay.api.finding.FindItemsAdvancedResponse;importcom.ebay.api.finding.FindItemsIneBayStoresResponse;importcom.ebay.api.finding.FindItemsForFavoriteSearchRequest;importcom.ebay.api.finding.FindItemsByKeywordsRequest;importcom.ebay.api.finding.FindItemsByProductRequest;importcom.ebay.api.finding.FindItemsIneBayStoresRequest;importcom.ebay.api.finding.FindItemsAdvancedRequest;importcom.ebay.api.finding.FindItemsByImageResponse;importcom.ebay.api.finding.GetVersionResponse;importcom.ebay.api.finding.GetHistogramsResponse;importcom.ebay.api.finding.GetVersionRequest;importcom.ebay.api.finding.GetSearchKeywordsRecommendationResponse;importcom.ebay.api.finding.FindItemsByKeywordsResponse;importcom.ebay.api.finding.GetHistogramsRequest;importcom.ebay.api.finding.FindCompletedItemsRequest;/** This class is the SOAP client to the FindingServicePortType Web Service.*/publicclassFindingServicePortType_SOAPClientextendsNanoSOAPClient{/** public method */publicvoidgetSearchKeywordsRecommendation(GetSearchKeywordsRecommendationRequestrequestObject,SOAPServiceCallback<GetSearchKeywordsRecommendationResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","getSearchKeywordsRecommendation");super.invoke(requestObject,serviceCallback,GetSearchKeywordsRecommendationResponse.class);}/** public method */publicvoidfindItemsByKeywords(FindItemsByKeywordsRequestrequestObject,SOAPServiceCallback<FindItemsByKeywordsResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findItemsByKeywords");super.invoke(requestObject,serviceCallback,FindItemsByKeywordsResponse.class);}/** public method */publicvoidfindItemsByCategory(FindItemsByCategoryRequestrequestObject,SOAPServiceCallback<FindItemsByCategoryResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findItemsByCategory");super.invoke(requestObject,serviceCallback,FindItemsByCategoryResponse.class);}/** public method */publicvoidfindItemsAdvanced(FindItemsAdvancedRequestrequestObject,SOAPServiceCallback<FindItemsAdvancedResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findItemsAdvanced");super.invoke(requestObject,serviceCallback,FindItemsAdvancedResponse.class);}/** public method */publicvoidfindItemsByProduct(FindItemsByProductRequestrequestObject,SOAPServiceCallback<FindItemsByProductResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findItemsByProduct");super.invoke(requestObject,serviceCallback,FindItemsByProductResponse.class);}/** public method */publicvoidfindItemsIneBayStores(FindItemsIneBayStoresRequestrequestObject,SOAPServiceCallback<FindItemsIneBayStoresResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findItemsIneBayStores");super.invoke(requestObject,serviceCallback,FindItemsIneBayStoresResponse.class);}/** public method */publicvoidfindItemsByImage(FindItemsByImageRequestrequestObject,SOAPServiceCallback<FindItemsByImageResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findItemsByImage");super.invoke(requestObject,serviceCallback,FindItemsByImageResponse.class);}/** public method */publicvoidgetHistograms(GetHistogramsRequestrequestObject,SOAPServiceCallback<GetHistogramsResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","getHistograms");super.invoke(requestObject,serviceCallback,GetHistogramsResponse.class);}/** public method */publicvoidfindCompletedItems(FindCompletedItemsRequestrequestObject,SOAPServiceCallback<FindCompletedItemsResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findCompletedItems");super.invoke(requestObject,serviceCallback,FindCompletedItemsResponse.class);}/** public method */publicvoidgetVersion(GetVersionRequestrequestObject,SOAPServiceCallback<GetVersionResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","getVersion");super.invoke(requestObject,serviceCallback,GetVersionResponse.class);}/** public method */publicvoidfindItemsForFavoriteSearch(FindItemsForFavoriteSearchRequestrequestObject,SOAPServiceCallback<FindItemsForFavoriteSearchResponse>serviceCallback){super.getAsyncHttpClient().addHeader("X-EBAY-SOA-OPERATION-NAME","findItemsForFavoriteSearch");super.invoke(requestObject,serviceCallback,FindItemsForFavoriteSearchResponse.class);}}
All the methods in the interface follow same calling paradigm - you call the service with required request object and a callback object implementing interface SOAPServiceCallback.
Step 3 - Implement Appliction Logic and UI, Call Proxy to Invoke Web Service as Needed.
packagecom.ebay.service.finding;importcom.ebay.api.finding.client.FindingServicePortType_SOAPClient;importcom.leansoft.nano.ws.SOAPVersion;publicclassFindingServiceClient{publicstaticStringeBayFindingServiceURLString="http://svcs.ebay.com/services/search/FindingService/v1";publicstaticStringeBayAppId="YOUR APPID HERE";privatestaticvolatileFindingServicePortType_SOAPClientclient=null;publicstaticFindingServicePortType_SOAPClientgetSharedClient(){if(client==null){synchronized(FindingServiceClient.class){if(client==null){client=newFindingServicePortType_SOAPClient();client.setEndpointUrl(eBayFindingServiceURLString);client.setSoapVersion(SOAPVersion.SOAP12);// ebay finding service supports SOAP 1.2client.setContentType("application/soap+xml");client.getAsyncHttpClient().addHeader("Accept","application/soap+xml");client.getAsyncHttpClient().addHeader("X-EBAY-SOA-SECURITY-APPNAME",eBayAppId);client.getAsyncHttpClient().addHeader("X-EBAY-SOA-MESSAGE-PROTOCOL","SOAP12");client.getAsyncHttpClient().addHeader("X-EBAY-SOA-REQUEST-DATA-FORMAT","SOAP");}}}returnclient;}}
The shared client for eBay Finding service is a little more complex than the simple serivce client in tutorial 1 and 2, this is because that eBay Finding service needs a few HTTP headers set to work, let me give more comments:
eBay Finding service support SOAP12, so we set the client to use SOAP12 protocol, this is not necessary since eBay Finding service also supports SOAP11(which is Nano default), we use SOAP12 here just for demo and to show the capability of Nano.
eBay Finding service needs to set a few HTTP headers to work, for a list of required headers, please refer to doc here.
One mandatory header for eBay Finding service is eBayAppId, you need to register on eBay developer site as an eBay developer then get this id, before your can run this demo, you must fill in your own eBayAppId in the shared client.
Now the UI part and application logic, for this hello world like sample, we just need a EditText for keyword input and Button to trigger eBay search by invoking listening method onClick which will indirectly call eBay Finding service through the proxy, fairly simple, see the full application logic in MainActivity class below:
packagecom.leansoft.nano.sample;importcom.ebay.api.finding.AckValue;importcom.ebay.api.finding.ErrorData;importcom.ebay.api.finding.FindItemsByKeywordsRequest;importcom.ebay.api.finding.FindItemsByKeywordsResponse;importcom.ebay.api.finding.PaginationInput;importcom.ebay.api.finding.SearchItem;importcom.ebay.api.finding.client.FindingServicePortType_SOAPClient;importcom.ebay.service.finding.FindingServiceClient;importcom.leansoft.nano.soap12.Reasontext;importcom.leansoft.nano.ws.SOAPServiceCallback;importandroid.os.Bundle;importandroid.app.Activity;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;importandroid.widget.EditText;importandroid.widget.Toast;publicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButtonsearchButton=(Button)this.findViewById(R.id.search_button);searchButton.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(Viewarg0){// Get shared clientFindingServicePortType_SOAPClientclient=FindingServiceClient.getSharedClient();client.setDebug(true);// enable soap message logging// Build requestFindItemsByKeywordsRequestrequest=newFindItemsByKeywordsRequest();Stringkeywords=((EditText)findViewById(R.id.keyword_input)).getText().toString();request.keywords=keywords;PaginationInputpi=newPaginationInput();pi.pageNumber=1;pi.entriesPerPage=1;request.paginationInput=pi;// Make API call and register callbacksclient.findItemsByKeywords(request,newSOAPServiceCallback<FindItemsByKeywordsResponse>(){@OverridepublicvoidonSuccess(FindItemsByKeywordsResponseresponseObject){if(AckValue.SUCCESS==responseObject.ack){if(responseObject.searchResult!=null&&responseObject.searchResult.count>0){// show the title of the first found itemSearchItemitem=responseObject.searchResult.item.get(0);Toast.makeText(MainActivity.this,item.title,Toast.LENGTH_LONG).show();}else{// no resultToast.makeText(MainActivity.this,"No result",Toast.LENGTH_LONG).show();}}else{// response resident errorErrorDataerrorData=responseObject.errorMessage.error.get(0);Toast.makeText(MainActivity.this,errorData.message,Toast.LENGTH_LONG).show();}}@OverridepublicvoidonFailure(Throwableerror,StringerrorMessage){// http or parsing errorToast.makeText(MainActivity.this,errorMessage,Toast.LENGTH_LONG).show();}@OverridepublicvoidonSOAPFault(ObjectsoapFault){// soap faultcom.leansoft.nano.soap12.Faultfault=(com.leansoft.nano.soap12.Fault)soapFault;ReasontextreasonText=fault.reason.text.get(0);Toast.makeText(MainActivity.this,reasonText.value,Toast.LENGTH_LONG).show();}});}});}}
More comments to the serivce call code:
I’ve added comments in the code so the whole service call flow should be easy to understand.
We used the eBay Finding findItemsByKeywords call, which takes a keyword as input, and will return a list of matched items, for demo, we just need one item to display, so we set entries per page to 1.
In the success handling logic, we show the title of the returned item using Android Toast component.
Since we set the client to use SOAP12 protocol, in the soap fault error handling logic, we need to cast the soapFault variable to type SOAP12Fault and handle it accordingly.
eBay Finding service supports response resident error(RRE), so even we get a success response, we still need to check the response for resident error and handle it accordingly.
Final Step - Run the Demo
Let’s run the demo on simulator, see a screen shot below:
let’s also try a soap fault case, for example, if you forget to fill in your eBayAppId in the shared client, then you will get:
This is just a bare minimum eBay Finding service based application, for a demo with more functions, please see the eBayDemoApp sample in the sample\webservice folder of Nano source, eBayDemoApp is a composite app which calls two eBay serivces behind, this app searches eBay by calling eBay Fining service, showes a list of matched items on UI, when an item is clicked, it will show item details by calling eBay Shopping service, see a screen shot below.
Now it’s your turn to create Android applications based on eBay Finding web service, see your next great service based app.