Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Calling WebService with JSON

    I'm trying to call a webservice that returns JSON data and am using the WSDLDataBindingSample.java from the Showcase as a starting point. If I use service.getFetchDS("getRamReport", null), it actually invokes the WSDL's getRamReport method correctly and outputs JSON. However, I would like to use my own datasource called ramDS, but when I do this it never calls the WSDL's getRamReport method. Am I putting the Webservice method in the correct place ? fetch.setWsOperation("getRamReport") ??

    Here's the Entry class:
    Code:
    	public Canvas callJSONWebservice() {
    		final Canvas canvas = new Canvas();
    		canvas.setWidth100();
    		canvas.setHeight100();
    
    		final String wsdlURL = "http://localhost:8080/pmTools/services/FormWebService?wsdl";
    		SC.showPrompt("Loading WSDL from: " + wsdlURL);
    		XMLTools.loadWSDL(wsdlURL, new WSDLLoadCallback() {
    			public void execute(WebService service) {
    				if (service == null) {
    					SC.warn("WSDL not currently available from Google (tried "
    							+ wsdlURL + ")", new BooleanCallback() {
    						public void execute(Boolean value) {
    						}
    					});
    					return;
    				}
    				
    				final DynamicForm searchForm = new DynamicForm();
    				searchForm.setNumCols(4);
    				searchForm.setWidth(500);
    				
    				// WebService method and params being invoked
    				searchForm.setDataSource(service.getInputDS("getRamReport"));		 		
    				searchForm.setValue("applicationId", "39202583-F898-E769-6512-25B888108E39");
    				searchForm.setValue("program", "0BXY");
    				
    		        
    				//DataSource resultDS = service.getFetchDS("getRamReport", null);
    				DataSource ramDS = RAMJsonDS.getInstance();
    				
    				// create Grid
    				final ListGrid lreGrid = new ListGrid();
    				lreGrid.setWidth100();
    				lreGrid.setDataSource(ramDS);
    				lreGrid.setAutoFetchData(true);
    				lreGrid.setFields(
    		        		new ListGridField("wbsNum", "WBS Num"),		        		
    		        		new ListGridField("controlAccountNum", "Pre LRE($K)")
    		        	);
    		
    				
    				IButton searchButton = new IButton("Search");
    				searchButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
    					public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    						lreGrid.fetchData(searchForm.getValuesAsCriteria());
    					}
    				});
    				
    				// create layout
    				VLayout layout = new VLayout(20);
    				layout.setWidth100();
    				layout.setHeight100();
    				layout.setLayoutMargin(40);
    
    				layout.addMember(searchForm);
    				layout.addMember(searchButton);
    				layout.addMember(lreGrid);
    				canvas.addChild(layout);
    				
    				canvas.draw();
    			
    				SC.clearPrompt();
    				
    				
    			}
    		});
    
    		return canvas;
    	}
    Here's my custom Datasource:
    Code:
    public class RAMJsonDS extends DataSource {
    
        private static RAMJsonDS instance = null;
    
        public static RAMJsonDS getInstance() {
            if (instance == null) {
                instance = new RAMJsonDS("ramDS");
            }
            return instance;
        }
        
    	final String wsdlURL = "http://localhost:8080/pmTools/services/FormWebService?wsdl";
    
    
        public RAMJsonDS(String id) {
    
            setID(id);
            setRecordXPath("rows");
            setDataFormat(DSDataFormat.JSON);
            setDataURL(wsdlURL);
            
            //jsonDS.setServiceNamespace("http://form.workflow.pmtools.com");
    
    		DataSourceField wbsNum = new DataSourceField("wbsNum", FieldType.TEXT);
    		DataSourceField controlAccountNum = new DataSourceField("controlAccountNum", FieldType.TEXT);
    
    
    		setFields(wbsNum, controlAccountNum);
    
    				
            OperationBinding fetch = new OperationBinding();
            fetch.setOperationType(DSOperationType.FETCH);
            fetch.setDataProtocol(DSProtocol.POSTPARAMS);
            DSRequest fetchRequest = new DSRequest();
            fetchRequest.setHttpMethod("GET");
            fetch.setRequestProperties(fetchRequest);
            fetch.setDataURL(wsdlURL);
            fetch.setWsOperation("getRamReport");
    		
            setOperationBindings(fetch);
    		
    		
        }
    }

    #2
    What exactly does this web service look like, a SOAP input and a pure JSON response? Or a JSON response embedded inside a SOAP response?

    Your JSON DataSource expects to be working with just JSON (input and output from the web service). If you have something more like JSON embedded in a SOAP response, you need to use a DataSource with dataFormat:"xml" and use transformResponse to extract and process the JSON embedded inside.

    Comment


      #3
      It's SOAP input and pure JSON response. The return is just a JSON formatted string.

      Here is a sample of the JSON response String

      [CODE]
      {
      cols:[
      {
      "OBS":"MfgEng"
      },
      {
      "OBS":"ProdEng"
      },
      {
      "OBS":"QUAL"
      },
      {
      "OBS":"SCM"
      },
      {
      "OBS":"Supt"
      },
      {
      "OBS":"SusEng"
      },
      {
      "OBS":"SysEng"
      },
      {
      "OBS":"TestEng"
      }
      ],
      rows:[
      {
      "wbsNum":"",
      "controlAccountNum":"B111",
      "controlAccountName":"BSC",
      "camWfMember":"Troy Veth",
      "ProgramName":"B2 RMP LRIP",
      "MfgEng":794.20
      },
      {
      "wbsNum":"",
      "controlAccountNum":"B112",
      "controlAccountName":"BSC Test",
      "camWfMember":"Aaron Vos",
      "ProgramName":"B2 RMP LRIP",
      "MfgEng":196.60
      },
      {
      "wbsNum":"",
      "controlAccountNum":"B121",
      "controlAccountName":"TR Module Labor \u0026 Material",
      "camWfMember":"John Scoggan",
      "ProgramName":"B2 RMP LRIP",
      "MfgEng":28456.60
      },
      [CODE]

      Comment


        #4
        One more thing. I put a breakpoint while running debugger in Eclipse and it never reaches the webservice getRamReport method. I suspect that the method isn't even getting invoke.

        Is this the correct place to put the method call?

        fetch.setWsOperation("getRamReport")

        Comment


          #5
          Wow, that is bizarre.

          Your best approach use a DataSource where the dataFormat to JSON and dataProtocol is "postMessage". Then in transformRequest, call WebService.getSoapMessage() to obtain the input SOAP message as a String and provide it as dsRequest.data.

          Note: WebService.getSoapMessage() is not in the SGWT API at the moment, but it's being added. For now you'd have to call the underlying SmartClient API via JSNI.

          Comment


            #6
            I was mistaken. The response isn't a JSON string, but JSON inside a SOAP message. I've changed the dataProtocol to XML, but is there another way to get to the JSON string besides using JSNI ?

            Code:
            - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            - <soapenv:Body>
            - <getRamReportResponse xmlns="http://form.workflow.pmtools.com">
              <getRamReportReturn>
            	JSON String...	
            </getRamReportReturn> 
              </getRamReportResponse>
              </soapenv:Body>
              </soapenv:Envelope>

            Comment


              #7
              See the various utility methods on JSOHelper. In your override of transformResponse, you probably want to extract the string via XMLTools.selectString(), eval() it, turn it into a Record Array and call dsResponse.setData() with it.

              Comment


                #8
                I was able to get it to work using what you suggested, but slightly different. I'm not using a datasource to fetch the SOAPMessage, but calling server.callOperation directly, with the appropriate XMLNS and XPath. Then processing the data using a method I found on one of the threads to convert the JSON string to ListGridRecord[]. Either way works.

                But I've run into another problem. What if I don't want to convert the entire JSON string into ListGridRecords? What I really want to do is to somehow put the JSON string into a XJSONDatasource, and be able to create DataSourceFields, and use ValueXPath to get to the appropriate JSON xpaths.
                Is this possible to do ?

                Search button
                [CODE]
                IButton searchButton = new IButton("Search");
                searchButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
                public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {

                // WebService method and params being invoked
                Map<String, String> requestParams = new LinkedHashMap<String, String>();
                requestParams.put("applicationId", "39202583-F898-E769-6512-25B888108E39");
                requestParams.put("program", "0BXY");

                WSRequest requestProperties = new WSRequest();
                XmlNamespaces xmlNs = new XmlNamespaces();
                xmlNs.addNamespace("ns", "http://form.workflow.pmtools.com");
                requestProperties.setXmlNamespaces(xmlNs);
                service.callOperation("getRamReport", requestParams, "//ns:getRamReportReturn", new WebServiceCallback() {

                @Override
                public void execute(Object[] data, JavaScriptObject xmlDoc, RPCResponse rpcResponse, JavaScriptObject wsRequest) {

                String jsonString = data[0].toString();
                SC.logWarn(jsonString);

                ListGridRecord[] records = jsonToRecords(jsonString);
                lreGrid.setData(records);
                }
                }
                , requestProperties);

                }
                });
                [</CODE]

                Code for jsonToRecords method
                [CODE]
                public static native ListGridRecord[] jsonToRecords(String jsonString) /*-{
                var json = eval(jsonString);
                return @com.smartgwt.client.widgets.grid.ListGrid::convertToListGridRecordArray(Lcom/google/gwt/core/client/JavaScriptObject;)(json);
                }-*/;
                [</CODE]

                Here's the JSON string. I only want to get what's in "/rows"
                Code:
                {cols:[{Stuff..}],
                rows:[
                {
                "wbsNum":"",
                "controlAccountNum":"B111",
                "controlAccountName":"BSC",
                "camWfMember":"Troy Veth",
                "ProgramName":"B2 RMP LRIP",
                "MfgEng":794.20
                },
                {
                "wbsNum":"",
                "controlAccountNum":"B112",
                "controlAccountName":"BSC Test",
                "camWfMember":"Aaron Vos",
                "ProgramName":"B2 RMP LRIP",
                "MfgEng":196.60
                },
                {
                "wbsNum":"",
                "controlAccountNum":"B121",
                "controlAccountName":"TR Module Labor \u0026 Material",
                "camWfMember":"John Scoggan",
                "ProgramName":"B2 RMP LRIP",
                "MfgEng":28456.60
                },

                Comment


                  #9
                  There currently isn't a way to do something like simulate the DataSource processing a response, but if you wanted to use the JSON XPath stuff it's exposed as a method XMLTools.selectObjects(). Note that nothing in your JSON response would currently require XPath anyway.

                  Comment


                    #10
                    That did it !!
                    Thank you Isomorphic for helping out. Here's the important piece of the code. Hope this helps out other people.
                    Code:
                    IButton searchButton = new IButton("Search");
                    searchButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
                    	public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
                    		
                    		// WebService method and params being invoked
                            Map<String, String> requestParams = new LinkedHashMap<String, String>();
                            requestParams.put("applicationId", searchForm.getValue("ApplicationID").toString());
                            requestParams.put("program", searchForm.getValue("ProgramCode").toString());
                            
                            WSRequest requestProperties = new WSRequest();		                
                            XmlNamespaces xmlNs = new XmlNamespaces();
                            xmlNs.addNamespace("ns", "http://form.workflow.pmtools.com");
                            requestProperties.setXmlNamespaces(xmlNs);
                            service.callOperation("getRamReport", requestParams, "//ns:getRamReportReturn", new WebServiceCallback() {
                    			
                    			@Override
                    			public void execute(Object[] data, JavaScriptObject xmlDoc,	RPCResponse rpcResponse, JavaScriptObject wsRequest) {
                    				
                    				String jsonString = data[0].toString();
                    				//SC.logWarn(jsonString);
                    				if (jsonString != null && jsonString.length() > 0) {
                    					
                    					JavaScriptObject jsObj = JSON.decode(jsonString);
                    					
                    					// select desired element from JSON string
                    					JSONArray jsonArray = XMLTools.selectObjects(jsObj, "rows");
                    					
                    					// convert to records and set records in grid
                    					ListGridRecord[] records = jsonToRecords(jsonArray.toString());
                    					ramGrid.setData(records);							
                    				}
                    			}
                    		}
                            , requestProperties);
                            
                    	}
                    });

                    Comment


                      #11
                      Good to hear, and thanks for posting that sample.

                      Comment


                        #12
                        Here's the updated code which doesn't need to call the JSNI method. I still find it strange that you have to use "XMLTools" to get a "JSON" element. But it works. ;)

                        Code:
                        String jsonString = data[0].toString();
                        if (jsonString != null && jsonString.length() > 0) {
                        	
                        	JavaScriptObject jsObj = JSON.decode(jsonString);
                        	
                        	// select desired element from JSON string
                        	JSONArray jsonArray = XMLTools.selectObjects(jsObj, "values");
                        	
                        	JavaScriptObject jsonObj = JSON.decode(jsonArray.toString());																		
                        	Record[] records = ListGridRecord.convertToRecordArray(jsonObj);
                        	
                        	lreGrid.setData(records);									
                        }

                        Comment

                        Working...
                        X