2013年5月22日星期三

ADF_228:ADF Mobile 11.1.2.4 Samples 介绍(14):Weather2

开发运行环境:JDeveloper 11.1.2.4 + Android SDK r21.1

与Weather1不同,Weather2演示了如何使用Java调用Web Service,并且通过解析 "GenericType" 返回对象生成最终的Java对象。用户界面组件是绑定到Java Bean上,而不是直接绑定到Web Service上。
这样做最大的好处是:可以尽可能地控制服务的访问,比如缓存结果数据,这样,即使服务不在线,仍然可以快速提供响应。
这种实现方式的目的让应用与网络尽可能地“绝缘”。



知识点:

1. 点击天气查询按钮,调用的是WeatherBean.java中的方法callForecast,后者会调用CityInformation.java中的方法retrieveForecast

    public boolean retrieveForecast(String zip) {
        // Before we get any forecast, we get the WeatherInfo if it's not retrieved yet
        weatherInfo.retreiveWeatherInfo();

        boolean ret = false;

        Trace.log(Utility.ApplicationLogger, Level.INFO, WeatherBean.class, "retrieveForecast",
                  ">>>>>> Inside retrieveForecast");

        List pnames = new ArrayList();
        List params = new ArrayList();
        List ptypes = new ArrayList();

        pnames.add("ZIP");
        ptypes.add(String.class);
        params.add(zip);

        // First lets clear the cityForecast
        cityForecast.setSuccess((Boolean)Boolean.FALSE);
        cityForecast.setResponseText((String)"");
        cityForecast.setCity((String)"");
        cityForecast.setState((String)"");
        cityForecast.setWeatherStationCity((String)"");
        cityForecast.clearForecast();

        try {
            Trace.log(Utility.ApplicationLogger, Level.INFO, WeatherBean.class, "retrieveForecast",
                      ">>>>>> Before invokeDataControlMethod");

            // This calls the DC method and gives us the Return
            GenericType result =
                (GenericType)AdfmfJavaUtilities.invokeDataControlMethod("WeatherDC", null, "GetCityForecastByZIP",
                                                                        pnames, params, ptypes);

            // This will give us the CityForeCast object from the result
            GenericType cfgt = (GenericType)result.getAttribute(0);

            // Read the attributes from the GenericType returend from the getCityForecastByZip call          
            cityForecast.setSuccess((Boolean)cfgt.getAttribute("Success"));
            cityForecast.setResponseText((String)cfgt.getAttribute("ResponseText"));
            cityForecast.setCity((String)cfgt.getAttribute("City"));
            cityForecast.setState((String)cfgt.getAttribute("State"));
            cityForecast.setWeatherStationCity((String)cfgt.getAttribute("WeatherStationCity"));

            // This will give us the ForecastResult which is a collection of Forecast objects
            GenericType frgt = (GenericType)cfgt.getAttribute("ForecastResult");


            // fcgt is a collection of Forecast objects, get all those in a loop
            int count = frgt.getAttributeCount();
            for (int i = 0; i < count; i++) {
                // Get each individual WeatherDescription object
                GenericType fgt = (GenericType)frgt.getAttribute(i);

                // Now make a real WeatherDescription java object out of this GenericType
                Forecast f = (Forecast)GenericTypeBeanSerializationHelper.fromGenericType(Forecast.class, fgt);
                f.weatherInfo = weatherInfo;

                // Now get the Temperature subobject
                GenericType tempgt = (GenericType)fgt.getAttribute("Temperatures");

                // Now set the high and low temps
                f.setDaytimeHigh((String)tempgt.getAttribute(0));
                f.setMorningLow((String)tempgt.getAttribute(1));
                // Now add this to our holder of all WeatherDescriptions
                cityForecast.addForecast(f);
            }
            ret = true;

            Trace.log(Utility.ApplicationLogger, Level.INFO, WeatherBean.class, "retrieveForecast",
                      ">>>>>> After invokeDataControlMethod");
        } catch (AdfInvocationException e) {
            Trace.log(Utility.ApplicationLogger, Level.SEVERE, WeatherBean.class, "retrieveForecast",
                      ">>>>>> AdfInvocationException=" + e.getMessage());
            AdfException ex = new AdfException("Error Invoking Web Service.  Please try later", AdfException.WARNING);
            throw ex;

        } catch (Exception e2) {
            Trace.log(Utility.ApplicationLogger, Level.SEVERE, WeatherBean.class, "retrieveForecast",
                      ">>>>>> Exception=" + e2.getMessage());
            AdfException ex = new AdfException("Error Invoking Web Service.  Please try later", AdfException.WARNING);
            throw ex;
        }
        return ret;
    }

说明:
(1)使用AdfmfJavaUtilities.invokeDataControlMethod调用Data Control中的方法,也就是真正的Web Service。
(2)返回值的类型是GenericType,后面是解析GenericType的逻辑,其中包括城市信息和城市未来5天的天气预报信息。
(3)异常的处理使用的是AdfException,如果调用出错,在界面会显示该错误。

2. 查询结果页面也不是绑定到Web Servcie Data Control上的,而是CityInformation.java生成的Data Control。

3. 这个例子中,模型层的基本设计是这样的
(1)CityInformation->CityForecast->Forecast,生成CityInformation Data Control,用于城市天气查询结果页面绑定。
(2)WeatherInformation->WeatherDescription,生成WeatherInformation Data Control,用于天气类型页面绑定。
(3)Web Service Data Control依然通过WSDL生成,不过不直接绑定到页面按钮上,而是在代码中,通过AdfmfJavaUtilities.invokeDataControlMethod调用。
(4)更进一步设想,如果需要缓存数据,可以修改相应的CityInformation.java和WeatherInformation.java,这正是这种模型层设计的好处。

参考文献:
1. https://blogs.oracle.com/mobile/entry/web_services_example_part_2

没有评论: