SeamFramework.orgCommunity Documentation

Capitolo 30. Configurare Seam ed impacchettare le applicazioni Seam

30.1. Configurazione base di Seam
30.1.1. Integrazione di Seam con JSF ed il servlet container
30.1.2. Usare Facelets
30.1.3. Resource Servlet di Seam
30.1.4. Filtri servlet di Seam
30.1.5. Integrazione di Seam con l'EJB container
30.1.6. Non dimenticare!
30.2. Uso di provider JPA alternativi
30.3. Configurazione di Seam in java EE 5
30.3.1. Packaging
30.4. Configurare Seam in J2EE
30.4.1. Boostrapping di Hibernate in Seam
30.4.2. Boostrapping di JPA in Seam
30.4.3. Packaging
30.5. Configurazione di Seam in java EE 5 senza JBoss Embedded
30.6. Configurazione di Seam in java EE 5 con JBoss Embedded
30.6.1. Installare JBoss Embedded
30.6.2. Packaging
30.7. Configurazione jBPM in Seam
30.7.1. Packaging
30.8. Configurazione di SFSB e dei timeout di sessione in JBoss AS
30.9. Esecuzione di Seam in un Portlet
30.10. Deploy di risorse personalizzate

La configurazione è un argomento molto noioso ed un passatempo estremamente tedioso. Sfortunatamente sono richieste parecchie linee di XML per integrare Seam con l'implementazione JSF ed il servlet container. Non c'è bisogno di soffermarsi sulle seguenti sezioni; non si dovrà mai scrivere queste cose a mano, poiché basta usare seam-gen per creare ed avviare l'applicazione oppure basta copiare ed incollare il codice dagli esempi di applicazione!

In primo luogo si cominci col guardare alla configurazione base che serve ogni volta che si usa Seam con JSF.

Certamente occorre un servlet faces!


<servlet>
    <servlet-name
>Faces Servlet</servlet-name>
    <servlet-class
>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup
>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name
>Faces Servlet</servlet-name>
    <url-pattern
>*.seam</url-pattern>
</servlet-mapping
>

(Si può sistemare il pattern dell'URL a proprio piacimento.)

In aggiunta, Seam richiede la seguente voce nel file web.xml:


<listener>
    <listener-class
>org.jboss.seam.servlet.SeamListener</listener-class>
</listener
>

Questo listener è responsabile dell'avvio di Seam e della distruzione dei contesti di sessione e di applicazione.

Alcune implementazioni JSF hanno un'implementazione erronea della conservazione dello stato lato server, che interferisce con la propagazione della conversazione di Seam. Se si hanno problemi con la propagazione della conversazione durante l'invio di form, si provi a cambiare impostanto la conservazione lato client. Occorre impostare questo in web.xml:


<context-param>
    <param-name
>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value
>client</param-value>
</context-param
>

C'è una piccola parte grigia nella specifica JSF riguardante la mutabilità dei valore dello stato della vista. Poiché Seam usa lo stato della vista JSF per tornare allo scope PAGE, questo in alcuni casi può diventare un problema. Se si usa la conservazione dello stato lato server con JSF-RI e si vuole che il bean con scope PAGE mantenga l'esatto valore per una data vista di pagina, occorre specificare il seguente parametro di contesto. Altrimenti se un utente usa il pulsante "indietro", un componente con scope PAGE avrà l'ultimo valore se questo non è cambiato nella pagina "indietro". (si veda Spec Issue ). Quest'impostazione non è abilitata di default a causa della performance nella serializzazione della vista JSF ad ogni richiesta.


<context-param>
    <param-name
>com.sun.faces.serializeServerState</param-name>
    <param-value
>true</param-value>
</context-param
>

Seam non ha bisogno di filtri servlet per le operazioni base. Comunque ci sono parecchie caratteristiche che dipendono dall'uso dei filtri. Per facilitare le cose, Seam lascia aggiungere e configurare i filtri servlet così come si configurano gli altri componenti predefiniti di Seam. Per sfruttare questa caratteristica occorre installa un filtro master in web.xml:


<filter>
    <filter-name
>Seam Filter</filter-name>
    <filter-class
>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name
>Seam Filter</filter-name>
    <url-pattern
>/*</url-pattern>
</filter-mapping
>

Il filtro master di Seam deve essere il primo filtro specificato in web.xml. Questo assicura che venga eseguito per primo.

I filtri Seam condividono un numero di attributi comuni, si possono impostare questi in components.xml in aggiunto ai parametri discussi sotto:

Si noti che i pattern corrispondono al percorso URI della richiesta (si veda HttpServletRequest.getURIPath()) e che il nome del contesto servlet viene rimosso prima del matching.

L'aggiunta del filtro master abilita i seguenti filtri predefiniti.

Nelle applicazioni Seam i componenti EJB hanno una certa dualità, poiché sono gestiti da entrambi: il container EJB e Seam. In verità Seam risolve i riferimenti ai componenti EJB, gestisce il ciclo di vita dei componenti bean con sessione stateful, e partecipa anche ad ogni chiamata di metodo via interceptor. Iniziamo con la configurazione della catena interceptor di Seam.

Occorre applicare SeamInterceptor ai componenti EJB di Seam. Quest'interceptor delega ad un set di interceptor predefiniti lato server che gestiscono i concern quali la bijection, la demarcazione delle conversazioni ed i segnali del processo di business. Il modo più semplice per fare questo in tutta l'applicazione è aggiungere la seguente configurazione per l'interceptor in ejb-jar.xml:


<interceptors>
    <interceptor>
        <interceptor-class
>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
    </interceptor>
</interceptors>
   
<assembly-descriptor>
    <interceptor-binding>
        <ejb-name
>*</ejb-name>
        <interceptor-class
>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
    </interceptor-binding>
</assembly-descriptor>

Seam necessita di sapere dove trovare i session bean in JNDI. Un modo per farlo è specificare l'annotazione @JndiName su ogni componente session bean. Comunque questa modalità è abbastanza noiosa. Un approccio migliore è specificare un pattern che Seam usa per calcolare il nome JNDI dal nome EJB. Sfortunatamente nella specifica EJB3 non è definita una mappatura standard al JNDI globale, quindi questa mappatura è specificata dal venditore (e può dipendere anche dalle proprie convenzioni di nome). Solitamente si specifica quest'opzione in components.xml.

Per JBoss AS ilseguente pattern è corretto:


<core:init jndi-name="earName/#{ejbName}/local" />

In questo caso earName è il nome dell'EAR in cui viene deployato il bean, Seam sostituisce #{ejbName} con il nome dell'EJB ed il segmento finale rappresenta il tipo di interfaccia (locale o remota).

Fuori dal contesto di un EAR (quando si usa il container JBoss Embeddable EJB3) il primo segmento viene ignorato poiché non c'è alcun EAR, rimanendo quindi con il seguente pattern:


<core:init jndi-name="#{ejbName}/local" />

Come questi nomi JNDI vengono risolti e come localizzare un componente EJB potrebbe apparire a questo punto un pò una questione di magia, quindi indaghiamo meglio i dettagli. Innanzitutto vediamo come i componenti EJB entrano in JNDI.

Le persone di JBoss non si preoccupano molto di XML. Quindi quando hanno progettato JBoss AS, hanno deciso che i componenti EJB avrebbero visto assegnarsi automaticamente un nome JNDI globale, usando il pattern appena descritto (cioè nome EAR/nome EJB/tipo interfaccia). Il nome EJB è il primo valore non vuoto della seguente lista:

Guardiamo un esempio. Si assuma di avere definiti il seguente bean EJB ed un'interfaccia.

package com.example.myapp;


import javax.ejb.Local;
@Local
public class Authenticator
{
    boolean authenticate();
}
package com.example.myapp;
import javax.ejb.Stateless;
@Stateless
@Name("authenticator")
public class AuthenticatorBean implements Authenticator
{ 
    public boolean authenticate() { ... }
}

Assumendo che la classe del bean EJB sia deployata in un'applicazione EAR chiamata myapp, il nome JNDI globale myapp/AuthenticatorBean/local verrà assegnato a lei in JBoss AS. Come visto, si può fare riferimento a questo componente EJB come componente Seam con il nome authenticator e Seam si preoccuperà di trovarlo in JNDI secondo il pattern JNDI (o l'annotazione @JndiName).

Ma cosa dire rispetto ai restanti application server? In accordo alla specifica Java EE, alla quale la maggior parte dei venditori cerca di aderire in modo religioso, si deve dichiarare un riferimento EJB per il proprio EJB affinché gli venga assegnato un nome JNDI. Questo richiede un pò di XML. Significa che sta a voi stabilire una convenzione di nomi JNDI per poter sfruttare il pattern JNDI di Seam. Si potrebbe ritenere buona e usare la convenzione JBoss.

Ci sono due posti dove poter definire il riferimento EJB usando Seam su application server non-JBoss. Se si cercheranno i componenti EJB di Seam attraverso JSF (in una vista JSF o in un action listener JSF) od un componente JavaBean di Seam, allora occorre dichiarare il riferimento EJB in web.xml. Ecco qua il riferimento EJB per il componente d'esempio appena mostrato:


<ejb-local-ref>
    <ejb-ref-name
>myapp/AuthenticatorBean/local</ejb-ref-name>
    <ejb-ref-type
>Session</ejb-ref-type>
    <local
>org.example.vehicles.action.Authenticator</local>
</ejb-local-ref>

Questo riferimento coprirà la maggior parte degli usi dei componenti in un'applicazione Seam. Comunque se si vuole essere in grado di iniettare un componente EJB di Seam in un altro componente usando @In, occorre definire questo riferimento EJB in un'altra posizione. Questa volta deve essere definito in ejb-jar.xml, ed è un pò più complicato.

Dentro il contesto di una chiamata di metodo EJB, occorre avere a che fare con un contesto JNDI protetto. Quando Seam tenta di trovare un altro componente EJB Seam per soddisfare un punto d'iniezione definito con @In, il fatto che Seam lo trovi oppure no dipende dal fatto che esista un riferimento EJB in JNDI. In senso letterale non si può semplicemente risolvere i nomi JNDI a proprio piacimento. Occorre definire esplicitamente i riferimenti. Fortunatamente JBoss ha capito come questo sarebbe aggravante per lo sviluppatore e quindi tutte le versioni di JBoss registrano automaticamente gli EJB cosicché siano sempre disponibili in JNDI, sia nel web container sia nell'EJB container. In definitiva se si usa JBoss, si possono saltare i prossimi paragrafi. Comunque, se si usa GlassFish, si presti molta attenzione.

Per gli application server che aderiscono testardamente alla specifica EJB, i riferimenti EJB devono sempre essere definititi esplicitamente. Ma diversamente dal contesto web, dove un singolo riferimento di una risorsa copre tutti gli usi di EJB, non si possono dichiarare i riferimenti EJB in modo globale nel container EJB. Invece si devono specificare le risorse JNDI per un dato componente EJB una per una.

Si assuma di avere un EJB chiamato RegisterAction (nome che viene risolto usando i tre passi menzionati prima). Questo EJB ha la seguente injection Seam:

@In(create = true)

Authenticator authenticator;

Per fare funzionare quest'injection, il link deve essere messo nel file ejb-jar.xml come mostrato:


<ejb-jar>
    <enterprise-beans>
        <session>
            <ejb-name
>RegisterAction</ejb-name>
            <ejb-local-ref>
                <ejb-ref-name
>myapp/AuthenticatorAction/local</ejb-ref-name>
                <ejb-ref-type
>Session</ejb-ref-type>
                <local
>com.example.myapp.Authenticator</local>
            </ejb-local-ref>
        </session>
    </enterprise-beans>

    ...
    
</ejb-jar>

Si noti che i contenuti di <ejb-local-ref> sono identici a ciò che viene definito in web.xml. Ciò che viene fatto è portare il riferimento nel contesto EJB dove può essere usato dal bean RegisterAction. Occorre aggiungere uno di questi riferimenti per qualsiasi injection di componente EJB Seam in un altro componente EJB Seam con @In. (Vedere l'esempio di setup di jee5/booking).

E riguardo @EJB? E' vero che si può iniettare un EJB in un altro usando @EJB. Comunque, facendo così, si sta iniettando il riferimento EJB piuttosto che l'istanza del componente EJB Seam. In questo caso, alcune funzionalità di Seam funzioneranno, mentre altre no. Questo perchè l'interceptor di Seam viene invocato ad ogni chiamata di metodo in un componente EJB. Ma questo invoca solo la catena dell'interceptor Seam lato server. Ciò che viene persa è la gestione dello stato di Seam e la catena dell'interceptor lato client. Gli interceptor lato client gestiscono i concern quali sicurezza e concorrenza. Inoltre, quando si inietta un SFSB, non c'è garanzia che il SFSB venga associato alla conversazione o sessione attiva, qualunque sia il caso. Quindi si inietterà il componente EJB Seam usando @In.

Vediamo ora come vengono definiti ed usati i nomi JNDI. La lezione riguarda alcuni application server, come GlassFish, con cui occorre specificare i nomi JNDI esplicitamente per tutti i componenti EJB, ed alcune volte in modo doppio! Ed anche se si segue la stessa convenzione di nomi di JBoss AS, il pattern JNDI in Seam deve essere alterato. Per esempio in GlasshFish ai nomi JNDI viene automaticamente aggiunto il prefisso java:comp/env, e quindi occorre definire il pattern JNDI come segue:


<core:init jndi-name="java:comp/env/earName/#{ejbName}/local" />

Infine parliamo di transazioni. In un ambiente EJB3 si raccomanda l'uso di un componente speciale predefinito per la gestione delle transazioni, che sia pienamente consapevole delle transazioni del container e possa correttamente processare gli eventi di successo legati alle transazioni registrato con il componente Events. Se non viene aggiunta questa linea al file components.xml, Seam non saprà quando finiscono le transazioni gestite dal container:


<transaction:ejb-transaction/>

Seam viene assemblato e configurato con Hibernate in qualità di provider JPA. Se si vuole usare un diverso provider JPA occorre dirlo a seam.

Comunicare a Seam di usare un altro provider JPA può essere realizzato in uno dei due modi:

Si aggiorni il components.xml della propria applicazione affinché PersistenceProvider abbia la precedenza sulla versione Hibernate. Semplicemente si aggiunga al file:


<component name="org.jboss.seam.persistence.persistenceProvider" 
           class="org.jboss.seam.persistence.PersistenceProvider"
           scope="stateless">
</component
>

Se si vogliono sfruttare le caratteristiche nonstandard del proprio provider JPA occorre scrivere la propria implementazione di PersistenceProvider. Si usa HibernatePersistenceProvider come punto di partenza (si ricordi di dare qualcosa alla comunità :). Quindi occorrerà dire a seam di usarlo come prima.


<component name="org.jboss.seam.persistence.persistenceProvider" 
           class="org.your.package.YourPersistenceProvider">
</component
>

Ciò che rimane da fare è aggiornare il file persistence.xml come la giusta classe del provider e quelle proprietà che il provider richiede. Non dimenticare di impacchettare nell'applicazione i file jar del provider se richiesti.

Se si esegue il software in ambiente Java EE 5, questa è tutta la configurazione richiesta per usare Seam!

Una volta impacchettato assieme tutte queste cose in un EAR, la struttura dell'archivio apparirà così:

my-application.ear/
    jboss-seam.jar
    lib/
        jboss-el.jar
    META-INF/
        MANIFEST.MF
        application.xml
    my-application.war/
        META-INF/
            MANIFEST.MF
        WEB-INF/
            web.xml
            components.xml
            faces-config.xml
            lib/
                jsf-facelets.jar
                jboss-seam-ui.jar
        login.jsp
        register.jsp
        ...
    my-application.jar/
        META-INF/
            MANIFEST.MF
            persistence.xml
        seam.properties
        org/
            jboss/
                myapplication/
                    User.class
                    Login.class
                    LoginBean.class
                    Register.class
                    RegisterBean.class
                    ...

Si dovrebbe dichiarare jboss-seam.jar come modulo ejb in META-INF/application.xml; jboss-el.jar dovrebbe essere collocato nella directory lib dell'EAR (mettendolo nel classpath dell'EAR).

Se si vuole usare jBPM o Drools, occorre includere i jar necessari nella directory lib di EAR.

Se si vuole usare facelets (consigliato), occorre includere jsf-facelets.jar nella directory WEB-INF/lib del WAR.

Se si vuole usare la libreria dei tag di Seam (come per la maggior parte delle applicazioni), occorre includere jboss-seam-ui.jar nella directory WEB-INF/lib del WAR. Se si vuole usare la libreria PDF o quella email, occorre mettere jboss-seam-pdf.jar o jboss-seam-mail.jar in WEB-INF/lib.

Se si vuole usare la pagina di debug di Seam (funziona solo per applicazioni con facelets), occorre includere jboss-seam-debug.jar nella directory WEB-INF/lib del WAR.

Seam porta con sé parecchi esempi di applicazioni che sono deployate in un container Java EE che supporta EJB 3.0.

Ci piacerebbe aver terminato l'argomento configurazione, ma sfortunatamente siamo solo ad un terzo. Se si è troppo sopraffatti da questo tedioso argomento, si può saltare alla prossima sezione e tornare qua più tardi.

Seam è utile anche se non si è ancora pronti per il grande salto in EJB3.0. In questo caso si usa Hibernate3 o JPA invece della persistenza EJB3.0, ed i JavaBean invece dei bean di sessione. Non si avranno a disposizione alcune funzionalità carine per i session bean, ma sarà molto semplice migrare a EJB3.0 quando si sarà pronti ed allora si potrà sfruttare l'architettura unica di Seam per la gestione dichiarativa dello stato.

I componenti JavaBean di Seam non forniscono la demarcazione dichiarativa delle transazioni come fanno i session bean. Si possono gestire manualmente le transazioni usando UserTransaction di JTA od in modo dichiarativo usando l'annotazione @Transactional di Seam. Ma la maggior parte delle applicazioni userà solo le transazioni gestite da Seam con Hibernate ed i JavaBean.

La distribuzione Seam include una versione dell'esempio booking che usa Hibernate3 e JavaBean invece di EJB3, ed un'altra versione che usa JPA e JavaBean. Queste applicazioni d'esempio sono pronte per essere deployate in ogni application server J2EE.

E' possibile usare Seam completamente fuori dall'ambiente EE. In questo caso serve istruire Seam come gestire le transazioni gestire, poiché non sarà disponibile JTA. Se si usa JTA, si può dire a Seam di usare le transazioni resource-local di JTA, cioè EntityTransaction, in questo modo:


<transaction:entity-transaction entity-manager="#{entityManager}"/>

Se si usa Hibernate, si può dire a Seam di usare l'API transaction di Hibernate in questo modo:


<transaction:hibernate-transaction session="#{session}"/>

Certamente occorre definire un datasource.

Un'alternativa migliore è usare JBoss Embedded per accedere alle API EE.

JBoss Embedded consente di eseguire i componenti EJB3 fuori dal contesto dell'application server Java EE 5. Questo è utile specialmente, ma non solo, per il testing.

L'applicazione d'esempio booking include la suite d'integrazione per TestNG che esegue JBoss Embedded via SeamTest.

L'applicazione d'esempio booking può essere deployata via Tomcat.

Embedded JBoss deve essere installato in Tomcat per le eseguire correttamente le applicazioni Seam. Embedded JBoss gira con JDK 5 o JDK 6 (si veda Sezione 42.1, «Dipendenze JDK» per i dettagli con JDK 6). Embedded JBoss può essere scaricato qua. Il processo di installazione di Embedded JBoss in Tomcat 6 è abbastanza semplice. Innanzitutto bisogna copiare i jar di Embedded JBoss ed i file di configurazione in Tomcat.

  • Copiare tutti i file e le directory di Embedded JBoss bootstrap e la directory lib, tranne il file jndi.properties, nella directory di Tomcat lib.

  • Rimuovere il file annotations-api.jar dalla directory Tomcat lib.

Poi devono essere aggiornati due file di configurazione per poter aggiungere funzionalità specifiche di JBoss Embedded.

  • Aggiungere il listener Embedded JBoss EmbeddedJBossBootstrapListener a conf/server.xml. Deve apparire dopo tutti gli altri listener nel file:

    
    <Server port="8005" shutdown="SHUTDOWN">

      <!-- Comment these entries out to disable JMX MBeans support used for the 
           administration web application -->
      <Listener className="org.apache.catalina.core.AprLifecycleListener" />
      <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
      <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
      <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener" />
    
      <!-- Add this listener -->
      <Listener className="org.jboss.embedded.tomcat.EmbeddedJBossBootstrapListener" />
  • La scansione del file WAR può essere abilitata aggiungendo il listener WebinfScanner in conf/context.xml:

    
    <Context>
        <!-- Default set of monitored resources -->
        <WatchedResource
    >WEB-INF/web.xml</WatchedResource>
        
        <!-- Uncomment this to disable session persistence across Tomcat restarts -->
        <!--
        <Manager pathname="" />
        -->
    
      <!-- Add this listener -->
      <Listener className="org.jboss.embedded.tomcat.WebinfScanner" />
    
    </Context
    >
  • Se si usa Sun JDK 6, occorre impostare l'opzione Java sun.lang.ClassLoader.allowArraySyntax a true nella variabile d'ambiente JAVA_OPTS usata dallo script di avvio Catalina (catalina.bat in Windows o catalina.sh in Unix).

    Aprire in un editor lo script appropriato per il proprio sistema operativo. Aggiungere una nuova linea immediatamente sotto i commenti in cima al file dove verrà definita la variabile d'ambiente JAVA_OPTS. Su Windows, usare la seguente sintassi:

    set JAVA_OPTS=%JAVA_OPTS% -Dsun.lang.ClassLoader.allowArraySyntax=true

    In Unix, usare invece questa sintassi:

    JAVA_OPTS="$JAVA_OPTS -Dsun.lang.ClassLoader.allowArraySyntax=true"

Per ulteriorio opzioni di configurazione, si prega di vedere l'integrazione con Embedded JBoss Tomcat wiki entry.

L'integrazione jBPM di Seam non è installata di default, quindi occorre abilitare jBPM installando il componente predefinito. Serve anche elencare esplicitamente le definizioni di processo ed i pageflow. In components.xml:


<bpm:jbpm>
    <bpm:pageflow-definitions>
        <value
>createDocument.jpdl.xml</value>
        <value
>editDocument.jpdl.xml</value>
        <value
>approveDocument.jpdl.xml</value>
    </bpm:pageflow-definitions>
    <bpm:process-definitions>
        <value
>documentLifecycle.jpdl.xml</value>
    </bpm:process-definitions>
</bpm:jbpm
>

Non servono ulteriori configurazioni se si usano solo i pageflow. Se si hanno definizioni di processi di business, bisogna fornire una configurazione jBPM ed una configurazione Hibernate per jBPM. La demo Seam DVD Store include i file d'esempio jbpm.cfg.xml e hibernate.cfg.xml che funzionano con Seam:


<jbpm-configuration>

  <jbpm-context>
    <service name="persistence">
       <factory>
          <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
             <field name="isTransactionEnabled"
><false/></field>
          </bean>
       </factory>
    </service>
    <service name="tx" factory="org.jbpm.tx.TxServiceFactory" />
    <service name="message" factory="org.jbpm.msg.db.DbMessageServiceFactory" />
    <service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory" />
    <service name="logging" factory="org.jbpm.logging.db.DbLoggingServiceFactory" />
    <service name="authentication" 
             factory="org.jbpm.security.authentication.DefaultAuthenticationServiceFactory" />
  </jbpm-context>

</jbpm-configuration
>

La cosa più importante da notare è che il controllo della transazione jBPM è disabilitato. Seam o EJB3 dovrebbero controllare le transazioni JTA.

E' molto importante che il timeout per i bean di sessione stateful sia impostato ad un tempo maggiore del timeout per le sessioni HTTP, altrimenti SFSB può andare in timeout primache la sessione HTTP sia terminata. JBoss AS ha un timeout di default di 30 minuti, che è impostato nel file server/default/conf/standardjboss.xml (sostituire defaultcon la propria configurazione).

Il timeout di default di SFSB può essere impostato modificando il valore di max-bean-life nella configurazione della cache LRUStatefulContextCachePolicy:


<container-cache-conf>
    <cache-policy
>org.jboss.ejb.plugins.LRUStatefulContextCachePolicy</cache-policy>
    <cache-policy-conf>
        <min-capacity
>50</min-capacity>
        <max-capacity
>1000000</max-capacity>
        <remover-period
>1800</remover-period>

        <!-- SFSB timeout in seconds; 1800 seconds == 30 minutes -->
        <max-bean-life
>1800</max-bean-life
>  

        <overager-period
>300</overager-period>
        <max-bean-age
>600</max-bean-age>
        <resizer-period
>400</resizer-period>
        <max-cache-miss-period
>60</max-cache-miss-period>
        <min-cache-miss-period
>1</min-cache-miss-period>
        <cache-load-factor
>0.75</cache-load-factor>
    </cache-policy-conf>
</container-cache-conf
>

Il timeout di default per la sessione HTTP può essere modificato in server/default/deploy/jbossweb-tomcat55.sar/conf/web.xml per JBoss 4.0.x, o in server/default/deploy/jboss-web.deployer/conf/web.xml per JBoss 4.2.x o successivi. La seguente riga in questo file controlla il timeout di default per la sessione di tutte le applicazioni web:


<session-config>
    <!-- HTTP Session timeout, in minutes -->
    <session-timeout
>30</session-timeout>
</session-config
>

Per sovrascrivere questo valore per la propria applicazione, si includa semplicemente questa riga nel proprio web.xml.

Se si vogliono eseguire le applicazioni in un portlet, si guardi JBoss Portlet Bridge, un'implementazione di JSR-301 che supporta JSF con i portlet, con estensioni per Seam e RichFaces. Si veda http://labs.jboss.com/portletbridge.

Seam scansiona all'avvio tutti i jar contenenti /seam.properties, /META-INF/components.xml o /META-INF/seam.properties. Per esempio, tutte le classi annotate con @Name vengono registrate da Seam come componenti Seam.

Si potrebbe volere fare gestire a Seam delle risorse personalizzate. Un comune caso d'uso è gestire una specifica annotazione, Seam fornisce un supporto specifico per questo. Innanzitutto, dire a Seam quali annotazioni gestire in /META-INF/seam-deployment.properties:

# A colon-separated list of annotation types to handle
org.jboss.seam.deployment.annotationTypes=com.acme.Foo:com.acme.Bar

Poi durante l'avvio dell'applicazione si può comunicare con tutte le classi annotate con @Foo:

@Name("fooStartup")
@Scope(APPLICATION)
@Startup
public class FooStartup {

   @In("#{deploymentStrategy.annotatedClasses['com.acme.Foo']}")
   private Set<Class<Object
>
> fooClasses;
   
   @In("#{hotDeploymentStrategy.annotatedClasses['com.acme.Foo']}")
   private Set<Class<Object
>
> hotFooClasses;

   @Create
   public void create() {
      for (Class clazz: fooClasses) {
         handleClass(clazz);
      }
      for (Class clazz: hotFooClasses) {
         handleClass(clazz);
      }
   }
   
   public void handleClass(Class clazz) {
       // ...
   }

}

Si può gestire qualsiasi risorsa. Per esempio, si processano i file con estensione .foo.xml. Per fare questo occorre scrivere un deployment handler personalizzato:

public class FooDeploymentHandler implements DeploymentHandler {
    private static DeploymentMetadata FOO_METADATA = new DeploymentMetadata()
    {

        public String getFileNameSuffix() {
            return ".foo.xml";
        }
    };
    
   public String getName() {
      return "fooDeploymentHandler";
   }

    public DeploymentMetadata getMetadata() {
        return FOO_METADATA;
    }
}

Qua viene costruita una lista di file con il suffisso .foo.xml.

Poi occorre registrare il deployment handler con Seam in /META-INF/seam-deployment.properties. Si possono registrare più deployment handler usando una lista separata da virgola.

# For standard deployment
org.jboss.seam.deployment.deploymentHandlers=com.acme.FooDeploymentHandler
# For hot deployment
org.jboss.seam.deployment.hotDeploymentHandlers=com.acme.FooDeploymentHandler

Seam utilizza internamente dei deployment handler per installare componenti e namespace. Si può facilmente accedere ad un deployment handler durante l'avvio di un componente con scope APPLICATION:

@Name("fooStartup")
@Scope(APPLICATION)
@Startup
public class FooStartup {

   @In("#{deploymentStrategy.deploymentHandlers['fooDeploymentHandler']}")
   private FooDeploymentHandler myDeploymentHandler;
   
   @In("#{hotDeploymentStrategy.deploymentHandlers['fooDeploymentHandler']}")
   private FooDeploymentHandler myHotDeploymentHandler;

   @Create
   public void create() {
      for (FileDescriptor fd: myDeploymentHandler.getResources()) {
           handleFooXml(fd);
      }
      
      for (FileDescriptor f: myHotDeploymentHandler.getResources()) {
           handleFooXml(fd);
      }
   }

   public void handleFooXml(FileDescriptor fd) {
       // ...
   }
}