MokaByte 67 - 8bre 2002 
J2ME e gli SMS
Wireless Messaging API: brevi messaggi Java
di
Marco Toma
Il sistema di messaggistica Sms, offerto dalla tecnologia Gsm è diventato, di fatto, un nuovo modo di comunicare. Vediamo, in questo articolo, come si possono creare ed inviare messaggi Sms in Java da un apparato wireless

La possibilità di inviare e ricevere messaggi sms da un dispositivo wireless, utilizzando librerie Java, può, a prima vista, sembrare superflua: è vero, infatti, che la maggior parti di tali apparati (non solo cellulari e smart-phone ma anche numerosi PDA) sono già dotati di tali funzionalità.
I sistemi di gestione degli sms di un dato apparato non sono però accessibili alle applicazioni Java (per ragioni di sicurezza imposte dal Sandbox Model e per la mancanza del supporto di Java Native Interface da parte di CLDC/MIDP) se non ricorrendo all'utilizzo di librerie proprietarie fornite dal produttore del dispositivo stesso. Quest'ultima soluzione porta però alla realizzazione di applicazioni "troppo dedicate" ad una determinata marca di apparati o addirittura di modelli, limitando pesantemente la portabilità del codice. Le Wireless Messaging API (WMA) invece, essendo una vera e propria java-extension, possono garantire lo stesso grado di portabilità software offerto dall'ambiente Java stesso (CLDC e MIDP in questo caso). Quello che, infatti, può variare, rispetto ai vari dispositivi utilizzati, è l'implementazione delle librerie mentre il loro utilizzo, a livello di applicazione, è completamente cross-platform. Questo da la possibilità di eseguire il medesimo applicativo in tutti gli apparati per i quali esiste un'implementazione delle WMA (e dell'ambiente J2ME - es: MIDP/CLDC).

 

L'architettura delle WMA
Le classi e le interfacce che compongono le Wireless Messaging API possono essere suddivise in tre diversi strati: questi corrispondono ad altrettanti livelli di astrazione rispetto al dispositivo host. Come è possibile osservare in figura 1, le applicazioni Java (Midlet) hanno accesso solo al livello più alto dell'architettura. Tale livello fornisce un insieme di interfacce che contengono la definizione dei metodi, di cui un'applicazione Java potrà disporre, per l'invio e la ricezione di messaggi sms. Lo strato inferiore rappresenta l'implementazione di tali interfacce, mentre il livello più basso, quello più "vicino" alla piattaforma hardware, implementa i protocolli di trasporto per l'effettiva trasmissione e ricezione dei messaggi.


Figura 1 - Architettura delle WMA


Le interfacce delle Wireless Messaging API (figura 2), permettono di "nascondere" i dettagli implementativi alle MIDlet (e ai programmatori...).In particolare esse si preoccupano di garantire funzionalità per la gestione delle connessione (invio e ricezione dei messaggi), e la definizione degli oggetti (java) che rappresentano il messaggio stesso.




Figura 2 - Interfacce delle WMA


Message rappresenta la "definizione base" di un messaggio: essa fornisce i seguenti tre metodi:

public String getAddress( )
public void setAddress( )
public Date getTimestamp( )

i primi due permettono rispettivamente di ottenere e settare l'indirizzo di un messaggio, mentre l'ultimo consente di ricavare l'istante di invio del messaggio.
L'interfaccia Message è estesa da BinaryMessage e TextMessage (Figura 2):
BinaryMessage rappresenta un messaggio il cui campo dati è in formato binario:

public byte[ ] getPayloadData( )
public void setPayloadData(byte[ ] data)

permettono di leggere (get) e scrivere (set) il campo dati (payload) del messaggio.
TextMessage definisce un messaggio di puro testo, con i metodi:

public String getPayloadText( )
public void setPayloadText(String data)

è possibile ottenere la rappresentazione stringa del campo dati, mentre setPayloadText ne permette il settaggio. La differenza principale tra un messaggio di tipo "text" e uno "binary" sta nel tipo di codifica utilizzato ( 7-bit o UCS-2 nel primo caso, 8-bit nel caso di messaggi binari come previsto dallo standard GSM 03.38).
L'interfaccia MessageConnection rappresenta la connessione per l'invio e la ricezione dei messaggi. Un oggetto di tipo MessageConnection viene istanziato con una chiamata a Connector.open() (javax.microedition.io):

MessageConnection messConn = (MessageConnection) Connector.open(String connectionString);

La stringa "connectionString", passata come parametro al metodo open permette al Generic Connection Framework della CLDC di stabilire il tipo di connessione da attivare.
Nel caso delle WMA il formato previsto è del tipo:
"sms://address : port"oppure "sms://: port"a seconda che si desideri attivare una connessione in modalità client (primo caso) oppure server (indicando il solo numero della porta). Una connessione di tipo client, può essere utilizzata esclusivamente per l'invio dei messaggi mentre la modalità server ne permette sia l'invio sia la ricezione. Esempi di stringhe di connessione possono essere:

"sms://+3922728821"
"sms://+3922728821:9000"
"sms://:9002"

(In realtà le WMA supportano anche i Cell Broadcast Sms, un particolare tipo di sms che, trasmesso da una stazione radio base vengono ricevuti da tutti i terminali mobili in ascolto con quella stazione. Le stringhe di connessione in questo caso hanno il seguente formato:
"sms://:8000").

Poiché alcune porte sono riservate ad usi specifici le applicazioni Java non possono, per ragioni di sicurezza, aprire connessioni in ascolto su tali porte (un elenco delle porte riservate è riportato in appendice).
Una volta attivata la connessione la si può utilizzare per l'invio e la ricezione dei messaggi.
Il metodo newMessage consente la creazione di nuovi messaggi e prevede due diverse firme:

public Message newMessage(String type)
public Message newMessage(String type, String address)

nella prima occorre specificare il tipo (variabili statiche: BINARY_MESSAGE - TEXT_MESSAGE) nella seconda anche l'indirizzo (del destinatario).

Utilizzando i metodi di Message e delle sue estensioni (TextMessage e BinaryMessage) è possibile manipolare il campo dati e il campo indirizzo del messaggio, che, una volta pronto, può essere inviato con il metodo:

public void send(Message msg)

Per quanto riguarda la ricezione il metodo:

public Message receive()

rimane in attesa (è bloccante) dell'arrivo di un messaggio o della chiusura della connessione.
In alternativa all'utilizzo del metodo receive si può ricorrere ad un meccanismo di listening:

public void setMessageListener(MessageListener listener)

permette l'aggancio di un listener ad una connessione.
I
mplementando poi l'interfaccia MessageListener è possibile gestire la ricezione di un messaggio. attraverso il metodo (unico):

public void notifyIncomingMessage(MessageConnection connection)

che viene richiamato alla ricezione di ogni messaggio sulla connessione aperta (alla quale è stato "collegato" il listener).

Concludiamo la trattazione delle interfacce delle WMA con il metodo:

public int numberOfSegments(Message msg)

esso ritorna il numero di segmenti (parti) in cui il protocollo di trasporto deve dividere il messaggio passato come parametro per poterlo inviare. Occorre precisare, che nell'attuale implementazione delle WMA, questo metodo non esegue l'invio dei messaggi ma solo il conteggio dei segmenti.
Una volta terminate le operazioni si può procedere alla chiusura della connessione con il metodo

public void close( )

ereditato da javax.microedition.io.Connection.

Attualmente esiste una sola implementazione delle librerie WMA: quella di riferimento della Sun Microsystem. Vediamo brevemente il suo funzionamento (Figura 3).
La classe Protocol rappresenta l'implementazione dell'interfaccia MessageConnection, vista precedentemente. Essa si occupa di verificare la validità e la sintassi dei parametri di connessione, rilanciando eventuali eccezioni al livello applicazione, recupera, a run-time, eventuali parametri di configurazione ( che vedremo tra breve), la gestione di un eventuale listener collegato alla connessione, gestisce la segmentazione e la concatenazione dei messaggi per i protocolli di trasporto. TextObject e BinaryObject implementano rispettivamente TextMessage e BinaryMessage ed entrambe estendono la classe MessageObject. Quest'ultima è l'implementazione dell'interfaccia Message e costituisce "un messaggio java", mentre TextMessage rappresenta un messaggio di testo e BinaryMessage uno binario puro.



Figura 3 - Implementazione delle WMA

 

Il "livello trasporto" (vedi figura 4), ha il compito di fornire un insieme di classi (usate a run-time) per la gestione dei meccanismi di trasporto dei messaggi, cioè per le effettive operazioni di invio e ricezione delle informazioni. L'attuale implementazione di riferimento prevede due tipi di "protocolli di trasporto": uno via datagram (utile per lo sviluppo e il testing di applicazioni) l'altro via porta seriale utilizzabile su reti GSM reali (inviando comandi AT ad un telefono o ad un modem GSM).




Figura 4 - Il livello di trasporto


Prima di concludere con un esempio di utilizzo delle librerie, facciamo un breve passo indietro e riprendiamo il discorso della configurazione precedentemente accennato.
Per poter utilizzare le WMA occorre modificare il file di configurazione del MIDP. Si tratta del file internal.config (solitamente ne sono presenti due: internal.config e system.config, le proprietà del primo sono accessibili con com.sun.midp.Configuration.getProperty(propName) quelle presenti in system con System.getProperty(propName) ) al quale vanno aggiunte le seguenti righe:

Specifica il tipo di protocollo di trasporto da utilizzare

com.sun.midp.io.j2me.sms.Impl: com.sun.midp.io.j2me.sms.DatagramImpl

il valore alternativo può essere (nell'implementazione di riferimento)

com.sun.midp.io.j2me.sms.Impl=com.sun.midp.io.j2me.sms.DatagramImpl

Parametri di configurazione per l'utilizzo dei datagram ( host-porte)

com.sun.midp.io.j2me.sms.DatagramHost: localhost
com.sun.midp.io.j2me.sms.DatagramPortIn: 54321
com.sun.midp.io.j2me.sms.DatagramPortOut: 12345

Permessi di ricezione/invio dei messaggi Sms

com.sun.midp.io.j2me.sms.permission.receive: true
com.sun.midp.io.j2me.sms.permission.send: true

Permesso per la ricezione di messaggi di tipo cbs

com.sun.midp.io.j2me.cbs.permission.receive: true

Permesso per l'utilizzo delle connessioni (sms/cbs)

javax.microedition.io.Connector.sms: true
javax.microedition.io.Connector.cbs: true

Settaggio di una porta alternativa per l'emulazione dei messaggi cbs

com.sun.midp.io.j2me.sms.CBSPort: 24680

Abilitazione all'utilizzo delle connessioni comm (seriale) e datagram

com.sun.midp.io.enable_extra_protocols: true

Indirizzo del centro servizi SMS

wireless.messaging.sms.smsc: +17815511212

Quello che segue è un esempio di utilizzo delle librerie WMA. La parte "server" è composta dalle seguenti due classi:

package smstest;

import java.awt.*;

public class SmsTester {

public static void main(String[] args) {
SmsFrame frame = new SmsFrame();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height)
frameSize.height = screenSize.height;
if (frameSize.width > screenSize.width)
frameSize.width = screenSize.width;
frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
frame.validate();
}

}

package smstest;

import java.io.*;
import java.net.*;
import java.util.*;
import java.text.SimpleDateFormat;
import java.awt.*;
import java.awt.event.*;
import com.sun.tck.wma.*;
import com.sun.tck.wma.sms.*;

public class SmsFrame extends Frame {

Panel smsPanel = new Panel();
GridBagLayout gridBagLayout1 = new GridBagLayout();
TextField smsNumber = new TextField();
TextField smsText = new TextField();
java.awt.List smsIncomingList = new java.awt.List();
Label label1 = new Label();
Label label2 = new Label();
Label label3 = new Label();
Button sendButton = new Button();

static MessageConnection messageConnection;

public SmsFrame() {
try {
//Apre una connessione sulla porta 9001 (modalità server)
messageConnection = new SMSConnector().open("sms://:9001");
//Crea e manda in esecuzione un nuovo thread per la ricezione dei messaggi SMS in arrivo
new Thread(new ReceiverMessage()).start();
init();
} catch( Exception ee)
{
ee.printStackTrace();
}
}

private void init() throws Exception {
this.setBackground(new Color(157, 157, 173));
this.setSize(new Dimension(400, 493));
this.setResizable(false);
this.addWindowListener(new java.awt.event.WindowAdapter() {

public void windowClosing(WindowEvent e) {
this_windowClosing(e);
}
});
smsPanel.setLayout(gridBagLayout1);
smsNumber.addActionListener(new java.awt.event.ActionListener() {

public void actionPerformed(ActionEvent e) {
smsNumber_actionPerformed(e);
}
});
label1.setFont(new java.awt.Font("Dialog", 1, 12));
label1.setText("Sms Number");
label2.setFont(new java.awt.Font("Dialog", 1, 12));
label2.setText("Sms Text");
label3.setFont(new java.awt.Font("Dialog", 1, 12));
label3.setText("Sms List");
sendButton.setBackground(Color.lightGray);
sendButton.setFont(new java.awt.Font("Dialog", 1, 12));
sendButton.setLabel("Send Sms");
smsText.setBackground(Color.gray);
smsText.setForeground(Color.black);
smsNumber.setBackground(Color.gray);
smsNumber.setForeground(Color.black);
smsIncomingList.setBackground(Color.lightGray);
smsIncomingList.setFont(new java.awt.Font("Dialog", 1, 12));

sendButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
sendButton_actionPerformed(e);
}
});

smsIncomingList.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
smsIncomingList_actionPerformed(e);
}
});

smsText.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
smsText_actionPerformed(e);
}
});

smsNumber.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
smsNumber_actionPerformed(e);
}
});

smsIncomingList.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
smsIncomingList_actionPerformed(e);
}
});

smsIncomingList.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
smsIncomingList_actionPerformed(e);
}
});

this.add(smsPanel, BorderLayout.CENTER);
smsPanel.add(smsText, new GridBagConstraints(0, 3, 4, 1, 0.0, 0.0
,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 331, 0));
smsPanel.add(smsNumber, new GridBagConstraints(0, 1, 3, 1, 0.0, 0.0
,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 2), 197, 0));
smsPanel.add(label1, new GridBagConstraints(0, 0, 3, 1, 0.0, 0.0
,GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
smsPanel.add(label2, new GridBagConstraints(0, 2, 3, 1, 0.0, 0.0
,GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, new Insets(1, 10, 0, 0), 0, 3));
smsPanel.add(smsIncomingList, new GridBagConstraints(0, 6, 3, 1, 0.0, 0.0
,GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(10, 30, 10, 43), 204, 218));
smsPanel.add(label3, new GridBagConstraints(0, 5, 2, 1, 0.0, 0.0
,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 10, 0, 96), 0, 0));
smsPanel.add(sendButton, new GridBagConstraints(0, 4, 1, 1, 0.0, 7.0
,GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, new Insets(1, 10, 18, 0), 2, 2));
this.setTitle(" SMS Tester");
}

void smsNumber_actionPerformed(ActionEvent e) {
}

void sendButton_actionPerformed(ActionEvent e) {
sendSms();
}

void smsIncomingList_actionPerformed(ActionEvent e) {
}

void this_windowClosing(WindowEvent e) {
System.exit(0);
}

void smsText_actionPerformed(ActionEvent e) {
}

private void sendSms() {
//Stringa di connessione nel formato "sms://address:port"
String destAddress = "sms://"+smsNumber.getText()+":9002";
//Lettura del testo inserito nel textfield
String message = smsText.getText();
try {
// Creazione di un nuovo messaggi (di tipo Text)
Message mess = messageConnection.newMessage(MessageConnection.TEXT_MESSAGE);
// Inserimento del testo all'interno del messaggio
((TextMessage)mess).setPayloadText(message);
// Settaggio dell'indirizzo di destinazione del messaggio
mess.setAddress(destAddress);
// Invio del messaggio sms
messageConnection.send(mess);
} catch (Exception ioe) {
ioe.printStackTrace();
}
}

class ReceiverMessage implements Runnable {

public void run() {
while (true) {
try {
// Resta in attesa dell'arrivo di un nuovo messaggio
Message receivedMessage = messageConnection.receive();
// All'arrivo di un nuovo sms:
// Viene recuperato l'indirizzo
String destAddress = receivedMessage.getAddress();
int numberStart = destAddress.lastIndexOf("/");
int numberEnd = destAddress.indexOf(":",numberStart );
numberEnd = numberEnd == -1 ? destAddress.length() : numberEnd;
String senderNumber = destAddress.substring(numberStart +1 , numberEnd );
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
// Viene letto il timestamp relativo al momento dell'invio del messaggio
String timestamp = sdf.format(receivedMessage.getTimestamp());
// Per recuperare il contenuto occorre valutare se si tratta di un messaggio di testo
// o binario
if ( receivedMessage instanceof TextMessage)
{
// Si tratta di un messaggio di testo
TextMessage tm = (TextMessage) receivedMessage;
// Visualizza le informazioni del messaggio nella lista
smsIncomingList.add(" SMS : "+ senderNumber + " -- "+ timestamp +" -- " + tm.getPayloadText());
}
else
if ( receivedMessage instanceof BinaryMessage)
{
// Si tratta di un messaggio di binario
BinaryMessage bm = (BinaryMessage) receivedMessage;
// Visualizza le informazioni del messaggio nella lista
smsIncomingList.add(" SMS : "+ senderNumber + " -- "+ timestamp +" -- " + new String(bm.getPayloadData()));
}
} catch (Exception ioe)
{
ioe.printStackTrace();
}
}
}
}
}.

Codice del client MIDP

package midpsms;

import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.wireless.*;
import javax.wireless.messaging.*;

public class SmsManager extends MIDlet implements CommandListener, MessageListener {
private Display display;
private Form mainForm;
private Command exit;
private Command openMessage;
private Command sendMessage;
private Ticker ticker;
private MessageConnection smsConnection;
private MessageList messageList;
public static String smscAddress;


public SmsManager() {

try{
smscAddress = com.sun.midp.Configuration.getProperty("wireless.messaging.sms.smsc");
// Stringa di connessione per la connessione sms - modalità server sulla porta 9002
String smsReceivePort = "sms://:9002";
// Apertura della connessione
smsConnection = (MessageConnection) Connector.open(smsReceivePort);
// Collegamento di un listener per la notifica dei messaggi in arrivo (ricevuti)
smsConnection.setMessageListener(this);
}catch( Exception e)
{
e.printStackTrace();
}
mainForm = new Form(" SMS MANAGER ");
exit = new Command("exit",Command.EXIT, 1);
openMessage = new Command("list",Command.EXIT, 1);
sendMessage = new Command("send",Command.OK, 1);
mainForm.addCommand(exit);
mainForm.addCommand(openMessage);
mainForm.addCommand(sendMessage);
mainForm.setCommandListener(this);
ticker = new Ticker("New message incoming");
}

public void startApp() {
display = Display.getDisplay(this);
messageList = new MessageList(display, mainForm );
display.setCurrent(mainForm);
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void notifyIncomingMessage(MessageConnection smsConnection)
{
// Questo metodo viene richiamato automaticamente all'arrivo di un nuovo messaggio
try {
// Ricezione del messaggio
Message inMessage = smsConnection.receive();
// Aggiunta del messaggio alla lista
messageList.addIncomingMessage(inMessage);
// Un messaggio scorrevole (Ticker) segnala la ricezione del nuovo messaggio
if ( mainForm.getTicker() == null )
{
mainForm.setTicker(ticker);
}
} catch( Exception e)
{
System.out.println(" Error : "+ e.toString() );
}
}

public void commandAction(Command command, Displayable displayable)
{
if ( command == exit && displayable == mainForm)
{
this.destroyApp(true);
this.notifyDestroyed();
}
if ( command == sendMessage && displayable == mainForm )
{
new SendMessageForm(display, mainForm);
}

if ( command == openMessage && displayable == mainForm )
{
display.setCurrent(messageList);
}
}
}

package midpsms;

import java.io.*;
import java.util.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.wireless.*;
import javax.wireless.messaging.*;

public class MessageList extends List {

private Command back;
private Display display;
private Displayable oldDisplayable;
private Vector messages = new Vector();
private boolean toRead = false;

public MessageList(Display d, Displayable dy) {

super("Message List", List.IMPLICIT);
this.display = d;
this.oldDisplayable = dy;

setCommandListener(new CommandListener() {
public void commandAction(Command command, Displayable displayable) {
commandPerformed(command, displayable);
}
});
back = new Command("back",Command.BACK, 1);
this.addCommand(back);
}

public void addIncomingMessage( Message message ) {
Image envelope = null;
try {
envelope = Image.createImage("/icons/envelope.png");
} catch (IOException e) {}
this.append("new Message", envelope);
messages.addElement(new SmsMessage(message));
}

public boolean messageToRead () {
for ( Enumeration e = messages.elements(); e.hasMoreElements();)
{
if( ((SmsMessage)e.nextElement()).getIsToRead() == true )
return true;
}
return false;
}

public void commandPerformed(Command command, Displayable displayable) {
if( command == back )
{
display.setCurrent(oldDisplayable);
}
if( command == this.SELECT_COMMAND )
{
display.setCurrent( new SmsMessageForm( (SmsMessage) messages.elementAt(this.getSelectedIndex()), display, this ));
}
}
}

package midpsms;

import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.wireless.*;
import javax.wireless.messaging.*;
public class SendMessageForm extends Form {

private TextField smsDestNumber;
private TextField smsMessage;
private Command back;
private Command send;
private Display display;
private Displayable oldDisplayable;
private MessageConnection smsConnection;
private String smscAddress = SmsManager.smscAddress;

public SendMessageForm(Display d, Displayable dy) {
super("Send Message");
this.display = d;
this.oldDisplayable = dy;
this.setCommandListener(new CommandListener() {
public void commandAction(Command command, Displayable displayable) {
commandPerformed(command, displayable);
}
});

send = new Command("send",Command.OK, 1);
back = new Command("back",Command.BACK, 1);
smsDestNumber = new TextField(" Number ", "", 15, TextField.PHONENUMBER);
smsMessage = new TextField(" Message ", "", 160, TextField.ANY);
this.append(smsDestNumber);
this.append(smsMessage);
this.addCommand(send);
this.addCommand(back);
display.setCurrent(this);
}

/** Handle command events*/
public void commandPerformed(Command command, Displayable displayable) {
if( command == back )
{
display.setCurrent(oldDisplayable);
}
if( command == send )
{
sendSmsMessage( smsDestNumber.getString(), smsMessage.getString() );
}
}

private void sendSmsMessage( String smsDestNum, String smsMsgBody )
{
// Dopo aver effettuato alcuni controlli sui dati inseriti nella form provvede all'invio dell' SMS
Image alertImg;
Alert alert;
try {
alertImg = Image.createImage("/icons/alert.png");
alert = new Alert("", "" , alertImg, AlertType.ERROR);
alert.setTimeout(Alert.FOREVER);
}catch (IOException e)
{
alert = new Alert("", "" , null, AlertType.ERROR);
}
if( !"".equals(smsDestNum) )
{
try {
String destAddress = "sms://"+smsDestNum;
// Apertura della connessione con un ipotetico centro servizi sms
smsConnection = (MessageConnection) Connector.open("sms://"+smscAddress+":9001");
// Creazione di un nuovo messaggio di tipo "testo"
TextMessage smsTextMessage = (TextMessage)smsConnection.newMessage(MessageConnection.TEXT_MESSAGE);
// Settaggio dell'indirizzo del destinatario
smsTextMessage.setAddress(destAddress+":9001");
// Inserimento del contenuto dati (testo)
smsTextMessage.setPayloadText(smsMsgBody);
// Invio del messaggio
smsConnection.send(smsTextMessage);
// Chiusura della connessione
smsConnection.close();
} catch (Exception e)
{
alert.setString("\n ERROR SENDING \n SMS MESSAGE ");
e.printStackTrace();
display.setCurrent(alert , this);
}
}
else
{
alert.setString("\n INVALID\n NUMBER");
display.setCurrent(alert , this);
}
}
}


package midpsms;

import java.io.*;
import java.util.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import javax.wireless.*;
import javax.wireless.messaging.*;

public class SmsMessageForm extends TextBox {
private Command back;
private Command datails;
private Display display;
private Displayable oldDisplayable;
private SmsMessage smsMessage;
private boolean showDetails = false;

public SmsMessageForm( SmsMessage smsMessage, Display d, Displayable dy) {
super("Message", "", 50, TextField.ANY);
this.display = d;
this.oldDisplayable = dy;
this.smsMessage = smsMessage;

setCommandListener(new CommandListener() {
public void commandAction(Command command, Displayable displayable) {
commandPerformed(command, displayable);
}
});
back = new Command("back",Command.BACK, 1);
datails = new Command("details",Command.OK, 1);
this.addCommand(back);
this.addCommand(datails);

this.setMaxSize(smsMessage.getMessageBody().length());
this.setString(smsMessage.getMessageBody());
smsMessage.setIsToRead(false);
}

public void commandPerformed(Command command, Displayable displayable) {

if( command == back && showDetails == false )
{
display.setCurrent(oldDisplayable);
}

if( command == back && showDetails == true )
{
showDetails = false;
this.setMaxSize(smsMessage.getMessageBody().length());
this.setString(smsMessage.getMessageBody());
}

if( command == datails )
{
showDetails = true;
this.setMaxSize(smsMessage.getMessageDetails().length());
this.setString(smsMessage.getMessageDetails());
}
}
}


package midpsms;

import java.util.*;
import javax.wireless.messaging.*;

public class SmsMessage {

private String address;
private String timestamp;
private String messageBody;
private boolean toRead = true;

public SmsMessage(Message message) {

// Ottiene l'indirizzo del messaggio sms (del mittente)
address = message.getAddress();
// Ottiene il timestamp del messaggio
timestamp = getTimeStamp( message.getTimestamp() );
// Per ottenere il campo dati occorre valutare se si tratta di un messaggio di testo o binario
if (message instanceof TextMessage) {
TextMessage textSmsMessage = (TextMessage)message;
messageBody = textSmsMessage.getPayloadText();
}
else
if (message instanceof BinaryMessage) {
BinaryMessage binarySmsMessage = (BinaryMessage)message;
messageBody = new String (binarySmsMessage.getPayloadData());
}
}

public String getMessageDetails () {
return "Sender : "+ address + "\n Date : "+ timestamp;
}

public String getMessageBody () {
return messageBody;
}

public boolean getIsToRead () {
return toRead;
}

public void setIsToRead (boolean read ) {
toRead = read;
}

private String getTimeStamp (Date timestamp ) {
Calendar c = Calendar.getInstance();
c.setTime(timestamp);
String ts = "";
ts += " " + c.get(Calendar.DAY_OF_MONTH);
ts += "/" + (c.get(Calendar.MONTH) + 1);
ts += "/" + c.get(Calendar.YEAR);
ts += " " + c.get(Calendar.HOUR_OF_DAY);
ts += ":" + c.get(Calendar.MINUTE);
ts += ":" + c.get(Calendar.SECOND);
ts += ":" + c.get(Calendar.MILLISECOND);
return ts;
}
}


Il funzionamento di tale applicazione è visibile nelle figure seguenti.


Figura 5 - Invio di un Sms dal dispositivo wireless

 


Figura 6 - Ricezione del messaggio da parte del "server"

 


Figura 7 - Invio di un Sms al dispositivo wireless e sua ricezione.
In alto a destra è visibile il ticker che segnala la ricezione del nuovo messaggio



Figura 8 - Visualizzazione del contenuto del messaggio Sms ricevuto



Tabella 1 - le porte riservate

 

Bibliografia e riferimenti
Sito di riferimento su J2ME
  http://java.sun.com/j2me
Configurazione CLDC:
  http://www.mokabyte.it/2002/02/j2me_2.htm
Generic Connection Framework:
  http://www.mokabyte.it/2002/07/j2me-6.htm
JavaComm e GSM:
  http://www.mokabyte.it/2002/09/javasms.htm
  http://www.gsmworld.com/index.shtml
Protocollo GSM
  http://www.etsi.org

 

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it