Synopsis emnebeskrivelse Fag:
system integration
Navn: Emne: Foreløbig problemformulering:
Bjarne hansen Hvordan bruger Android system-Integrations-patterns Undersøge hvordan Android systemet bruger design patterns, som er relateret til udveksling af beskeder mellem uafhængige systemer, eller mellem subsystemer indenfor eet system, altså system-integration!. Et af hovedemnerne er undersøgelse af message bus: -bruger Android det, og I så fald hvordan? -Fordele, ulemper ved Androids implementering Hvordan er Intent-mekanismen (Androids implementering af Observer-pattern) implementeret? -Sker der message-filtering for lyttende enheder? Hvad typer message-channels bruges Hvordan fungerer routing
Hovedemnerne: Jeg viser at Android Systemet implementerer mange elementer vi har berørt i System Integration kurset, som hører til WebService arkitektur, bla. -SOA-trekantens bestanddele genfindes. -en lidt speciel message-channel mekanisme med centralt styring, message-kø, en slags content-filtrering. -broadcast, point-point. Synopsis hovedtekst: s. 1-7 Bilag s.7-14
Diverse:
Jeg har haft stor fornøjelse af undervisningsmateriale her http://grail.cba.csuohio.edu/~matos/notes/cis-493/AndroidSyllabus.pdf
Bjarne Hansen
1/15
System-Integration Synopsis
INTENT-OBJECT ER BASIS FOR MESSAGE-MEKANISME [ ] er optional attributter Action:
for ikke-broadcast, udtryk for ”aktivitet der ønskes udført udføres” for broadcast: notification om event, fx ”battery low”
[Data]=[URI=reference resource][mimeType] Action og Data er de primære attributter, som er tilstrækkelige i mange tilfælde:
ACTION_PHONE_STATE_CHANGED broadcastes af TelephonyManager ved opkald. [Component name]: Eksplicit Modtagernavn. Hvis komponent A skal kalde bestemt modtager komponent B; ofte til intern kommunikation mellem komponenter indenfor én applikation. Hvis ikke angivet (implicit target), laver systemet Intent-Resolution: finder modtager(e) der kan håndtere opgaven, se nedenfor [Category]: fx CATEGORY_BROWSABLE: app kan åbnes som link i browser [Ekstras]: eventuel overførelse af parametre som
-altså selv-beskrivende som XML, fx
BESKEDER SENDES I FORM AF INTENTS på meget simpel måde, som Eks.1, 2 og 3 viser Eks.1. Komponent A-kode (skitsér hvordan A kan få afsendt sms vha ekstern component) Intent intent = new Intent( Intent.ACTION_SENDTO, Uri.parse("sms:5551234")); /* Data= Uri.parse("sms:5551234") */ Intent.putExtra("sms body" "are we playing golf next Saturday?"); /* overføres som selv-beskrivende data, */ startActivity(intent); /* A kalder system: ‘find component der afsender sms’ */
Eks.2 viser kode-del der åbner hjemmeside Intent myIntent = new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.google.com")); startActivity(myIntent);
Bjarne Hansen
2/15
System-Integration Synopsis
Eks.3 åbner tlf-opkalder-modulet indenfra aktive component Intent myIntent = new Intent(Intent.ACTION_DIAL,Uri.parse("tel:123 ")); startActivity(myIntent);
SOA-TREKANTEN simplificeret Service consumer får link til WSDL-dokument hos service-udbyderen fra brokeren. Brokeren(mægleren) skal gerne være et centralt register over mange service-udbyders services, fx som NemHandel. Service beskrives i UDDI-dokument, som har 3 komponenter: 1) kontakt-info til serviceudbyder, 2) services inddeles i kategorier, 3) teknisk info om api til services.
INTENT-FILTER ~ WSDL-filen i SOA. Applikationen fremviser/udbyder sine services med AndroidManifest.xml filen, se eksempel i bilag 2 og 3. I filen står også eventuelle permissions-krav for at komponenten kan virke (fx at applikation skal have adgang til kalenderen, gps-info mv), se bilag 3.
En applikation kan bestå af 4 typer components: Activity: beregnet til UI, Service: beregnet til give baggrunds-service for andre komponenter BroadcastReceiver: som lytter efter broadcast
Bjarne Hansen
3/15
System-Integration Synopsis
ContentProvider: muliggør at app kan dele sine data til eksterne applikationer De 3 første kan alle udbyde service i en SOA-betydning. Når applikation installeres læser systemet AndroidManifest.xml -filen, i en statisk serviceregistrering: - Eventuelle permissions skal accepteres af brugeren ved promp. -’service-udbuddet’ registreres i systemet. -alternativt kan en applikation registrere sine ’services-udbud’ dynamisk til systemet.
INTENT-RESOLUTION svarer til 2)+3) i SOA-trekanten. Android-systemet virker som broker til at finde modtager(e) til en service-opgave (som kommer til systemet i form af en Intent I) når intet component-name er angivet. Modtager-komponent findes ved følgende test af I op mod IntentFilteret for komponenten, simplificeret forklaret: -Hvis action er specificeret skal den matche en af -værdierne Skal I fx initialiserer brugerens opstart af en activity, skal action=’android.intent.action.MAIN’, action=’android.intent.action.DIAL’ bruges til at aktivere tlf opkald-komponet
-Hvis category-værdi(er) er specificeret skal de(n) matche i filteret, ‘CATEGORY_BROWSABLE’ betyder fx at komponent med matches. Brug af category følger faktisk kategori-inddelinger der anvendes I UDDI indenfor SOA.
-Hvis [Data]=[URI=reference resource][mimeType] nævnes skal disse matche, mimeType=’audio/mpeg’ kræver simplificeret at modtager-komponent kan håndtere mpeg. Kun hvis alle specifikationer kan matches af mindst et af filter-delkomponenterne kan systemet sende opgaven til denne, opgaven kan så populært sagt passerer ind gennem Intent-filteret. Men det er systemet som fordeler opgaven i sidste ende, en content baseret routing Tilsvarende ’åbnes med’-mekanismen i Windows promptes brugeren for valg af standard applikation for behandling af en bestemt Intent-type første gang.
BROADCAST-MEKANISME Ønsker en applikation at modtage besked om system-events, fx ’battery low’, ’telefons orientering ændret’ skal den registreres som BroadcastReceiver i Manifest-filen eller under runtime med
Bjarne Hansen
4/15
System-Integration Synopsis
registerReceiver metoden; Manifest-filen i bilag 3 har IntentFilter med entry
> />
Men det er faktisk ikke nødvendigt at medtage i Manifest-filen. Men kan nemlig også registre IntentFilter dynamisk sådan, som jeg lige har testet: IntentFilter filter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED"); registerReceiver(mySmsReceiver, filter); //opstart af service Når der kommer en sms til telefonen, udsender systemet Broadcast med I(action="android.provider.Telephony.SMS_RECEIVED").
Det anbefales at BroadcastReceiver kun tager hånd om simple opgaver, en receiver bør sende krævende opgaver videre til en service. Publisher/subscriber pattern bruges: alle applikationer der registreres til ’battery low’ -event kaldes af systemet med deres onReceive(Intent:I) metode. Der kan bruges prioriteret rækkefølge med synchron besked med sendOrderedBroadcast(), hvor receiverne får besked én af gangen; systemet kan behandle respons fra receiver (har jeg læst et sted), der kan eventuelt overføres data fra den ene broadcast-receiver til den næste i ’kæden’, efter et filterings-pattern. Dette kan ses som Composed Routing composed Message Processor hvor systemet kan virke som ProcessManager og ScatterGather-enhed. Alternativt kan bruges asynchron beskeder med sendBroadcast(), hvor rækkefølge er ustyret og flere app faktisk kan behandle eventen samtidigt. Det er altså tale om et system-styret broadcast system, fordele herved: Undgå ’trafik-kaos’ på message-channel, mulighed for styret broadcast. Og det er ikke et problem med afhængighed af et centralt styret system (bryder systemet ned er alt jo lige meget!). En applikation der opdager at eventen er indtruffet, fx batteri-måler-app, kan give besked til systemet om at broadcast’e eventen videre med sendBroadcast() eller sendOrderedBroadcast() kald. LocationManager er ikke broadcast-baseret for ny location, vil givetvis oversvømme system med broadcasts, men udsender notification om nye locationsdata: applikation kan subscribe ’sømløst’ til modtage disse.
MESSAGE-CHANNEL Bjarne Hansen
5/15
System-Integration Synopsis
Styres af systemet. Request uden modtager-navn går til systemet som videresender til rette komponent. Systemet virker som mellemmand (SOAP kommunikationsformer) En komponent kan dog godt sende direkte til navngiven modtager-komponent (point-point kanal). Det kan både ske synchront (uden retur-respons) og asynchront, hvor callback funktions mekanisme bruges: onActivityResult() kaldes, som det er vist i figuren og bilag1.
Figur over Message message kanal, I testes mod filter vha. action, category, Data[URI,mimeType]
KØ-MEKANISME FOR BESKEDER
Bjarne Hansen
6/15
System-Integration Synopsis
Kø-mekanisme figur. Baggrundstråd Thread1 i app A kan sende besked til app B, 1) først skal app A have en free token med obtainMessage() og dernæst kan A anbringe Intent i Message Queue med 2) sendMessage(). Et Handler object og tilhørende hjælpetråd, fx r1, servicerer køen, B’s hovedtråd fortsætter hele tiden, og varetager bla. koordinerede opgaver.
Services kan startes og afsluttes med – Context.startService() – Context.bindService() /* etablerer en egentlig connection */ – stopService(…) and unbindService(…)
KARAKTERISTIKA VED WEBSERVICE -Løs kobling mellem komponenter. Det har Android fx med dynamisk ’plug & play’ registrering, man kan fx registrere alternativ sms-service til systemets indbyggede sms-applikation uden anden påvirkning af systemet end at brugeren skal vælge default sms-applikation.
Bjarne Hansen
7/15
System-Integration Synopsis
-Messaging på channel(bus), forkert. Men i event-drevet kommunikation kan forretningspartner lytte til events på vores ESB, og det er distribueret service men ikke en service i ’SOA-trekantforstand’. Både simpel content-baseret routing (system router jo afhængig af intent-indhold), men nok også(?) mulighed for composed routing composed Message Processor ved brug af avanceret system-styret broadcasbeskeder(uvigtig bemærkning).
Examples of open-source ESB med WebService are Mule and Open ESB. -Kø-mekanisme til service, ja mulighed for det. -Asynchron/synchron kommunikation, ja. -BroadCast (i event-drevet opsætninger vel en form for webservice), ja. -Selv-beskrivende beskeder(typisk med XML-dokumenter), ja på sin vis. Parametre kan overføres som ordnet {}-collection i som Intent Bundle objekt, se bilag1. -Centralt center for mange webservices, broker-rollen i SOA, som sikrer autentificering og autorisation(godkendt til kunne klare opgaven) for service-udbyder. Det implementeres med system-styret message-kanal. Applikationer fra registrerede App-udbyder, fx GooglePlay, er autenficerede og autoriserede (nej det er de ikke direkte af Google, men brugerkommentarer viser om de kan løse en opgave) før de installeres. Konfidentialitet, at info sendt mellem to parter ikke tilgås af andre, kun bruges til service-formål, er til vis grad sikret, ved at systemet kun sender Intent-besked[uden modtager] til passende modtager.
BILAG
Bilag 1 Eks 1. Act1_Sender,Act2_Receiver Applikation med to aktiviteter, afsender og modtager, Manifest-filen definerer Intent-filteret Med eksplicit modtager android:label="@string/app_name">
Bjarne Hansen
8/15
System-Integration Synopsis
//
Act1_Sender.java package android.tutorials; //Activity1: get two input values from user, put them in a bumble. call Activity2 to add the two numbers, show result import android.app.Activity; import android.content.Intent; import android.os.Bundle; //import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class Act1_Sender extends Activity { EditText txtVal1; EditText txtVal2; TextView lblResult; Button btnAdd; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main1); txtVal1 = (EditText)findViewById(R.id.EditText01); txtVal2 = (EditText)findViewById(R.id.EditText02); lblResult = (TextView) findViewById(R.id.TextView01); btnAdd = (Button) findViewById(R.id.btnAdd); btnAdd.setOnClickListener(new OnClickListener() { public void onClick(View v) { //get values from the UI Double v1 = Double.parseDouble(txtVal1.getText().toString()); Double v2 = Double.parseDouble(txtVal2.getText().toString()); //create intent to call Activity2, afsender , explcit modtager) Intent myIntentA1A2 = new Intent (Act1_Sender.this, Act2_Receiver.class); //create a container to ship data Bundle myData = new Bundle();
Bjarne Hansen
9/15
System-Integration Synopsis
//add data items to the container myData.putDouble("val1", v1); myData.putDouble("val2", v2); //attach the container to the intent myIntentA1A2.putExtras(myData); //call Activity2, tell your local listener to wait for response startActivityForResult(myIntentA1A2, 101); // med asynchront callback, stemples med id=101 } }); } //onCreate /////////////////////////////////////////////////////////////////////////// /// // local listener receiving callbacks from other activities @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); try { // control af id-stempel: if ((requestCode == 101 ) && (resultCode == Activity.RESULT_OK)){ Bundle myResults = data.getExtras(); Double vresult = myResults.getDouble("vresult"); lblResult.setText("Sum is " + vresult); } } catch (Exception e) { lblResult.setText("Problems ‐" + requestCode +" " + resultCode); } }//onActivityResult } //Activity1
Act2_Receiver.java package android.tutorials; import android.app.Activity; import android.content.Intent; import android.os.Bundle; //import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class Act2_Receiver extends Activity { EditText dataReceived; Button btnDone; @Override
Bjarne Hansen
10/15
System-Integration Synopsis
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main2); dataReceived = (EditText) findViewById(R.id.etDataReceived); btnDone = (Button) findViewById(R.id.btnDone); //btnDone.setOnClickListener(this); btnDone.setOnClickListener(new OnClickListener(){ public void onClick(View v) { // close current screen ‐ terminate Activity2 finish(); } }); // pick call made to Activity2 via Intent Intent myLocalIntent = getIntent(); // look into the bundle sent to Activity2 for data items Bundle myBundle = myLocalIntent.getExtras(); Double v1 = myBundle.getDouble("val1"); Double v2 = myBundle.getDouble("val2"); // operate on the input data Double vResult = v1 + v2; // for illustration purposes. show data received & result dataReceived.setText("Data received is \n" + "val1= " + v1 + "\nval2= " + v2 + "\n\nresult= " + vResult); // add to the bundle the computed result myBundle.putDouble("vresult", vResult); // attach updated bumble to invoking intent myLocalIntent.putExtras(myBundle); // return sending an OK signal to calling activity setResult(Activity.RESULT_OK, myLocalIntent); // kalder caller::onActivityResult(myLocalIntent) }//onCreate
}
Bilag 2 AndroidManifest.xml for en notepad applikation Denne består af de tre Activities: NotesList, NoteEditor, TitleEditor og ContentProvideren NotePadProvider
Bjarne Hansen
11/15
System-Integration Synopsis
Bjarne Hansen
12/15
System-Integration Synopsis
Bilag 3 // Registrerer dynamisk broadcast-receiver for sms; , receiveren sender data om modtaget sms til txt_message-box I denne application // jeg er pt. uklar om der skal være entry i Manifest.xml filen på forhånd, umiddelbart ser det ud til at filteret laves dynamisk. Jeg har haft det kørende i min emulator i en lidt anden version import import import import import public
android.app.Activity; android.content.IntentFilter; android.os.Bundle; android.util.Log; android.widget.TextView; class FancySms extends Activity { static TextView txtMsg; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e("bjarne_log", "FancySms::onCreate called"); // udskrives som E i LogCat setContentView(R.layout.main); txtMsg = (TextView)findViewById(R.id.theMessage); // define instance of local broadcast receiver MySMSReceiver mySmsReceiver = new MySMSReceiver(); // receiver's filter will accept event: ...SMS_RECEIVED IntentFilter filter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED"); // tell Android OS this receiver is ready to go registerReceiver(mySmsReceiver, filter); } }// class
// broadcast-receiveren import import import import import import
android.content.BroadcastReceiver; android.content.Context; android.content.Intent; android.os.Bundle; android.telephony.SmsMessage; android.util.Log;
Bjarne Hansen
13/15
System-Integration Synopsis
import android.widget.Toast;
//SMSReceiver: listens to broadcasted SMS_RECEIVED signals public class MySMSReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.e("bjarne_log", "onReceive called"); //Android saves in a bundle the current text-message //under name "pdus" and type: Object[]. Later we cast to //SmsMessage[]. Jargon pdu stands for "protocol data unit" Bundle bundle = intent.getExtras(); Object messages[] = (Object[]) bundle.get("pdus"); SmsMessage smsMessage[] = new SmsMessage[messages.length]; //Note: long sms are broken and transmitted into various pieces String msg = ""; int smsPieces = messages.length; for (int n = 0; n < smsPieces; n++) { smsMessage[n] = SmsMessage.createFromPdu((byte[]) messages[n]); //grab all pieces of the intercepted sms msg += "\n" + (n + 1) + " -of- " + smsPieces + "\n" + "Sender:\t" + smsMessage[n].getOriginatingAddress() + "\n" + "Body: \n " + smsMessage[n].getMessageBody(); } //show first part of intercepted (current) message Toast toast = Toast.makeText(context, "FANCY >>> Received SMS: " + smsMessage[0].getMessageBody(), Toast.LENGTH_LONG); toast.show(); FancySms.txtMsg.setText(msg); } }// class SMSReceiver
Bjarne Hansen
14/15
System-Integration Synopsis
>
Bjarne Hansen
15/15
System-Integration Synopsis