PDF Slides, 4.2MB - Wolf Paulus

Preview:

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

Copyright © 2010 http://wolfpaulus.com

Java Hessian

Copyright © 2010 http://wolfpaulus.com

Java Hessian

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

= Client

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