Home   |   Archivio   |   Chi siamo   |   Contatti
Stefano Rossini & Luca Dozio
J2EE Patterns
Il Pattern Service Locator
di
Stefano Rossini & Luca Dozio
Da completare.

Introduzione

La localizzazione dei servizi e la relativa creazione sono operazioni complesse che possono richiedere accessi a risorse di rete.

A cosa serve

Il pattern Service Locator gestisce le operazioni di localizzazione e creazione di Business Objects occupandosi di :

  • "nascondere" la complessità delle operazioni di ricerca (lookup) dei servizi
  • fornire una modalità uniforme di lookup e creazione dei servizi
  • isolare le eventuali operazioni di lookup "vendor dependent"
  • nascondere eventuali problematiche di networking
  • gestire eventuali necessità di caching

concentrando così la gestione delle problematiche in un singolo punto.

Motivazione

Il pattern garantisce una modalità uniforme e semplificata di localizzazione di risorse.

Spiegazione del funzionamento

La classe ServiceLocator effettua le operazioni che permettono l'inizializzazione del contesto JNDI e la localizzazione dell'oggetto Factory [GOF] d'interesse.

Di seguito si riporta il codice di un client che ricerca un EJB mediante le API JNDI senza utilizzare il pattern Service Locator :

import
javax.naming.*;

import javax.rmi.PortableRemoteObject;

import it.mokabyte.pattern.ejb.entity.AccountHome;

public
NoServiceLocatorTestClient {

    . . .
    public
    void doTest() {

        . . .

        try {

            Context ctx = new InitialContext();

            Object obj = ctx.lookup("MokaAccount");

            AccountHome accountHome =

            (AccountHome)PortableRemoteObject.narrow(obj, AccountHome.class);

        } catch(NamingException ne) {
            . . .
        }

        . . .

    }

    . . .

}

Per confronto si propone lo stesso client che effettua la medesima ricerca mediante il ServiceLocator:

import
it.mokabyte.pattern.delegate.MyServiceLocator;

import it.mokabyte.pattern.exception.ServiceLocationException;

public
ServiceLocatorTestClient {

    . . .
    public
    void doTest() {

        . . .

        try {

            AccountHome home =

            (AccountHome)ServiceLocator.getInstance().

            getHome( << SERVICEID>>);

        } catch(ServiceLocationException sle) {
            . . .
        }

        . . .

    }

    . . .

}

In questo caso l'implementazione del Service Locator è un Singleton [GOF] su cui si invoca un metodo (getHome) specificando come parametro di input (SERVICEID) il servizio da ricercare (algoritmo di tipo "type-checked"). L'implementazione del ServiceLocator proposta, espone anche API in cui è richiesto espressamente il nome del servizio e la classe che si sta ricercando. Un approccio di questo tipo è detto "type-unchecked".

.
. .

try {

    AccountHome home =

            (AccountHome)MyServiceLocator.getInstance().getHome(

                    "MokaAccount", AccountHome.class);

} catch(ServiceLocationException sle) {
    . . .
}

. . .

A parità di funzionalità offerte, il client che utilizza il ServiceLocator non è chiamato ad effettuare le operazioni di lookup e di narrow; conseguentemente non deve importare i package java.rmi e javax.naming.

Struttura

Si riportano i diagrammi UML relativi al pattern.

Class Diagram (ServiceLocator EJBHome)
Class Diagram (ServiceLocator EJBHome)
Class Diagram (ServiceLocator TopicConnectionFactory)
Class Diagram (ServiceLocator TopicConnectionFactory)
Sequence Diagram (EJB Home)
Sequence Diagram (EJB Home)
Sequence Diagram (TopicConnectionFactory) (clicca sull'immagine per ingrandire)
Sequence Diagram (TopicConnectionFactory) (clicca sull'immagine per ingrandire)

Presentazione del codice Java

Viene ora presentato un esempio di implementazione.

Class Diagram dell'esempio proposto (clicca sull'immagine per ingrandire)
Class Diagram dell'esempio proposto (clicca sull'immagine per ingrandire)

Come prima cosa bisogna definire gli ID logici dei servizi che verranno utilizzati dal client per indicare il servizio d'interesse.

public
final static int MOKA_SHOPPER_SERVICE = 0;

public final static int MOKA_ACCOUNT_SERVICE = 1;

. . .

Si deve provvedere a configurare opportunamente ogni servizio specificando la classe Home, la classe ContextFactory, il Provider URL ed il JNDI name. Per fare questo ci si avvale di una classe Helper il cui compito è di contenere i dati di configurazione del servizio mettendo a disposizione i relativi metodi accessor.

class
    ServiceConfig {

    private Class homeClass = null;

    private String jndiName = null;

    private String initialContextFactory = null;

    private String providerUrl = null;

    . . .

    Class getHomeClass() {
        return this.homeClass;
    }

    String getJndiName() {
        return this.jndiName;
    }

    String getInitialContextFactory() {

        return this.initialContextFactory;

    }

    String getProviderUrl() {
        return this.providerUrl;

    }

A questo punto si provvede all'effettiva configurazione dei servizi creando un array di configurazione.

/**
                        Configuration Array */

private static final Object businessServices[] = {

    /* 0 : Shopper */

    new ServiceConfig(

            it.mokabyte.pattern.ejb.session.stateful.ShopperHome.class,

            << JNDI SHOPPER>>,

            "org.jnp.interfaces.NamingContextFactory",

            "jnp://localhost:1099",

            null, null),

    /* 1 : Account */

    new ServiceConfig(

            it.mokabyte.pattern.ejb.entity.AccountHome.class,

            << JNDI ACCOUNT>>,

            "com.sun.jndi.cosnaming.CNCtxFactory",

            "iiop://localhost:1050",

            null, null),

    . . .

}
;

Il parametro service individua l'oggetto ServiceConfig da utilizzare al fine di localizzare il servizio d'interesse.

public
EJBHome getHome(int service) throws ServiceLocationException {

    EJBHome home = null;

    try {

// Look up using the service name from defined constant

        ServiceConfig config =

                (ServiceConfig)MyServiceLocator.businessServices[service];

        Context ctx =

                this.getInitialContext(config.getInitialContextFactory(),

                        config.getProviderUrl());

        Object objref = ctx.lookup(config.getJndiName());

// Narrow using the EJBHome Class from defined constant

        Object obj = PortableRemoteObject.narrow(

                        objref, config.getHomeClass());

        home = (EJBHome)obj;

    }

    catch(Exception ex) {

        ex.printStackTrace();

        throw new ServiceLocationException(ex.getMessage());

    }

    return home;

}

Un caso d'uso

Il caso d'uso proposto prevede un programma client che richiede alla classe ServiceLocator di reperire :

  • l'EJB Account installato sull'Application Server SUN Reference Implementation [DAO] in modalità "type-checked" AccountHome home =(AccountHome)MyServiceLocator.getInstance().getHome( MyServiceLocator.MOKAACCOUNTSERVICE);
  • l'EJB Shopper installato sull'Application Server JBoss[FACADE] in modalità "type- checked" ShopperHome home = (ShopperHome)MyServiceLocator.getInstance().getHome( MyServiceLocator.MOKASHOPPERSERVICE);
  • l'EJB Facade installato sull'Application Server JBoss[FACADE] in modalità "type-unchecked" FacadeHome home = (FacadeHome)MyServiceLocator.getInstance().getHome( JndiNames.FACADE,FacadeHome.class);
  • il Topic Connection Factory [JMS] installato sull'Application Server JBoss in modalità "type-unchecked" TopicConnectionFactory home TopicConnectionFactory) MyServiceLocator.getInstance(). getTopicHome( JndiNames.TOPICCONNECTIONFACTORY);

Allegati

L'esempio è scaricabile qui

Bibliografia e riferimenti

[DAO] S.Rossini, L. Dozio: "J2EE Patterns Dao", Mokabyte N.62 Aprile 2002

[FACADE] S.Rossini, L. Dozio: "J2EE Patterns Facade", Mokabyte N.64 Giugno 2002

[JMS] S.Rossini: "Java Message Service: la pratica", Mokabyte N.61, Marzo 2002

[GOF] Gamma, Helm, Johnson, Vlissides:

Design Patterns - Elements of Reusable Object-Oriented Software

[J2EE] Alur,Crupi,Malks:

Core J2EE Patterns - Best Practices and Design Strategies

[SJP] Sun Java Center J2EE Patterns:

http://developer.java.sun.com/developer/restricted/patterns/J2EEPatternsAtAGlance.html

[BPP] Sun blueprints-Design Patterns Catalog :

http://java.sun.com/blueprints/patterns/j2ee_patterns/catalog.html

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