MokaByte Numero 13 - Novembre 1997
Foto
JavaBeans: le specifiche
Glasgow
I parte
 
di
Daniela
Ruggeri
 

 



Il modello JavaBeans di componente softare non ha fatto in tempo ad affermarsi che ecco che arrivano i primi miglioramenti attraverso quelle che vengono chiamate specifiche Glasgow.
L' ultima versione risale al 22 Settembre.

Introduzione

Le principali novità di Glasgow (www.javasoft.com) si possono riassumere così:

In questo articolo si affronteranno le specifiche dei primi 2 punti.

In particolare :

Specifiche per il modello di composizione di componenti (container e componente).

Con queste nuove specifiche si pongono le basi astratte per un'architettura di un contenitore di componenti mediante il quale è possibile annidare più JavaBeans e fare in modo che questi possano ricevere informazioni sull'ambiente che li circonda, indipendentemente dal fatto che essi si trovino in un Web browser o in un'applicazione host e indipendentemente dal contenitore usato (si pensi ad un contenitore ActiveX che contenga un bean).

 Questo permetterà di:

A tale scopo è stato elaborato il concetto di BeanContext che ha qui il significato di "Container" e permette di :

  1. Fornire una gerarchia o struttura logica per JavaBeans e BeanContexts annidati.
  2. Fornire un meccanismo di connessione tra un JavaBean, e una varietà di servizi e informazioni accessibili dall'ambiente di esecuzione.

In figura 2. è sintetizzata l'architettura.


Figura 2

 

Come si può vedere dalla figura è possibile:

  1. La comunicazione tra JavaBeans di uno stesso BeanContext.
  2. La comunicazione tra BeanContexts.
  3. La comunicazione tra un JavaBean ed un servizio esterno od interno al BeanContext in cui è contenuto.
Analogamente è stato elaborato il concetto di BeanContextChild (forse questi termini verranno cambiati, dal momento che non piacciono neanche a chi ha scritto le specifiche) che ha il significato di "Component", nel senso che un BeanContextChild può essere sia un JavaBean che un BeanContext, esattamente come un Component può essere sia un Button che un Container (es. Panel).

Analogamente come un Container è estensione di un Component così un BeanContext è estensione di un BeanContextChild:
 
 

public interface java.beans.BeanContext extends java.beans.BeanContextChild {

    public static String ADDED;

    public static String REMOVED;

    Object instantiateChild(String beanName) throws IOException, ClassNotFoundException;

    void addChildren (Object[] targetChildren) throws ChildVetoException;

    void removeChildren(Object[] targetChildren) throws ChildVetoException;

    Object[] getChildren();

    boolean isChild(Object c);

    void addNestedStateListener(NestedStateListener l);

    void removeNestedStateListener(NestedStateListener l);

    void addBeanContextListener(BeanContextListener l);

    void removeBeanContextListener(BeanContextListener l);

    Aggregate getContextServices();

}
La cosa che notiamo sono le nuove liste ascoltatrici di nuovi eventi:
  1. java.beans.BeanContextListener.

  2.  publicinterface BeanContextListener extends java.util.EventListener {
        void beanContextChanged(PropertyChangeEvent pce);
    }
    L'interfaccia java.beans.BeanContextListener gestisce gli eventi java.beans.PropertyChangeEvent che riguardano esclusivamente i cambiamenti che avvengono all'interno del BeanContext e possono essere spediti ad altri figli che implementano l'interfaccia java.beans.PropertyChangeListener. I metodi per registrarsi come ascoltatori e rimuovere la registrazione sono addBeanContextListener() e removeBeanContextListener() .
  3. java.beans.ChildStateListener.
  4. publicinterface ChildStateListener extends java.util.EventListener {

  5.     void childStateChanged(ChildStateEvent cse) throws ChildVetoException;
    }
  6. public class ChildStateEvent extends java.util.EventObject {

  7.     publicstatic ChildStateEvent childAdded(Object s, BeanContext bc);
        publicstatic ChildStateEvent childDeleted(Object s, BeanContext bc);
        public BeanContext getBeanContext();
        String getTypeName();
    }
  8. public class ChildVetoException extends Exception {

  9.     public ChildVetoException(String reason);
    }
     
     
  10. Quando un oggetto viene aggiunto a o rimosso da un insieme di altri oggetti, assume uno stato con valore ADDED o REMOVED. Questa lista serve ad intercettare questo stato che costituisce il nuovo evento ChildStateEvent. Quindi se l'oggetto implementa l'interfaccia java.beans.beancontext.ChildStateListener, il BeanContext riceverà l'evento java.beans.beancontext.ChildStateEvent con la notifica di ADDED o REMOVED e un riferimento all'oggetto. Inoltre se un oggetto non è abilitato o impreparato per qualche ragione a far parte o a essere rimosso da quel particolare BeanContext, esso può attraverso la generazione dell'eccezione ChildVetoException notificare il fatto al BeanContext, il quale può revocare l'aggiunta o la rimozione. Se qualche lettore ha familiarità con i JavaBeans avrà notato come questo concetto sia molto simile a quello delle proprietà bound condizionate il cui cambiamento gestito dalla lista java.beans.VetoableChangeListener poteva essere impedito generando l'eccezione PropertyVetoException().
  11. java.beans.NestedStateListener.

  12.  publicinterface NestedStateListener {
           void nestedStateChanged(NestedStateEvent nse);
    }

    public class NestedStateEvent extends ChildStateEvent {
        publicstatic NestedStateEvent childrenAdded(BeanContext bc, Object[] children);
        publicstatic NestedStateEvent childrenRemoved(BeanContext bc, Object[] children);
        public Object[] getChildren();
        publicboolean isChild(Object child);
        publicvoid setPropagatedFrom(BeanContext id);
        public BeanContext getPropagatedFrom();
        publicboolean isPropagated();
    }

    Una volta che tutti i targetChildren (oggetti aggiunti o rimossi) sono stati trattati, il BeanContext riceverà la notifica dell'evento java.beans.beancontext.NestedStateEvent con lo stato di .ADDED (o REMOVED), e un array di riferimenti dei nuovi oggetti aggiunti (o vecchi oggetti rimossi) to the newly added targetChildren, e la propagherà a tutti gli oggetti registrati alla lista NestedStateListener.
     Gli oggetti che desiderano mantenere una traccia dei cambiamenti degli stati annidati di un BeanContext, dovranno implementare l'interfaccia java.beans.beancontext.NestedStateListener. I metodi per registrarsi come ascoltatori e rimuovere la registrazione sono addNestedStateListener() e removeNestedStateListener().
     Nel caso di BeanContexts annidati, tali eventi possono propagarsi dalla foglia alla radice della gerarchia. In questo caso un BeanContext della catena propagherà l'evento al prossimo BeanContext con un riferimento a se stesso, cosa che è possibile richiamando il metodo setPropagatedFrom(). Usando questa informazione (ricevuta tramite il metodo getPropagatedFrom()), ogni BeanContext sarà in grado di conoscere il precedente BeanContext propagatore oltre che la sorgente dell'evento.
     

Passiamo ora a considerare i metodi necessari alla costituzione di una gerarchia di JavaBeans:
  1. addChildren() per aggiungere oggetti nella struttura.
  2. removeChildren() per rimuovere oggetti dalla struttura.
  3. getChildren() metodo che restituisce una matrice di oggetti costituenti il BeanContext
  4. isChild() metodo per sapere se un determinato oggetto appartiene ad un determinato BeanContext.
Come detto precedentemente si può impedire l'aggiunta o la rimozione di figli sollevando l'eccezione ChildVetoException().

 Per finire usando i metodi isInstaceOf() e getInstanceOf() definiti dall'interfaccia java.util.Aggregate (vedere capitolo successivo sul modello di Aggregazione/Delega) restituita dal metodo restituiti getContextServices() del BeanContext, i JavaBeans possono interrogare circa l'esistenza di, e successivamente ottenere i riferimenti a; una varietà di servizi dinamici forniti dall'ambiente in cui esterno al BeanContext.

A questo punto affinché il nostro modello JavaBean assuma una struttura gerarchica per poter comunicare con l'ambiente esterno, basterà semplicemente che implementi l'interfaccia BeanContextChild definita di seguito:

public interface java.beans.BeanContextChild extends ChildStateListener {

    BeanContext getBeanContext();

}
 

 

Specifiche di supporto per i JavaBeans consistenti in Applet.

Una prima proposta riguarda l'overloading del metodo java.beans.Beans.instantiate() che oltre ad avere il compito di creare l'istanza del JavaBean, deve anche definire il suo contesto contenitore.

Il metodo proposto diviene quindi:

public static Object instantiate(ClassLoader cl, String beanName, BeanContext beanContext);
 

 

Questo metodo dovrebbe essere utilizzato da tutti i JavaBeans che non conoscono il loro BeanContext. E' chiaro quindi che per quelli che implementeranno la nuova interfaccia BeanContextChild che fornisce già questo tipo di informazione non sarà necessario l'utilizzo di questo metodo. Semplicemente basterà utilizzare il metodo addChildren() per trasmettere l'informazione al JavaBeans.

Per quanto riguarda i JavaBeans che in particolare sono Applet, ci sono delle proposte sul miglioramento della propagazione delle informazioni riguardanti le interfacce AppletContext e AppletStub.

Poiché il metodo instantiate() non fornisce abbastanza informazioni al fine di costruire un AppletContext e AppletStub dove far girare in maniera funzionale l'applet, per risolvere il problema è stato proposto un nuovo metodo instantiate():

public static Object instantiate(ClassLoader cl, String beanName, BeanContext bCtxt,
             AppletInitializer ai);
dove AppletInitializer è la nuova interfaccia proposta per l'inizializzazione dell'Applet:
public interface AppletInitializer {

    void initialize(Applet newApplet, BeanContext bCtxt);

    void activate(Applet newApplet);

}
Usando il metodo initialize() il bean che è un'Applet verrà passato all'interfaccia AppletInitializer che a questo punto dovrebbe incaricarsi di:
  1. Associare la nuova istanza dell'Applet all'appropriato AppletContext.
  2. Istanziare un AppletStub e associarlo all'Applet attraverso l'invocazione del metodo java.applet.Applet.setStub().
  3. Se il BeanContext è nullo allora l'AppletInitializer dovrebbe incaricarsi di associare l'Applet all'appropriato contenitore attraverso l'invocazione del metodo add(). Se invece il parametro BeanContext non è nullo allora la responsabilità di associare l'applet al suo contenitore è del BeanContext stesso attraverso le successive invocazioni dei suoi metodi addChildren().
 Esiste anche il metoto AppletInitializer.activate() che marchiano come attiva l'applet.

Se invece il JavaBeans non è un'Applet, allora l'interfaccia AppletInitializer sarà ignorata.

 

Specifiche per ulteriori interfacce di supporto.

 Sono state fornite inoltre delle ulteriori interfacce di supporto riguardanti stati che possono essere propagati attraverso la lista java.beans.propertyChangeEvent con valori di propertyName opportuni e appropriati valori per oldValue e newValue, nel caso di cambiamenti della proprietà:

  1.  Supporto per la modalità Design.
  1.  Finora sono state fornite le specifiche riguardanti i JavaBeans che prevedevano una modalità di Design o di run-time come attributo di JVM. Ma ci sono altri tipi di ambienti in cui possono girare i javabeans; uno di questi sono i generatori di applicazioni che possono riservare una parte del loro ambiente nel quale far girare i JavaBeans.

  2. A tale scopo viene fornita un'apposita interfaccia mediante la quale il BeanContext possa gestire lo stato della modalità del JavaBean:
     publicinterface java.beans.DesignMode {
          void setDesignTime(boolean isDesignTime);
          boolean isDesignTime();
    }
    Il valore di propertyName da propagare è "designTime".
  3. Supporto per la Visibilità.
Nelle specifiche attuali esiste l'interfaccia java.beans.Visibility che gestisce completamente questo tipo di condizione.

In una logica di BeanContext dovendo però gestire la propagazione di questo stato, è necessaria l'introduzione di una nuova interfaccia:
 publicinterface java.beans.VisibilityState {
       boolean isOkToUseGui();
 }
 Attraverso questa interfaccia il BeanContext può controllare la possibilità che i suoi figli hanno di utilizzare un'interfaccia GUI.
Il valore di propertyName da propagare è "okToUseGui".
Diamo anche un accenno all'interfaccia java.beans.beancontext.BeanContextSupport che è una classe che fornisce una sorta di help, per la gestione di tale complesso protocollo. Questa classe è stata disegnata per essere sottoclassata o delegata da un altro oggetto e fornisce una facilitazione nel reperire informazioni circa i protocolli da utilizzare.
 

Specifiche per il modello di Aggregazione/Delega

Quando un componente è contenuto in un altro e di conseguenza quando un Bean è composto da più componenti Bean si parla di aggregazione.

Il modello Glasgow fornisce degli stardard di comunicazione tra il Bean esterno e quelli interni sia come aggregazione (in questa fase dall'esterno avviene un'individuazione di un unico oggetto che eredita da tutti i componenti) sia come delega (cioè all'esterno si riesce a conoscere gli oggetti separati costituenti l'aggregazione)

Un'interfaccia di aggregazione definisce il meccanismo attraverso il quale un oggetto ottiene il riferimento ad un oggetto Delegato per un particolare tipo di interfaccia o classe da un Delegante:

L'interfaccia è la seguente:

public interface AppletInitializer {
    void initialize(Applet newApplet, BeanContext bCtxt);
    void activate(Applet newApplet);
}

appartenente al package java.util.
 


 Figura 1.

 

Il modello ruota attorno alle seguenti definizioni:
 
 

  1. Aggregato. Una classe astratta, o un'istanza di una classe Aggregato, che esibisce un'apparente comportamento dovuto alla sintesi dei singoli comportamenti di altre classi componenti.
  2. Delegante. E' la classe entro una classe Aggregato che implementa l'interfaccia Aggregate che è responsabile dei comportamenti delegati all'interno dell'aggregato.
  3. Delegato. Una classe, o istanza, componente di un Aggregato che implementa uno o più apparenti comportamenti sintetizzati dell'Aggregato.
  4. Aggregazioni di Delegati Semplici. Sono Aggregati in cui le classi delegate non sono coscienti della loro appartenenza all'aggregazione, e piu' generalmente di qualsiasi relazione Aggregato/Delegato.
  5. Aggregazioni di Delegati Coscienti. Sono Aggregati in cui le classi Delegate sono disegnate per partecipare coscientemente in un'aggregazione, in particolare questo implica che le istanze del Delegato incapsulano puntatori oggetti all'Aggregato, di cui fanno parte e al Delegante.
  6. Aggregati Statici. Per definizione è un'aggregazione il cui insieme di tipi di Delegati e/o istanze è costante/invariante per tutto il ciclo di vita della particolare istanza della classe di aggregazione.
  7. Aggregati Dinamici. Per definizione è un'aggregazione in cui di classi Delegate e/o istanze possono variare entro il ciclo di vita di una particolare classe di aggregazione.
  8. Aggregati Nidificati o Ricorsivi. E' un'aggregazione in cui anche l'oggetto Aggregato stesso è un'istanza di una classe Delegata Cosciente, e quindi incapsula un riferimento ad un Aggregato che è parte di esso.
 In figura 1. possiamo vedere come una classe Aggregato a possa contenere i riferimenti a 3 classi, una Delegante A la quale contiene i riferimenti alle classi Delegate B e C. Le classi Delegate a loro volta possono conoscere i riferimenti alla classe Delegante a secondo se siano Coscienti o meno. Dall'esterno è possibile conoscere i riferimenti alle classi Delegate utilizzando il metodo getInstanceOf(B) e getInstanceOf(C).

Per quanto riguarda la persistenza dell'aggregazione abbiamo due casi:


 
 

Conclusione.

La trattazione termina qui. Nel prossimo articolo affronteremo le specifiche che permettono di utilizzare servizi stardard al fine di rappresentare i dati nel formato richiesto. Per esempio se un browser ha ricevuto uno stream di tipo MPEG, queste specifiche dovrebbero abilitare il browser ad identificare giustamente il tipo di stream, e il browser potrebbe localizzare e istanziare l'oggetto che possa manipolare o vedere quello stream.   
 
 
 
 

 

MokaByte rivista web su Java

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