Upload
peterbuck
View
910
Download
3
Tags:
Embed Size (px)
Citation preview
Writing a Web Service Client App for Android© 2010 http://wolfpaulus.com
Agenda
Server Side (e.g. Tomcat)
Hessian, Binary Protocol
Http-Session Support
Client
hessdroid
remote calls / async
Quick Tips
Use Android’s R.class
Auto-Launch an Intent at boot time
Client
Things that can will go wrong
Agenda
Switch Activity
Switch Activity
Remote call
reload users
Remote Call to getNext
Four item main menu
Copyright © 2010 http://wolfpaulus.com
Exposing a Service Class: Hessian Binary Web Service Protocol
Copyright © 2010 http://wolfpaulus.com
package com.carlsbadcubes.api;
import java.util.Collection;
public interface CommService { Collection<Message> getMessages();
Collection<User> getUsers();}
Copyright © 2010 http://wolfpaulus.com
Copyright © 2010 http://wolfpaulus.com
<?xml version="1.0" encoding="UTF-8"?><web-app>
<servlet> <servlet-name>myservice</servlet-name> <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
<init-param> <param-name>service-class</param-name> <param-value>com.carlsbadcubes.impl.CommServiceImpl</param-value> </init-param>
<init-param> <param-name>api-class</param-name> <param-value>com.carlsbadcubes.api.CommService</param-value> </init-param>
</servlet>
<servlet-mapping> <servlet-name>myservice</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping>
</web-app>
Copyright © 2010 http://wolfpaulus.com
Interface
Implementation
defined in hessian.jar
Copyright © 2010 http://wolfpaulus.com
Roles <security-role> <role-name>HessianService</role-name> </security-role> <login-config> <auth-method>BASIC</auth-method> <realm-name>default</realm-name> </login-config> <security-constraint> <web-resource-collection> <web-resource-name>SecureConnection</web-resource-name> <url-pattern>/service/*</url-pattern> <url-pattern>/comm/*</url-pattern>
... <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>HessianService</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint>
Groups or Principals
Communication
Components
Access Privileges
Realm
Copyright © 2010 http://wolfpaulus.com
Copyright © 2010 http://wolfpaulus.com
Servlet
Thread
Thread
Thread
m_var
http requests
ServiceClassimpl.
ServiceAPI
created in servlet.init()
(1)
(1)
(1)
(n)
::
Copyright © 2010 http://wolfpaulus.com
http response
JSESSIONID = 123
JSESSIONID = 789
JSESSIONID = 357
SessionMap
123
789357
Servlet
Thread
Thread
Thread
m_var
ServiceClassimpl.
ServiceAPI
::
request.getSession()
Copyright © 2010 http://wolfpaulus.com
http response
JSESSIONID = 123
JSESSIONID = 789
JSESSIONID = 357
SessionMap
123
789357
http request Servlet
Thread
Thread
Thread
m_var
ServiceClassimpl.
ServiceAPI
::
123ThreadLocal
789ThreadLocal
357ThreadLocal
Copyright © 2010 http://wolfpaulus.com
The ThreadLocal Class:
public class ThreadLocal<T> { public void set( T newValue ); public T get(); public void remove(); protected T initialValue();}
Copyright © 2010 http://wolfpaulus.com
HessianHttpServlet extends HessianServlet implements HessianHttpService {
... }
... not in hessian.jar
Copyright © 2010 http://wolfpaulus.com
.. all of HessianServlet
Discovery Service for Android Clients
Map<String, String> getServices()
puts HttpSession Map into ThreadLocal
memory
HessianHttpServlet extends HessianServlet implements HessianHttpService
Copyright © 2010 http://wolfpaulus.com
HessianHttpServlet@Overrideinit() .. // // introspect service implementation to find out if we have to put the servlet into a session // if ( getInitParameter("service-class") != null ) { String className = getInitParameter("service-class"); if (className != null) { this.requiresSessionSupport = StateKeeper.class.isAssignableFrom(loadClass(className)); } if (this.requiresSessionSupport) { System.out.println(className + " has been registered for session support."); } }
@Overrideservice() ..
if (this.requiresSessionSupport) { HttpServletRequest req = (HttpServletRequest) request; ThreadLocalAttrMap.set( req.getSession( true ) ); }
Copyright © 2010 http://wolfpaulus.com
String url = “http://hostname.domain:port/service”;
ServiceProxyFactory factory = new HessianProxyFactory();factory.set ..(..);factory.set ..(..).
CommService cs = factory.create( CommService.class, url , getClassLoader());
hessdroidhttp://code.google.com/p/hessdroid/
Copyright © 2010 http://wolfpaulus.com
HessDroid Generified ...HessianProxyFactory:public <T>T create( Class<T> api,
String urlName, ClassLoader loader);
Clientside code without casting:Service s = (Service) factory.create( Service.class, url, cl );
hessdroidhttp://code.google.com/p/hessdroid/
Copyright © 2010 http://wolfpaulus.com
Creates a Cookie Map,Maintains HttpSessions
HessianHttpProxyFactory extends HessianProxyFactory {
... }
hessdroidhttp://code.google.com/p/hessdroid/
Copyright © 2010 http://wolfpaulus.com
Service Discovery:maps Interfaces to URLs
HessianFactory.initialize( )
... not in hessdroid.jar
Copyright © 2010 http://wolfpaulus.com
Hessian Client
CommService cs = HessianFactory.create( CommService.class, getClassLoader() )
Copyright © 2010 http://wolfpaulus.com
DemoTomcat Server with a Hessian Service and a Hessian based Android Client
Async ....
Don’t run HessionFactory.create(..) in the main threadDon’t run remote method calls in the main thread either.
Copyright © 2010 http://wolfpaulus.com
Interface Garage { void openDoor();
Car getCar();}
Interface Car {void openDoor();Color getColor();
}
Copyright © 2010 http://wolfpaulus.com
Copyright © 2010 http://wolfpaulus.com
Garage garage = HessianFactory.create( Garage.class, getClassLoader() );
// The interface Garage and the class CarImpl// need to be available on the client to make this work:
garage.openDoor(); // remote callgarage.getCar().openDoor(); // local call
Use Android’s R.XML:
<TextView android:textColor = "@color/ink" android:background= "@android:color/darker_gray" />
Code:
int c0 = getResources().getColor( R.color.ink );int c1 = getResources().getColor( android.R.color.darker_gray );
Copyright © 2010 http://wolfpaulus.com
Use Intent flags to control the flow.
XML: (Activity)<activity .. android:taskAffinity=” ”launchMode, allowTaskReparenting, clearTaskOnLaunch, alwaysRetainTaskState, finishOnTaskLaunch ..>
Code: (Intent)
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
Copyright © 2010 http://wolfpaulus.com
Auto-Launch after boot (1 of 2)
Copyright © 2010 http://wolfpaulus.com
AndroidManifest:..<receiver android:name=".BootNotificationReceiver"> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter></receiver><service android:name=".HessianService"/></application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Auto-Launch after boot (2 of 2)
Copyright © 2010 http://wolfpaulus.com
Code:
public class BootNotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
context.startService(new Intent(context, HessianService.class));
} }}
Things that can will go wrongwrong classloader:java.lang.IllegalArgumentException: com.pss.api.Service is not visible from class loaderUse AppContext.getClassLoader()
app doesn’t have Internet permission:com.caucho.hessian.client.HessianRuntimeException: java.net.SocketException: Permission deniedAndroidManifest.xml <uses-permission android:name="android.permission.INTERNET"/>
app cannot be debugged:need to add the debuggable attribute to the application tag in the AndroidManifest <application android:icon="@drawable/msg" android:debuggable="true">
wrong server URL (localhost doesn’t work.)com.caucho.hessian.client.HessianRuntimeException: java.net.ConnectException: /192.168.200.120:80 - Connection refused
Copyright © 2010 http://wolfpaulus.com
Unlocking Android
Android Wireless Application Development
Thanks For Coming!
http://twitter.com/wolfpaulus
Slides & SourcesSlides: http://wolfpaulus.com/bio/talks/androidws.pdf
Code: http://wolfpaulus.com/bio/talks/androidws.zip
Email: [email protected]