Home   |   Archivio   |   Chi siamo   |   Contatti
Marco Tomà
Wireless Messaging API
Brevi Messaggi Java
di
Marco Tomà
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).

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
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
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: BINARYMESSAGE - TEXTMESSAGE) 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.

Implementando 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
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
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.enableextraprotocols: 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 5: Invio di un Sms dal dispositivo wireless
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 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
Figura 8: Visualizzazione del contenuto del messaggio Sms ricevuto

Tabella delle porte riservate Port number Description 2805 WAP WTA secure connection-less session service 2923 WAP WTA secure session service 2948 WAP Push connectionless session service (client side) 2949 WAP Push secure connectionless session service (client side) 5502 Service Card reader 5503 Internet access configuration reader 5508 Dynamic Menu Control Protocol 5511 Message Access Protocol 5512 Simple Email Notification 9200 WAP connectionless session service 9201 WAP session service 9202 WAP secure connectionless session service 9203 WAP secure session service 9207 WAP vCal Secure 49996 SyncML OTA configuration 49999 WAP OTA configuration

Riferimenti:

HYPERLINK "http://java.com.sun" http://java.sun.com/j2me

Configurazione CLDC: HYPERLINK "http://www.mokabyte.it/2002/02/j2me2.htm" http://www.mokabyte.it/2002/02/j2me2.htm Generic Connection Framework: HYPERLINK "http://www.mokabyte.it/2002/07/j2me-6.htm" http://www.mokabyte.it/2002/07/j2me-6.htm JavaComm e GSM: HYPERLINK "http://www.mokabyte.it/2002/09/javasms.htm" http://www.mokabyte.it/2002/09/javasms.htm HYPERLINK "http://www.gsmworld.com/index.shtml" http://www.gsmworld.com/index.shtml Protocollo GSM HYPERLINK "http://www.etsi.org" 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