MokaByte Numero 19 - Maggio 1998
Implementazione di  una 
struttura Client Server
di
Dario
Bosi
Vediamo come sia possibile interfacciarsi con un archivio remoto per mezzo di una struttura Client Server: in questo caso il client comunica  col server via socket, ed  il server colloquia con il Database via JDBC

 

INTRODUZIONE
L'idea di questo articolo mi e' venuta leggendo le numerose lettere sulla mailing list JAVA-IT che trattano l'accesso ai Database.
Pur sapendo di affrontare argomenti gia' in parte trattati da altri collaboratori, mi e' sembrato utile fornire un esempio completo.

Il lavoro si compone di 2 parti:
- Una applicazione che gira sul server.
- Un applet che puo' essere scaricato dal server attraverso Internet.

Il client ed il server comunicano tra loro attraverso un socket.
Il socket viene aperto sulla porta 5060. Si puo' usare qualunque altra porta non occupata diversamente.

La comunicazione avviene con i metodi readLine e println.
Per migliorare le prestazioni si inviano sul socket piu' dati contemporaneamente, separati da un opportuno delimitatore.
In ricezione i singoli dati vengono ritrovati usando StringTokenizer.

APPLICAZIONE SERVER:
Il server e' stato testato in Windows NT con il JDK 1.1.3 ma dovrebbe funzionare anche sotto Unix e con tutti i JDK 1.1.x.
Esso comunica con il database attrverso il ponte JDBC-ODBC.
Per motivi legati alla sicurazza, il programma server deve girare sulla stessa macchina da cui viene scricato l'applet.

Il server e' provvisto di un batch di partenza. Il batch contiene il riferimento al classpath, e quindi deve essere modificato a seconda di come e' installato il JDK.
Inoltre sulla linea di comando bisogna indicare la fonte ODBC dei dati.
Ad esempio, se la fonte dei dati si chiama archivio, la linea di comando da digitare sara':

server archivio
Il server usa un'interfaccia a caratteri, e quindi puo' essere utilizzato anche su sistemi non grafici.
Sullo schermo viene segnalata la connessione o la disconnessione di un utente ed il numero di connessioni aperte contemporaneamente.
Per uscire da programma digitare il tasto f seguito da Invio.

APPLET CLIENT:
Il client usa il JDK 1.0.2 ed e' stato testato sotto Windows sia con Netscape che con MS Explorer.
Esso genera una frame di 780x515 pixel, e quindi richiede uno schermo almeno 800x600.

Anzitutto il client tenta di collegarsi al server per controllare che sia attivo. Se non e' attivo non consente di proseguire.

Sono possibili 4 diverse operazioni:

1 - La visualizzazione dell'intero archivio su una listbox.
2 - La modifica di un record.
3 - La cancellazione di un record
4 - L'aggiunta di nuovi record.

Le funzioni 1 e 4 sono sulla videata iniziale, mentre alla 2 e alla 3 si accede con doppio click sulla listbox.

Il campo codice, che funge da chiave, e' di tipo autoinc e viene assegnato dal server.

ARCHIVIO:
L'archivio di prova e' stato testato in formato access.
Bisogna anzitutto settare ODBC in modo che l'archivio diventi una fonte di dati ODBC. (Su windows usare Pannello di Controllo - ODBC).

La struttura dell'archivio e' la seguente:

TABELLA: persone
CAMPI: codice:----numerico autoinc
cognome:---18 caratteri
nome:------18 caratteri
indirizzo:-25 caratteri
citta:-----20 caratteri
telefono:--14 caratteri
LIMITAZIONI:
    A - Il server non e' indipendente dalla struttura dell'archivio.
    Si tratta quindi di un programma di esempio che va adattato
    alle specifiche esigenze.
    B - Non viene gestito il lock-unlock dei record.
 
BATCH DI PARTENZA DELL'APPLICAZIONE SERVER
\jdk113\bin\java -classpath .;c:\jdk113\lib\classes.zip;c:\jdk113\java\lib Server %1

SEGUONO I SORGENTI COMMENTATI DELL'APPLICAZIONE SERVER E DELL'APPLET CLIENT.

// *******************************************************************
// *  APPLICAZIONE SERVER                                            *
// *  IL NOME DELLA FONTE ODBC VIENE PASSATO SULLA LINEA DI COMANDO  *
// *******************************************************************

import java.util.*;
import java.io.*;
import java.sql.*;
import java.net.*;
import java.text.*;

public class Server {
  // La variabile nconn e' il numero di connessioni (socket) aperte.
  // E' definita static perche' viene aggiornata dalla classe ServerThread
  static int nconn = 0;
  // il metodo incnoconn viene chiamato per incrementare la variabile nconn
  static synchronized int incnconn()
    {
    ++nconn;
    return nconn;
    }
  // il metodo incnoconn viene chiamato per decrementare la variabile nconn
  static synchronized int decnconn()
    {
    --nconn;
    return nconn;
    }

  // COSTRUTTORE DI CLASSE DEL PROGRAMMA PRINCIPALE
  public static void main(String[] args) {
    ServerSocket serverSocket = null;
    String NDB;
    String sockdat;
    Database database;
    boolean listening = true;
    int port=5060;
    int numconn;

    //  LEGGO LA FONTE DEI DATI DALLA LINEA DI COMANDO
    //  deve essere il nome di una fonte odbc disponibile sul computer
    if (args.length != 1) {
      System.err.println("Errore sulla linea di comando");
      System.exit(-1);
      return;
    }
    NDB = args[0];
 

    // DETERMINO IL NOME DEL SERVER LOCALE
    // serve solo per documentazione al lancio del programma
    try {
      InetAddress indilocal = InetAddress.getLocalHost();
      System.err.println("NOME DI QUESTO SERVER: "+indilocal.toString());
      System.err.println("Per terminare il programma digitare  il tasto  f  seguito da Invio.");
    }
    catch (IOException e) {
      System.err.println(e);
    }

    // APRO UN SERVERSOCKET SULLA PORTA 5060
    // il client dovra aprire il socket sulla stessa porta.
    try {
      serverSocket = new ServerSocket(port);
    }
    catch (IOException e) {
      System.err.println("Non posso usare la porta " + port + ", " + e.getMessage());
      System.exit(1);
    }

    // Creo SINGOLA Istanza del Database
    // tutte le connessioni si appoggiano ad un unico oggetto database
    // NDB e' la fonte dei dati.
    database = new Database("jdbc:odbc:"+NDB);

    // acquisizione da tastiera del segnale di fine programma
    // devo fare un Thread separato, altrimenti blocca il programma.
    new FineThread(database).start();

    // Esegue un ciclo infinito.
    // Ogni volta che un utente si collega lancio un Thread per gestirne le richieste.
    while (listening) {
      Socket clientSocket = null;
      try {
        clientSocket = serverSocket.accept();
        clientSocket.setSoTimeout(3600000);     //SE IL SOCKET RESTA INATTIVO PER 1 ORA LO CHIUDO
        numconn = Server.incnconn();
        // Stampo sullo schermo del server il numero di connessioni aperte.
        System.out.println("Ho aperto un socket. Connessioni in uso: "+String.valueOf(numconn));
      }
      catch (InterruptedIOException IOe) {
        try {
          clientSocket.close();
          System.err.println("Socket chiuso per timeout  "+IOe.getMessage());
        }
        catch (IOException ex3) {
          System.err.println("Close fallito.  "+ex3.getMessage());
        }
        continue;
      }
      catch (IOException e) {
        System.err.println("Socket non accettato: "+port+", "+e.getMessage());
        continue;
      }
      new ServerThread(clientSocket, database).start();
    }
  }
}
 

// ************************************************************/
// * Definisco la classe  Database  che accede al Database e  */
// * mi esegue le operazioni di accesso, connessione, query e */
// * update                                                   */
// ************************************************************/

class Database {
  Connection dbconn;
  //Il COSTRUTTORE DI CLASSE mi esegue la connessione al database
  public Database(String URL) {
    try {
      Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
    }
    catch (ClassNotFoundException ex2) {
      System.err.println("Fallita connessione al database. Errore 1");
      System.exit(-1);
    }
    catch (Exception ex) {
      System.err.println("Fallita connessione al database. Errore 2");
      ex.printStackTrace();
      System.exit(-1);
    }
    try {
      dbconn = DriverManager.getConnection(URL);
    }
    catch (SQLException e) {
      System.err.println("Fallita connessione al database.. Errore 3");
      System.err.println("La fonte ODBC non esiste.");
      System.exit(-1);
    }
    catch (Exception ex) {
      System.err.println("Fallita connessione al database. Errore 4");
      ex.printStackTrace();
      System.exit(-1);
    }
  }

  //Il metodo ESEGUI_QUERY esegue un comando SQL (select) sul database
  //sottostante e ritorna un Result_Set al chiamante;
  public synchronized ResultSet Esegui_Query(String stringa_SQL) {
    Statement statement;
    ResultSet result_set = null;
    ResultSetMetaData meta_data;
    try {
      statement = dbconn.createStatement();
      result_set = statement.executeQuery(stringa_SQL);
      //statement.close();  //NON USARE    FORSE C'E' UN BUG ??
    }
    catch (SQLException e)  {
      System.err.println(e.getMessage());
      System.err.println(e.getErrorCode());
      System.exit(1);
   }
   return result_set;
 }

  //Il metodo ESEGUI_UPDATE esegue un comando SQL (Update o Delete) sul database
  //sottostante e ritorna il numero di righe modificate o cancellate al chiamante;
  public synchronized int Esegui_Update (String stringa_SQL) {
    Statement statement;
    int NumRighe = 0;
    try {
      statement = dbconn.createStatement();
      NumRighe = statement.executeUpdate(stringa_SQL);
      statement.close();
    }
    catch (SQLException e)  {
      System.err.println(e.getMessage());
      System.err.println(e.getErrorCode());
    }
    return NumRighe;
  }

  //Il metodo DBCCHIUDI esegue la commit e chiude la connessione al Database
  //In questo esempio non viene usato
  public void dbchiudi() {
    try {
      dbconn.commit();
      dbconn.close();
    }
    catch (SQLException e) {
      System.err.println(e.getMessage());
      System.err.println(e.getErrorCode());
    }
  }

}
 

//  *************************************
//  *    CREO LA CLASSE SERVERTHREAD    *
//  *************************************
class ServerThread extends Thread {
  Database database;
  Socket socket;
  int i,numconn;
  // campi del database
  String campo1,campo2,campo3,campo4,campo5,campo6;
  // COSTRUTTORE DI CLASSE
  ServerThread(Socket sock, Database DB) {
    super("ServerThread");
    this.socket = sock;
    this.database = DB;
  }

  public void run() {
    String tmp,inputriga;
    StringTokenizer tokens, token2;
    boolean transacting = true;
    //consultazione
    ResultSet RScons,RScodice;
    String riscons;
    // risultato delle update
    int rigupdate;
    //INIZIO
    try {
      BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      PrintWriter output = new PrintWriter(socket.getOutputStream(),true);
      try {
        output.println("Welcome");
      }
      catch (Exception e) {
        System.err.println ("Welcome Failed");
      }
      // ciclo infinito
      // Ogni volte che riceve una parola chiave ( consulta inserisci ecc.. )
      // il server intraprende l'azione opportuna
      // La comunicazione avviene con i metodi readLine e println
      // Per migliorare le prestazioni si inviano sul socket piu' dati contemporaneamente,
      // separati da un delimitatore.
      // In ricezione i singoli dati vengono ritrovati usando  StringTokenizer
      while (transacting) {
        inputriga = input.readLine();
        tokens = new StringTokenizer(inputriga, "#");
        tmp    = tokens.nextToken();

        // CONSULTAZIONE
        if (tmp.equals("consulta")) {
          RScons=database.Esegui_Query("SELECT * FROM PERSONE");
          riscons="";
          while (RScons.next()) {
            campo1=preptr(RScons.getString(1));
            campo2=preptr(RScons.getString(2));
            campo3=preptr(RScons.getString(3));
            campo4=preptr(RScons.getString(4));
            campo5=preptr(RScons.getString(5));
            campo6=preptr(RScons.getString(6));
            // ciascun campo e' separato da  $
            // ciascun record  e' separato da  #

            if (riscons.equals("")) {
              riscons+=campo1+"§"+campo2+"§"+campo3+"§"+campo4+"§"+campo5+"§"+campo6;
            }
            else {
              riscons+="#"+campo1+"§"+campo2+"§"+campo3+"§"+campo4+"§"+campo5+"§"+campo6;
            }
          }
          // Riscons contiene l'intero Database.
          // Naturalmente questo e' accettabile solo per database "piccoli".
          if (riscons.equals("")) {
            riscons="null";
          }
          output.println(riscons);
        }

        // AGGIORNAMENTO
        if (tmp.equals("memorizza")) {
          campo1 = tokens.nextToken();
          campo2 = tokens.nextToken();
          campo3 = tokens.nextToken();
          campo4 = tokens.nextToken();
          campo5 = tokens.nextToken();
          campo6 = tokens.nextToken();
          // rigupdate e' il numero di righe modificate dalla Update
          rigupdate=database.Esegui_Update("UPDATE PERSONE SET COGNOME = '"+campo2+"', NOME = '"+campo3+"', INDIRIZZO = '"+campo4+"', CITTA = '"+campo5+"', TELEFONO = '"+campo6+"' WHERE ( CODICE = "+campo1+" ) ");
          // Se dico OK al client vuol dire che l'operazione e' andata a buon fine.
          if (rigupdate>0) {
            output.println("OK");
          }
          else {
            output.println("KO");
          }
        }

        // INSERIMENTO
        if (tmp.equals("inserisci")) {
          campo2 = tokens.nextToken();
          campo3 = tokens.nextToken();
          campo4 = tokens.nextToken();
          campo5 = tokens.nextToken();
          campo6 = tokens.nextToken();
          rigupdate=database.Esegui_Update("INSERT INTO PERSONE (COGNOME, NOME, INDIRIZZO, CITTA, TELEFONO ) VALUES ('"+campo2+"', '"+campo3+"', '"+campo4+"', '"+campo5+"', '"+campo6+"')");
          if (rigupdate>0) {
            // Il codice e' scelto dal database (autoinc)
            // Trasmetto al client il codice del nuovo record
            RScodice=database.Esegui_Query("SELECT MAX(CODICE) FROM PERSONE ");
            while (RScodice.next()) {
              campo1 = RScodice.getString(1);
            }
            output.println(campo1);
          }
          else {
            output.println("KO");
          }
        }

        // ELIMINAZIONE RECORD
        if (tmp.equals("cancella")) {
          campo1 = tokens.nextToken();
          rigupdate=database.Esegui_Update("DELETE FROM PERSONE WHERE ( CODICE = "+campo1+" ) ");
          if (rigupdate>0) {
            output.println("OK");
          }
          else {
            output.println("KO");
          }
        }

      } // while (transacting)
    } // try
    catch (Exception e) {
    }
    // la finally viene eseguita quando l'utente chiude il socket
    finally {
      try {
        socket.close();
        numconn=Server.decnconn();
        // Stampo sullo schermo del server il numero di connessioni aperte.
        System.out.println("Ho chiuso un socket. Connessioni in uso: "+String.valueOf(numconn));
      }
      catch (IOException e) {
      System.err.println("Non posso chiudere il socket " + e.getMessage());
      }
    } // finally
  } // run

  // Il metodo preptr prepara ciascun campo per la trasmissione
  // se il campo e' vuoto bisogna metterci almeno un blank
  String preptr(String stxx) {
    String retstr;
    if (stxx.equals("")) {
      retstr=" ";
    }
    else {
      retstr=stxx;
    }
    return retstr;
  }

} // ServerThread

// LA CLASSE FINETHREAD SERVE PER TERMINARE REGOLARMENTE IL PROGRAMMA
class FineThread extends Thread {
  Database database;
  int kkey;
  FineThread(Database DB) {
    super("FineThread");
    this.database=DB;
  }
  public void run() {
    for(;;) {
      try {
        kkey=System.in.read();
        // 70 e 102 sono i codici del tasto  f  maiuscolo e minuscolo
        if((kkey==70)||(kkey==102)) {
          database.dbchiudi();
          System.exit(0);
        }
      }
      catch (IOException e) {
        System.err.println("Errore nella lettura del tasto");
      }
    }
  }
}
 
 
 

// ********************
// *   APPLET CLIENT  *
// ********************
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;

public class Client extends Applet {
  String host;
  AppletContext apcont;
  Mioframe mioframe;
  public void init() {
    super.init();
    apcont = getAppletContext();
    // trova l'indirizzo IP da cui viene scaricato l'applet
    try {
      host = InetAddress.getByName(getDocumentBase().getHost()).getHostAddress();
    }
    catch (java.net.UnknownHostException e) {
      System.err.println("errore InetAddress");
    }
  }
  public synchronized void start() {
    mioframe = new Mioframe("ESEMPIO CLIENT-SERVER PER ACCESSO A DATABASE",host,apcont);
    super.start();
  }
  public synchronized void stop() {
    mioframe.dispose();
    super.stop();
  }
} //  fine della classe Client
 

// ************************
// *   CLASSE FINESTRA    *
// ************************
class Mioframe extends Frame {
  int port=5060;
  int ssock;
  int numrec;
  String host;
  String stfineurl;
  String tmp="";
  AppletContext apcont;
  Socket socket;
  DataInputStream input;
  PrintStream output;
  StringTokenizer tokens,token2;
  URL fineurl;
  //  Font grafiche e colori
  Font ffont10 = new Font("Courier",Font.PLAIN,10);
  Font ffont12 = new Font("Courier",Font.PLAIN,12);
  Font ffont14 = new Font("Courier",Font.PLAIN,14);
  Font ffont16 = new Font("Courier",Font.PLAIN,16);
  Font ffont18 = new Font("Courier",Font.PLAIN,18);
  Color bianco = new Color(16777215);
  Color giallo = new Color(16776960);
  Color azzurro  = new Color(65535);
  Color verde  = new Color(65280);
  Color grigiochiaro = new Color(12632256);
  Color rosso = new Color(16711680);
  Color magenta = new Color(16711935);
  // stringhe contenenti campi del record
  String strecord,stcodice,stcognome,stnome,stindir,stcitt,sttelef;
  // DEFINISCO I COMPONENTI DI CIASCUNA SCHERMATA DELL'APPLET
  // PER VISUALIZZARE UNA SCHERMATA RICHIAMO GLI APPOSITI METODI
  // CHE ESEGUONO LO SHOW E IL RESHAPE
  // pagina 0
  Button btnMenucons,btnMenuins,btnFine;
  Label lbl00;
  // pagina 1 - consulta database
  Label lbl10;
  List lstCons;
  Button btnFinecons;
  // pagina 2 - modifica o elimina record
  Label lblMod0,lblMod1,lblMod2,lblMod3,lblMod4,lblMod5,lblMod6;
  TextField txtMod1,txtMod2,txtMod3,txtMod4,txtMod5,txtMod6;
  Button btnRinumod,btnMod,btnDel,btnConfdel;
  // pagina 3 - inserisci record
  Label lblIns0,lblIns1,lblIns2,lblIns3,lblIns4,lblIns5,lblIns6;
  TextField txtIns1,txtIns2,txtIns3,txtIns4,txtIns5,txtIns6;
  Button btnRinuins,btnResetins,btnIns;

//        *****************************
//        *  COSTRUTTORE DELLA FRAME  *
//        *****************************
  Mioframe(String title, String host, AppletContext apcont) {
  super(title);
    this.host=host;
    this.apcont=apcont;
    setLayout(null);
    addNotify();
    setFont(ffont12);
    setBackground(azzurro);
    // STURL2 e' l'URL cui si arriva a fine programma.  CORRISPONDE ALLA HOME PAGE DEL SERVER.
    stfineurl = "http://"+host;

    // ELEMNTI DELL'INTERFACCIA
    // PAGINA 0  - inizio
    lbl00 = new Label("");
    lbl00.setFont(ffont16);
    add(lbl00);
    btnMenucons = new Button("Consulta Database");
    btnMenucons.setFont(ffont12);
    btnMenucons.disable();
    add(btnMenucons);
    btnMenuins = new Button("Aggiungi Record");
    btnMenuins.setFont(ffont12);
    btnMenuins.disable();
    add(btnMenuins);
    btnFine = new Button("Fine programma");
    btnFine.setFont(ffont12);
    add(btnFine);
    // PAGINA 1  - consulta
    lbl10 = new Label();
    lbl10.setFont(ffont16);
    add(lbl10);
    lstCons = new List(0,false);
    lstCons.setBackground(bianco);
    lstCons.setFont(ffont12);
    add(lstCons);
    btnFinecons = new Button("Fine consultazione");
    btnFinecons.setFont(ffont12);
    add(btnFinecons);
    // PAGINA 2  - modifica
    lblMod0 = new Label();
    lblMod0.setFont(ffont14);
    add(lblMod0);
    lblMod1 = new Label("Codice");
    lblMod1.setFont(ffont14);
    add(lblMod1);
    txtMod1 = new TextField();
    txtMod1.setFont(ffont14);
    txtMod1.setBackground(giallo);
    txtMod1.setEditable(false);
    add(txtMod1);
    lblMod2 = new Label("Cognome");
    lblMod2.setFont(ffont14);
    add(lblMod2);
    txtMod2 = new TextField();
    txtMod2.setFont(ffont14);
    txtMod2.setBackground(bianco);
    add(txtMod2);
    lblMod3 = new Label("Nome");
    lblMod3.setFont(ffont14);
    add(lblMod3);
    txtMod3 = new TextField();
    txtMod3.setFont(ffont14);
    txtMod3.setBackground(bianco);
    add(txtMod3);
    lblMod4 = new Label("Indirizzo");
    lblMod4.setFont(ffont14);
    add(lblMod4);
    txtMod4 = new TextField();
    txtMod4.setFont(ffont14);
    txtMod4.setBackground(bianco);
    add(txtMod4);
    lblMod5 = new Label("Citta'");
    lblMod5.setFont(ffont14);
    add(lblMod5);
    txtMod5 = new TextField();
    txtMod5.setFont(ffont14);
    txtMod5.setBackground(bianco);
    add(txtMod5);
    lblMod6 = new Label("Telefono");
    lblMod6.setFont(ffont14);
    add(lblMod6);
    txtMod6 = new TextField();
    txtMod6.setFont(ffont14);
    txtMod6.setBackground(bianco);
    add(txtMod6);
    btnRinumod = new Button("Fine");
    btnRinumod.setFont(ffont12);
    add(btnRinumod);
    btnMod = new Button("Memorizza");
    btnMod.setFont(ffont12);
    add(btnMod);
    btnDel = new Button("Elimina Record");
    btnDel.setFont(ffont12);
    add(btnDel);
    btnConfdel = new Button("Elimina Record");
    btnConfdel.setFont(ffont12);
    add(btnConfdel);
    // PAGINA 3  - inserisci
    lblIns0 = new Label();
    lblIns0.setFont(ffont14);
    add(lblIns0);
    lblIns1 = new Label("Codice");
    lblIns1.setFont(ffont14);
    add(lblIns1);
    txtIns1 = new TextField();
    txtIns1.setFont(ffont14);
    txtIns1.setBackground(giallo);
    txtIns1.setEditable(false);
    add(txtIns1);
    lblIns2 = new Label("Cognome");
    lblIns2.setFont(ffont14);
    add(lblIns2);
    txtIns2 = new TextField();
    txtIns2.setFont(ffont14);
    txtIns2.setBackground(bianco);
    add(txtIns2);
    lblIns3 = new Label("Nome");
    lblIns3.setFont(ffont14);
    add(lblIns3);
    txtIns3 = new TextField();
    txtIns3.setFont(ffont14);
    txtIns3.setBackground(bianco);
    add(txtIns3);
    lblIns4 = new Label("Indirizzo");
    lblIns4.setFont(ffont14);
    add(lblIns4);
    txtIns4 = new TextField();
    txtIns4.setFont(ffont14);
    txtIns4.setBackground(bianco);
    add(txtIns4);
    lblIns5 = new Label("Citta'");
    lblIns5.setFont(ffont14);
    add(lblIns5);
    txtIns5 = new TextField();
    txtIns5.setFont(ffont14);
    txtIns5.setBackground(bianco);
    add(txtIns5);
    lblIns6 = new Label("Telefono");
    lblIns6.setFont(ffont14);
    add(lblIns6);
    txtIns6 = new TextField();
    txtIns6.setFont(ffont14);
    txtIns6.setBackground(bianco);
    add(txtIns6);
    btnRinuins = new Button("Fine");
    btnRinuins.setFont(ffont12);
    add(btnRinuins);
    btnResetins = new Button("Reset");
    btnResetins.setFont(ffont12);
    add(btnResetins);
    btnIns = new Button("Memorizza");
    btnIns.setFont(ffont12);
    add(btnIns);
 

    // APRO UN SOCKET
    ssock=0;
    aprisocket();

    // INIZIO
    this.reshape(10,20,780,515);
    this.show();
    frameresh0();
    frameshow0();
  }

//  *********************
//  *  GESTIONE EVENTI  *
//  *********************
  public boolean handleEvent(Event event) {
    // EVENTI DELLA PAGINA 0  -  MENU' PRINCIPALE
    // Se premo il BOTTONE di CONSULTA DATABASE
    if ((event.target==btnMenucons)&&(event.id==Event.ACTION_EVENT)) {
      consult();
    }
    // Se premo il BOTTONE di AGGIUNGI RECORD
    if ((event.target==btnMenuins)&&(event.id==Event.ACTION_EVENT)) {
      framehide();
      lblIns0.setText("INTRODUCI IL NUOVO RECORD");
      frameresh3();
      frameshow3();
      txtIns2.requestFocus();
    }
    // Se premo il BOTTONE di FINE PROGRAMMA
    if ((event.target==btnFine)&&(event.id==Event.ACTION_EVENT)) {
      fineprog();
    }

    // EVENTI DELLA PAGINA 1  -  LISTA
    // Se premo il BOTTONE di FINE CONSULTAZIONE
    if ((event.target==btnFinecons)&&(event.id==Event.ACTION_EVENT)) {
      framehide();
      if (lstCons.countItems()>0) {
        lstCons.delItems(0,lstCons.countItems()-1);
      }
      frameresh0();
      frameshow0();
    }
    // Se premo sulla lista per MODIFICARE IL RECORD
    if ((event.target==lstCons)&&(event.id==Event.ACTION_EVENT)) {
      modif();
    }

    // EVENTI DELLA PAGINA 2  -  MODIFICA
    // Se premo IL BOTTONE MEMORIZZA MODIFICA
    if ((event.target==btnMod)&&(event.id==Event.ACTION_EVENT)) {
      btnMod.disable();
      btnDel.disable();
      memomod();
    }
    // Se premo IL BOTTONE  ELIMINA RECORD
    if ((event.target==btnDel)&&(event.id==Event.ACTION_EVENT)) {
      rdelete();
    }
    // Se premo IL BOTTONE  CONFERMA ELIMINAZIONE RECORD
    if ((event.target==btnConfdel)&&(event.id==Event.ACTION_EVENT)) {
      btnConfdel.disable();
      confdel();
    }
    // Se premo il BOTTONE di FINE MODIFICHE
    if ((event.target==btnRinumod)&&(event.id==Event.ACTION_EVENT)) {
      framehide();
      btnMod.enable();
      btnDel.enable();
      btnConfdel.enable();
      frameresh1();
      frameshow1();
    }

    // EVENTI DELLA PAGINA 3 - INSERIMENTO
    // Se premo IL BOTTONE AGGIUNGI RECORD
    if ((event.target==btnIns)&&(event.id==Event.ACTION_EVENT)) {
      btnIns.disable();
      memoins();
    }
    // Se premo il BOTTONE di FINE INSERIMENTI
    if ((event.target==btnRinuins)&&(event.id==Event.ACTION_EVENT)) {
      framehide();
      blanktext();           // mette a blank i campi per l'inserimento
      frameresh0();
      frameshow0();
    }
    // Se premo il BOTTONE di RESET INSERIMENTI
    if ((event.target==btnResetins)&&(event.id==Event.ACTION_EVENT)) {
      lblIns0.setText("INTRODUCI IL NUOVO RECORD");
      blanktext();           // mette a blank i campi per l'inserimento
      btnIns.enable();
    }

  return super.handleEvent(event);
  }

// RESHAPE,SHOW E HIDE DELLE FINESTRE
  // esegue il resape del menu' principale
  void frameresh0() {
    lbl00.reshape(20,35,700,30);
    btnMenucons.reshape(50,450,150,25);
    btnMenuins.reshape(250,450,150,25);
    btnFine.reshape(450,450,150,25);
  }
  // esegue lo show del menu' principale
  void frameshow0() {
    lbl00.show();
    btnMenucons.show();
    btnMenuins.show();
    btnFine.show();
  }
  // esegue il reshape della lista archivio
  void frameresh1() {
    lbl10.reshape(20,30,700,30);
    lstCons.reshape(5,70,770,350);
    btnFinecons.reshape(450,450,150,25);
  }
  // esegue lo show della lista archivio
  void frameshow1() {
    lbl10.show();
    lstCons.show();
    btnFinecons.show();
  }
  // esegue il reshape della maschera di modifica record
  void frameresh2() {
    lblMod0.reshape(30,50,600,30);
    lblMod1.reshape(100,100,150,30);
    txtMod1.reshape(300,100,300,30);
    lblMod2.reshape(100,150,150,30);
    txtMod2.reshape(300,150,300,30);
    lblMod3.reshape(100,200,150,30);
    txtMod3.reshape(300,200,300,30);
    lblMod4.reshape(100,250,150,30);
    txtMod4.reshape(300,250,300,30);
    lblMod5.reshape(100,300,150,30);
    txtMod5.reshape(300,300,300,30);
    lblMod6.reshape(100,350,150,30);
    txtMod6.reshape(300,350,300,30);
    btnMod.reshape(70,450,150,25);
    btnDel.reshape(250,450,150,25);
    btnRinumod.reshape(430,450,150,25);
  }
  // esegue lo show della maschera di modifica record
  void frameshow2() {
    lblMod0.show();
    lblMod1.show();
    txtMod1.show();
    lblMod2.show();
    txtMod2.show();
    lblMod3.show();
    txtMod3.show();
    lblMod4.show();
    txtMod4.show();
    lblMod5.show();
    txtMod5.show();
    lblMod6.show();
    txtMod6.show();
    btnMod.show();
    btnDel.show();
    btnRinumod.show();
  }
  // esegue il reshape della maschera di inserimento record
  void frameresh3() {
    lblIns0.reshape(30,50,400,30);
    lblIns1.reshape(100,100,150,30);
    txtIns1.reshape(300,100,300,30);
    lblIns2.reshape(100,150,150,30);
    txtIns2.reshape(300,150,300,30);
    lblIns3.reshape(100,200,150,30);
    txtIns3.reshape(300,200,300,30);
    lblIns4.reshape(100,250,150,30);
    txtIns4.reshape(300,250,300,30);
    lblIns5.reshape(100,300,150,30);
    txtIns5.reshape(300,300,300,30);
    lblIns6.reshape(100,350,150,30);
    txtIns6.reshape(300,350,300,30);
    btnIns.reshape(70,450,150,25);
    btnRinuins.reshape(250,450,150,25);
    btnResetins.reshape(430,450,150,25);
  }
  // esegue lo show della maschera di inserimento record
  void frameshow3() {
    lblIns0.show();
    lblIns1.show();
    txtIns1.show();
    lblIns2.show();
    txtIns2.show();
    lblIns3.show();
    txtIns3.show();
    lblIns4.show();
    txtIns4.show();
    lblIns5.show();
    txtIns5.show();
    lblIns6.show();
    txtIns6.show();
    btnRinuins.show();
    btnResetins.show();
    btnIns.show();
  }
  // Esegue la cancellazione di tutti i componenti  dello schermo
  // Su programmi molto grandi e' meglio avere diverse routine di hide
  // per ciascuna videata.
  void framehide() {
    lbl00.hide();
    btnMenucons.hide();
    btnMenuins.hide();
    btnFine.hide();
    lbl10.hide();
    lstCons.hide();
    btnFinecons.hide();
    lblMod0.hide();
    lblMod1.hide();
    txtMod1.hide();
    lblMod2.hide();
    txtMod2.hide();
    lblMod3.hide();
    txtMod3.hide();
    lblMod4.hide();
    txtMod4.hide();
    lblMod5.hide();
    txtMod5.hide();
    lblMod6.hide();
    txtMod6.hide();
    btnMod.hide();
    btnDel.hide();
    btnConfdel.hide();
    btnRinumod.hide();
    lblIns0.hide();
    lblIns1.hide();
    txtIns1.hide();
    lblIns2.hide();
    txtIns2.hide();
    lblIns3.hide();
    txtIns3.hide();
    lblIns4.hide();
    txtIns4.hide();
    lblIns5.hide();
    txtIns5.hide();
    lblIns6.hide();
    txtIns6.hide();
    btnIns.hide();
    btnRinuins.hide();
    btnResetins.hide();
  }

  // termina il programma
  public void fineprog(){
    dispose();
    try {
      fineurl = new URL(stfineurl);
      apcont.showDocument(fineurl);
    } catch (IOException ex2) {
      System.err.println("url errata");
    }
  }

  // OVERRIDING DEL METODO DISPOSE - IL SOCKET SI CHIUDE INSIEME ALLA FRAME
  public synchronized void dispose() {
    chiudisocket();
    super.dispose();
  }

  // VISUALIZZA LA LISTA CONTENENTE L'INTERO ARCHIVIO
  void consult() {
    framehide();
    frameresh1();
    frameshow1();
    lbl10.setText("Attendere ... ");
    output.println("consulta");
    try {
      tmp = input.readLine();
      if (tmp.equals("null")) {
        lbl10.setText("L'archivio e' vuoto");
      }
      else {
        tokens = new StringTokenizer(tmp,"#");
        for (;;) {
          try {
            token2 = new StringTokenizer(tokens.nextToken(),"§");
            lstCons.addItem(aggsp1(token2.nextToken(),6)+aggsp1(token2.nextToken(),19)+aggsp1(token2.nextToken(),19)+aggsp1(token2.nextToken(),26)+aggsp1(token2.nextToken(),21)+aggsp1(token2.nextToken(),14));
            lbl10.setText("FAI DOPPIO CLICK SULLA LISTA PER MODIFICARE O ELIMINARE IL RECORD.");
          }
          catch (NoSuchElementException ex) {
            break;
          }
        }
      }
    }
    catch (java.io.IOException e) {
      System.err.println("readLine consult error");
    }
    lstCons.show();
  }

  // MASCHERA PER MODIFICARE IL RECORD
  void modif() {
    framehide();
    lblMod0.setText("INTRODUCI I NUOVI DATI");
    numrec=lstCons.getSelectedIndex();
    strecord=lstCons.getItem(numrec);
    stcodice=strecord.substring(0,6).trim();
    stcognome=strecord.substring(6,24).trim();
    stnome=strecord.substring(25,43).trim().trim();
    stindir=strecord.substring(44,69).trim();
    stcitt=strecord.substring(70,90).trim();
    sttelef=strecord.substring(91,105).trim();
    txtMod1.setText(stcodice);
    txtMod2.setText(stcognome);
    txtMod3.setText(stnome);
    txtMod4.setText(stindir);
    txtMod5.setText(stcitt);
    txtMod6.setText(sttelef);
    frameresh2();
    frameshow2();
  }

  // ESEGUE LA MODIFICA DEL RECORD
  void memomod() {
    stcognome=prepdb(txtMod2.getText().trim(),14);
    stnome=prepdb(txtMod3.getText().trim(),18);
    stindir=prepdb(txtMod4.getText().trim(),25);
    stcitt=prepdb(txtMod5.getText().trim(),20);
    sttelef=prepdb(txtMod6.getText().trim(),14);
    output.println("memorizza#"+stcodice+"#"+stcognome+"#"+stnome+"#"+stindir+"#"+stcitt+"#"+sttelef);
    try {
      tmp = input.readLine();
      if (tmp.equals("OK")) {
        lblMod0.setText("AGGIORNAMENTO ESEGUITO.");
        strecord=aggsp1(stcodice,6)+aggsp1(stcognome,19)+aggsp1(stnome,19)+aggsp1(stindir,26)+aggsp1(stcitt,21)+aggsp1(sttelef,14);
        lstCons.replaceItem(strecord,numrec);
        txtMod2.setText(stcognome);
        txtMod3.setText(stnome);
        txtMod4.setText(stindir);
        txtMod5.setText(stcitt);
        txtMod6.setText(sttelef);
      }
      else {
        lblMod0.setText("ATTENZIONE : AGGIORNAMENTO NON ESEGUITO.");
        stcodice=strecord.substring(0,6).trim();
        stcognome=strecord.substring(6,24).trim();
        stnome=strecord.substring(25,43).trim().trim();
        stindir=strecord.substring(44,69).trim();
        stcitt=strecord.substring(70,90).trim();
        sttelef=strecord.substring(91,105).trim();
        txtMod1.setText(stcodice);
        txtMod2.setText(stcognome);
        txtMod3.setText(stnome);
        txtMod4.setText(stindir);
        txtMod5.setText(stcitt);
        txtMod6.setText(sttelef);
      }
    }
    catch (java.io.IOException e) {
      System.err.println("readLine memorizza error");
      lblMod0.setText("ATTENZIONE : ERRORE NELL'AGGIORNAMENTO.");
    }
  }

  // CHIEDE CONFERMA PRIMA DI ELIMINARE UN RECORD
  void rdelete() {
    stcognome=strecord.substring(6,24).trim();
    stnome=strecord.substring(25,43).trim().trim();
    stindir=strecord.substring(44,69).trim();
    stcitt=strecord.substring(70,90).trim();
    sttelef=strecord.substring(91,105).trim();
    txtMod2.setText(stcognome);
    txtMod3.setText(stnome);
    txtMod4.setText(stindir);
    txtMod5.setText(stcitt);
    txtMod6.setText(sttelef);
    lblMod0.setText("SEI SICURO DI VOLER DEFINITIVAMENTE ELIMINARE QUESTO RECORD ?");
    btnMod.hide();
    btnDel.hide();
    btnConfdel.reshape(160,450,150,25);
    btnConfdel.show();
  }

  // ELIMINA DEFINITIVAMENTE IL RECORD
  void confdel() {
    output.println("cancella#"+stcodice);
    try {
      tmp = input.readLine();
      if (tmp.equals("OK")) {
        lblMod0.setText("ELIMINAZIONE ESEGUITA.");
        stcodice="";
        stcognome="";
        stnome="";
        stindir="";
        stcitt="";
        sttelef="";
        txtMod1.setText("");
        txtMod2.setText("");
        txtMod3.setText("");
        txtMod4.setText("");
        txtMod5.setText("");
        txtMod6.setText("");
        lstCons.delItem(numrec);
      }
      else {
        lblMod0.setText("ATTENZIONE : CANCELLAZIONE NON ESEGUITA.");
      }
    }
    catch (java.io.IOException e) {
      System.err.println("readLine memorizza error");
      lblMod0.setText("ATTENZIONE : ERRORE NELL'AGGIORNAMENTO.");
    }
  }

  // INSERISCE UN NUOVO RECORD
  // ATTENZIONE : IL CODICE E' UN CAMPO AUTOINC PER CUI VIENE GENERATO
  // AUTOMATICAMENTE DAL DATABASE SUL SERVER
  void memoins() {
    stcognome=prepdb(txtIns2.getText().trim(),14);
    stnome=prepdb(txtIns3.getText().trim(),18);
    stindir=prepdb(txtIns4.getText().trim(),25);
    stcitt=prepdb(txtIns5.getText().trim(),20);
    sttelef=prepdb(txtIns6.getText().trim(),14);
    output.println("inserisci#"+stcognome+"#"+stnome+"#"+stindir+"#"+stcitt+"#"+sttelef);
    try {
      tmp = input.readLine();
      if (tmp.equals("KO")) {
        lblIns0.setText("ATTENZIONE : INSERIMENTO NON ESEGUITO.");
      }
      else {
        txtIns1.setText(tmp);
        txtIns2.setText(stcognome);
        txtIns3.setText(stnome);
        txtIns4.setText(stindir);
        txtIns5.setText(stcitt);
        txtIns6.setText(sttelef);
        lblIns0.setText("INSERIMENTO ESEGUITO.");
      }
    }
    catch (java.io.IOException e) {
      System.err.println("readLine memorizza error");
      lblIns0.setText("ATTENZIONE : ERRORE NELL'INSERIMENTO.");
    }
  }

  // APRE UN SOCKET.
  // IL COMPUTER VERSO CUI SI APRE IL SOCKET E' LO STESSO DA CUI
  // E' STATO SCARICATO L'APPLET.
  // VIENE CHIAMATO AUTOMATICAMENTE ALL'INIZIO DEL PROGRAMMA.
  void aprisocket() {
    if (ssock==0) {
      try {
        socket = new Socket(host,port);
        input = new DataInputStream(socket.getInputStream());
        output = new PrintStream(socket.getOutputStream());
        ssock=1;
        try {
          tmp = input.readLine();
          if(tmp.equals("Welcome")) {
            lbl00.setText("Il server e' attivo.");
            btnMenucons.enable();
            btnMenuins.enable();
          }
        }
        catch (java.io.IOException e) {
          System.err.println("readLine error");
        }
      }
      catch (java.io.IOException e) {
        System.err.println ("Connection Failed");
        lbl00.setText("ATTENZIONE: Il server NON e' attivo.");
      }
    }
  }

  // CHIUDE IL SOCKET.
  // VIENE CHIAMATO AUTOMATICAMENTE ALL'USCITA DAL PROGRAMMA.
  void chiudisocket() {
    if (ssock==1) {
      ssock=0;
      try {
        socket.close();
      } catch (IOException ex2) {
        System.err.println("Errore in chiusura socket");
      }
    }
  }

  // mette a blank i textfield per inserimento nuovo record
  void blanktext() {
    txtIns1.setText("");
    txtIns2.setText("");
    txtIns3.setText("");
    txtIns4.setText("");
    txtIns5.setText("");
    txtIns6.setText("");
  }

  // tronca il campo oppure aggiunge dei blank per arrivare alla lunghezza desiderata
  String aggsp1(String stxx, int stlung) {
    int stattu=stxx.length();
    String retstr;
    if (stattu>stlung) {
      retstr=stxx.substring(0,stlung);
    }
    else {
      retstr=stxx+nspazi(stlung-stattu);
    }
    return retstr;
  }

  // genera una stringa di n spazi bianchi
  String nspazi(int spn) {
    StringBuffer retstr= new StringBuffer(0);
    int ii;
    for(ii = 0; ii < spn; ii++) {
      retstr.append(' ');
    }
    return retstr.toString();
  }

  // Prepara il campo per la trasmissione l'inserimento nel database
  // Il campo deve essere troncato alla sua lunghezza massima.
  // Se e' vuoto deve diventare un blank per essere trasmesso.
  String prepdb(String stxx, int stlung) {
    int stattu=stxx.length();
    String retstr;
    if (stxx.equals("")) {
      retstr=" ";
    }
    else {
      if (stattu>stlung) {
        retstr=stxx.substring(0,stlung);
      }
      else {
        retstr=stxx;
      }
    }
    return retstr;
  }

}

 
 

MokaByte Web  1998 - www.mokabyte.it 
MokaByte ricerca nuovi collaboratori. Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it