Consuming Webservices - Weather Demo
/* This code is Based on example given by M. Murphy CommonsWare, LLC
"The Busy Coder's Guide To Android Development" V3.4 Chapter 29.
App has been modified to get the weather forecast of a particular
location (no GPS). The elements included in the response object
are briefly shown as an array of nodes.
*/
packagecom.commonsware.android.internet;
importjava.io.StringReader;
importjava.util.ArrayList;
importjava.util.List;
importjavax.xml.parsers.DocumentBuilder;
importjavax.xml.parsers.DocumentBuilderFactory;
importorg.apache.http.client.HttpClient;
importorg.apache.http.client.ResponseHandler;
importorg.apache.http.client.methods.HttpGet;
importorg.apache.http.impl.client.BasicResponseHandler;
importorg.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
importorg.xml.sax.InputSource;
importandroid.app.Activity;
importandroid.location.Location;
importandroid.location.LocationListener;
importandroid.location.LocationManager;
importandroid.os.Bundle;
importandroid.util.Log;
importandroid.webkit.WebView;
publicclassWeatherDemoextends Activity {
private String format;
privateWebViewbrowser;
privateHttpClientclient;
private List<Forecast> forecasts = newArrayList<Forecast>();
@Override
publicvoidonCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
format = getString(R.string.url);
browser = (WebView) findViewById(R.id.webkit);
client = newDefaultHttpClient();
}
@Override
publicvoidonResume() {
super.onResume();
// provide coordinates of a given location
Location loc = newLocation("CLEVELAND AERA");
loc.setLatitude(41.4797);
loc.setLongitude(-81.6785);
updateForecast(loc);
}
privatevoidupdateForecast(Location loc) {
//obtaining forecast for given region
String url = String.format(format,
loc.getLatitude(),
loc.getLongitude());
Log.e("URL value: ", url );
HttpGetgetMethod = newHttpGet(url);
try {
ResponseHandler<String> responseHandler = newBasicResponseHandler();
String responseBody = client.execute(getMethod, responseHandler);
buildForecasts(responseBody);
String page = generatePage();
browser.loadDataWithBaseURL(null, page, "text/html", "UTF-8", null);
} catch (Throwable t) {
Log.e("ERROR", t.toString() );
browser.loadData("<html<body>" + t.toString() + "</body</html>",
"text/html",
"UTF-8");
}//updateForecast
}
// //////////////////////////////////////////////////////////////////////////
voidbuildForecasts(String raw) throws Exception {
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document doc = builder.parse(newInputSource(newStringReader(raw)));
NodeList times = doc.getElementsByTagName("start-valid-time");
for (inti = 0; itimes.getLength(); i++) {
Element time = (Element) times.item(i);
Forecast forecast = newForecast();
forecasts.add(forecast);
forecast.setTime(time.getFirstChild().getNodeValue());
}
NodeList temps = doc.getElementsByTagName("value");
for (inti = 0; itemps.getLength(); i++) {
Element temp = (Element) temps.item(i);
Forecast forecast = forecasts.get(i);
forecast.setTemp(new Integer(temp.getFirstChild().getNodeValue()));
}
NodeList icons = doc.getElementsByTagName("icon-link");
for (inti = 0; iicons.getLength(); i++) {
Element icon = (Element) icons.item(i);
Forecast forecast = forecasts.get(i);
forecast.setIcon(icon.getFirstChild().getNodeValue());
}
}
String generatePage() {
StringBufferbufResult = newStringBuffer("<html<body<table>");
bufResult.append("<trth width=\"50%\">Time</th>"
+ "<thTemperature</thth>Forecast</th</tr>");
for (Forecast forecast : forecasts) {
bufResult.append("<tr<td align=\"center\">");
bufResult.append(forecast.getTime());
bufResult.append("</td<td align=\"center\">");
bufResult.append(forecast.getTemp());
bufResult.append("</td<td<imgsrc=\"");
bufResult.append(forecast.getIcon());
bufResult.append("\"</td</tr>");
}
bufResult.append("</table</body</html>");
return (bufResult.toString());
}
/////////////////////////////////////////////////////////////////
class Forecast {
String time = "";
Integer temp = null;
String iconUrl = "";
String getTime() {
return (time);
}
voidsetTime(String time) {
this.time = time.substring(0, 16).replace('T', ' ');
}
Integer getTemp() {
return (temp);
}
voidsetTemp(Integer temp) {
this.temp = temp;
}
String getIcon() {
return (iconUrl);
}
voidsetIcon(String iconUrl) {
this.iconUrl = iconUrl;
}
}
}//Forecast
Layout
<?xmlversion="1.0"encoding="utf-8"?>
WebViewxmlns:android="
android:id="@+id/webkit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
Manifest – Permission(s)
manifestxmlns:android="
package="com.commonsware.android.internet"
uses-permissionandroid:name="android.permission.INTERNET"/>
uses-sdkandroid:minSdkVersion="4"/>
application
activityandroid:name=".WeatherDemo"android:label="WeatherDemo"
intent-filter
actionandroid:name="android.intent.action.MAIN"/>
categoryandroid:name="android.intent.category.LAUNCHER"/>
</intent-filter
</activity
</application
</manifest
WEB SERVICES
REQUEST (HttpGetsent to website using IExplorer)
RESPONSE
<?xml version="1.0" ?>
-dwml version="1.0"xmlns:xsd="" xsi:noNamespaceSchemaLocation="">
-head
-product srsName="WGS 1984" concise-name="time-series" operational-mode="official">
titleNOAA's National Weather Service Forecast Data</title
fieldmeteorological</field
categoryforecast</category
creation-date refresh-frequency="PT1H">2011-02-17T16:28:30Z</creation-date
</product
+source
more-information</more-information
-production-center
Meteorological Development Laboratory
sub-centerProduct Generation Branch</sub-center
</production-center
disclaimer</disclaimer
credit</credit
credit-logo</credit-logo
feedback</feedback
</source
</head
-data
-location
location-keypoint1</location-key
pointlatitude="41.48" longitude="-81.68" />
</location
moreWeatherInformation applicable-location="point1"></moreWeatherInformation
-time-layout time-coordinate="local" summarization="none">
layout-keyk-p3h-n35-1</layout-key
start-valid-time2011-02-17T13:00:00-05:00</start-valid-time
start-valid-time2011-02-17T16:00:00-05:00</start-valid-time
start-valid-time2011-02-17T19:00:00-05:00</start-valid-time
start-valid-time2011-02-17T22:00:00-05:00</start-valid-time
start-valid-time2011-02-18T01:00:00-05:00</start-valid-time
start-valid-time2011-02-18T04:00:00-05:00</start-valid-time
start-valid-time2011-02-18T07:00:00-05:00</start-valid-time
start-valid-time2011-02-18T10:00:00-05:00</start-valid-time
start-valid-time2011-02-18T13:00:00-05:00</start-valid-time
start-valid-time2011-02-18T16:00:00-05:00</start-valid-time
start-valid-time2011-02-18T19:00:00-05:00</start-valid-time
start-valid-time2011-02-18T22:00:00-05:00</start-valid-time
start-valid-time2011-02-19T01:00:00-05:00</start-valid-time
start-valid-time2011-02-19T04:00:00-05:00</start-valid-time
start-valid-time2011-02-19T07:00:00-05:00</start-valid-time
start-valid-time2011-02-19T10:00:00-05:00</start-valid-time
start-valid-time2011-02-19T13:00:00-05:00</start-valid-time
start-valid-time2011-02-19T16:00:00-05:00</start-valid-time
start-valid-time2011-02-19T19:00:00-05:00</start-valid-time
start-valid-time2011-02-20T01:00:00-05:00</start-valid-time
start-valid-time2011-02-20T07:00:00-05:00</start-valid-time
start-valid-time2011-02-20T13:00:00-05:00</start-valid-time
start-valid-time2011-02-20T19:00:00-05:00</start-valid-time
start-valid-time2011-02-21T01:00:00-05:00</start-valid-time
start-valid-time2011-02-21T07:00:00-05:00</start-valid-time
start-valid-time2011-02-21T13:00:00-05:00</start-valid-time
start-valid-time2011-02-21T19:00:00-05:00</start-valid-time
start-valid-time2011-02-22T01:00:00-05:00</start-valid-time
start-valid-time2011-02-22T07:00:00-05:00</start-valid-time
start-valid-time2011-02-22T13:00:00-05:00</start-valid-time
start-valid-time2011-02-22T19:00:00-05:00</start-valid-time
start-valid-time2011-02-23T01:00:00-05:00</start-valid-time
start-valid-time2011-02-23T07:00:00-05:00</start-valid-time
start-valid-time2011-02-23T13:00:00-05:00</start-valid-time
start-valid-time2011-02-23T19:00:00-05:00</start-valid-time
</time-layout
-parameters applicable-location="point1">
-temperature type="hourly" units="Fahrenheit" time-layout="k-p3h-n35-1">
nameTemperature</name
value57</value
value57</value
value52</value
value49</value
value48</value
value46</value
value46</value
value49</value
value53</value
value51</value
value41</value
value36</value
value33</value
value31</value
value29</value
value33</value
value37</value
value37</value
value33</value
value29</value
value28</value
value38</value
value33</value
value29</value
value27</value
value33</value
value29</value
value26</value
value25</value
value34</value
value29</value
value24</value
value23</value
value35</value
value33</value
</temperature
-conditions-icon type="forecast-NWS" time-layout="k-p3h-n35-1">
nameConditions Icons</name
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
icon-link</icon-link
</conditions-icon
</parameters
</data
</dwml
MONEY EXCHANGE (RSS agent)
// Using RSS to find the current rate of exchange for USD
// data taken from
// example uses background thread for slow internet process
// and foreground thread for GUI management
// ------
package cis493.testa;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class USD_Exchange extends ListActivity {
ArrayList<SingleNewsItem> newsList = new ArrayList<SingleNewsItem>();
ArrayAdapter<String> aa;
String exchangeDate = "";
ProgressBar myBar1;
Handler myHandler = new Handler();
Context myMainContext;
TextView myMsg;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// show circular progress bar while other things are done
myBar1 = (ProgressBar)findViewById(R.id.myProgress1);
myMsg = (TextView) findViewById(R.id.myMsg);
myMainContext = getApplicationContext();
}//onCreate
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
try {
String text = "Position: " + position
+ "\n"
+ newsList.get(position).getDescription();
Toast.makeText(this, text, 1).show();
// do something useful with the data
} catch (Exception e) {
Log.e("<EXCHANGE ERROR>", e.getMessage());
}
}
@Override
protected void onStart() {
super.onStart();
// create background thread were the busy work will be done
Thread myThread1 = new Thread(backgroundTask, "getRssMoneyData" );
myThread1.start();
}
/////////////////////////////////////////////////////////////////////
//this is the "Runnable" object that executes the background thread
private Runnable backgroundTask = new Runnable () {
@Override
public void run() {
//busy work goes here...
try {
getRssPopulateListView();
myHandler.post(foregroundTask);
}
catch (Exception e) {
e.printStackTrace();
}
}//run
};//backgroundTask
// //////////////////////////////////////////////////////////////////
// this is the foreground "Runnable" object responsible for the GUI
// when RSS process is it shows list and removes circular progress bar
private Runnable foregroundTask = new Runnable() {
@Override
public void run() {
try {
myMsg.setText(exchangeDate);
myBar1.setVisibility(View.INVISIBLE);
// use your own (small font) layout to show a single row
int layoutID = R.layout.my_simple_list_item_1;
// show on a ListView news held in ArrayList just assembled
ArrayAdapter<SingleNewsItem> aaNews =
new ArrayAdapter<SingleNewsItem>(
myMainContext,
layoutID,
newsList);
setListAdapter(aaNews);
}
catch (Exception e) {
e.printStackTrace();
}
}
}; //foregroundTask
/////////////////////////////////////////////////////////////////////
public void getRssPopulateListView(){
try {
// go to web site, pickup RSS feed
URL url = new URL("
URLConnection connection;
connection = url.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = httpConnection.getInputStream();
DocumentBuilderFactory dbf = DocumentBuilderFactory
.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// create an parse tree for the XML input stream
Document dom = db.parse(in);
// this will be a single node in the tree
Element docEle = dom.getDocumentElement();
// extract individual exchange values
// such as: (1 US Dollar = xx other currency)
NodeList nl = docEle.getElementsByTagName("item");
if ((nl != null) & (nl.getLength() > 0)) {
for (int i = 0; i < nl.getLength(); i++) {
dissectNode(nl, i);
}// for
}// if
}// if
} catch (MalformedURLException e) {
Log.v("1-disecting", e.getMessage());
} catch (IOException e) {
Log.v("2-disecting", e.getMessage());
} catch (ParserConfigurationException e) {
Log.v("3-disecting", e.getMessage());
} catch (SAXException e) {
Log.v("4-disecting", e.getMessage());
}
}
/////////////////////////////////////////////////////////////////
public void dissectNode(NodeList nl, int i){
// examine input collection (NodeList) holding items,
// get from each news item the first child of elements:
// title, description, pubData, link. Put those pieces
// together into a SingleNewsItem object and add it to
// the ArrayList called: newsList
try {
Element entry = (Element) nl.item(i);
Element title = (Element) entry.getElementsByTagName(
"title").item(0);
Element description = (Element) entry.getElementsByTagName(
"description").item(0);
Element pubDate = (Element) entry.getElementsByTagName(
"pubDate").item(0);
Element link = (Element) entry.getElementsByTagName(
"link").item(0);
String titleValue = title.getFirstChild().getNodeValue();
String descriptionValue =description.getFirstChild().getNodeValue();
String dateValue = pubDate.getFirstChild().getNodeValue();
String linkValue = link.getFirstChild().getNodeValue();
// combine title & description for a simple ListView
titleValue += "\n " + descriptionValue;
if (exchangeDate.length()==0){
exchangeDate = dateValue;
}
// assemble 'singleItems' add each to the collection
SingleNewsItem singleItem = new SingleNewsItem(
dateValue,titleValue,descriptionValue, linkValue);
newsList.add(singleItem);
} catch (DOMException e) {
e.printStackTrace();
}
}//dissectNode
}//class
MAIN LAYOUT
<?xmlversion="1.0"encoding="utf-8"?>
LinearLayoutxmlns:android="
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ff006666"
ProgressBar
android:id="@+id/myProgress1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5px"
style="?android:attr/android:progressBarStyleSmall"/>
TextView
android:id="@+id/myMsg"
android:text="Please wait ..."
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout
ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
/>
</LinearLayout
my_simple_list_line_1.xml (small font)
<?xmlversion="1.0"encoding="utf-8"?>
TextViewxmlns:android="
android:id="@android:id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingLeft="10dip"
android:textSize="14sp"
android:minHeight="40sp"
/>
Manifest
<?xmlversion="1.0"encoding="utf-8"?>
manifestxmlns:android="
package="cis493.testa"
android:versionCode="1"
android:versionName="1.0"
applicationandroid:icon="@drawable/icon"android:label="@string/app_name"
activityandroid:name=".USD_Exchange"
android:label="@string/app_name"
intent-filter
actionandroid:name="android.intent.action.MAIN"/>
categoryandroid:name="android.intent.category.LAUNCHER"/>
</intent-filter
</activity
</application
uses-sdkandroid:minSdkVersion="8"/>
uses-permissionandroid:name="android.permission.INTERNET"</uses-permission
</manifest
Fragment of [ response ] RSS XML file received by client
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="../css/rss.css" ?>
<rss version="2.0" xmlns:atom="
<channel>
<title>Exchange Rates For US Dollar</title>
<link>
<description>The latest currency exchange rates for US Dollar</description>
<lastBuildDate>Thu, 17 Feb 2011 21:15:39 GMT</lastBuildDate>
<language>en-us</language>
<copyright>Copyright: (C) The Money Converter, see </copyright>
<docs>
<ttl>15</ttl<image>
<title>Exchange Rates For US Dollar</title>
<url>
<link>
<item>
<title>AED/USD</title<link>
<guid>e4600198-9686-4cfa-b20d-fb8a31919420</guid>
<pubDate>Thu, 17 Feb 2011 21:15:39 GMT</pubDate>
<description>1 US Dollar = 3.6725 United Arab Emirates Dirham</description>
<category>Middle East</category>
</item>
<item>
<title>ARS/USD</title<link>
<guid>7d01193a-a366-4cde-ac37-caec09d6faae</guid>
<pubDate>Thu, 17 Feb 2011 21:15:39 GMT</pubDate>
<description>1 US Dollar = 4.02397 Argentine Peso</description>
<category>South America</category>
</item>
CONSUMING WEB SERVICES PLACED IN AN APACAHE TOMCAT 7.0 SERVER
This example assumes you have installed the Apache Tomcat 7.0 Server in your computer
(Download from: The server comes with a set of samples located in the folder C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\examples\servlets
(assuming you installed on Windows, using Program Files directory).
In this sample the webservices are implemented in Java Servlets. One of them is the requestParamentersExample.
{[execute.gif]}{[return.gif]}
Source Code for Request Parameter Example
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestParamExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Request Parameters Example</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Request Parameters Example</h3>");
out.println("Parameters in this request:<br>");
if (firstName != null || lastName != null) {
out.println("First Name:");
out.println(" = " + HTMLFilter.filter(firstName) + "<br>");
out.println("Last Name:");
out.println(" = " + HTMLFilter.filter(lastName));
} else {
out.println("No Parameters, Please enter some");
}
out.println("<P>");
out.print("<form action=\"");
out.print("RequestParamExample\" ");
out.println("method=POST>");
out.println("First Name:");
out.println("<input type=text size=20 name=firstname>");
out.println("<br>");
out.println("Last Name:");
out.println("<input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
doGet(request, response);
}
}
In the example we need to supply first and last name. The request object is sent to the service, the arguments are extracted and echoed back to the user in a response object. The response is a well formed HTML document. In our Android application we drop the response into a WebView for displaying.
For the sake of the example assume the web server’s IP address is 192.169.0.183. When using the Android emulator we cannot use the url neither (the connection will be refused because of collisions with the emulator). Insteac you will have to provide a ‘real’ IP url.
Layout
<?xmlversion="1.0"encoding="utf-8"?>
WebViewxmlns:android="
android:id="@+id/webkit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
</WebView
Manifest needs Internet permission
uses-permissionandroid:name="android.permission.INTERNET"/>
Code
// Consuming a web-service residing in an local Apache Tomcat server
// WebService is a sample that comes with the installation package.
// The example asks for user's first & last name.
// The response is a valid HTML file that echoes the input values.
// ------
package ucr.netdemo1;
import. . .
publicclass Main extends Activity {
TextViewtextView;
WebViewbrowser;
publicenumRequestMethod {
GET, POST
}
@Override
publicvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Toast.makeText(this,
"Warning!\nThis code needs your Apache server's current IP.", 1).show();
browser = (WebView) findViewById(R.id.webkit);
useMethod1();// try this method first
// useMethod2(); // try this method next
}// onCreate
// ======
// VERSION 1.
// You assemble the URL. Separate arguments with a '$' sign. Arguments are
// pair of name=value elements (eg. firstname=maria)
// Based on:
publicvoid useMethod1() {
// url consists of: link2WebServRepository?servletName&argument(s)
String url = "
+ "RequestParamExample?firstname=Maria1&lastname=Macarena1";
try {
DefaultHttpClient client = newDefaultHttpClient();
URI uri = newURI(url);
HttpGetmethodGet = newHttpGet(uri);
HttpResponse response = client.execute(methodGet);
InputStreamisResponseData = response.getEntity().getContent();