SlideShare uma empresa Scribd logo
1 de 58
Baixar para ler offline
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
===============================================================================
Resumo Anotações para Certificação SCBCD 5.0

Autor:
         Gilberto Augusto Holms
         @gibaholms
         gibaholms85@gmail.com
         http://gibaholms.wordpress.com/
===============================================================================

- Introdução

        . EJB: Modelo de componentes padrão do lado do servidor para aplicativos
de negócio distribuídos
                - Escalonáveis
                - Transacionais
                - Seguros com multi-usuários
        . Bean de Entidade (JPA):
                - A JPA pode funcionar sozinha, porém o container EJB3 fornece
integração adicional.
                - É um POJO, e não um componente (como era no 2.1).
                - Obrigatório uma chave primária ( @Id ), que pode ser um
primitivo ou uma classe.
                - As anotations podem estar tanto nos atributos quanto nos
métodos GETTER.

        . Persistence.xml
                - É obrigatório
                - Sobrescreve as annotations
                - Deployado num JAR junto com as entidades
                - Pode declarar várias Persistence Units
                - Persistence Unit -> composta por Entidades, representa uma
base de dados

        . Interfaces de Negocio -> obrigatório ao menos uma interface de negócio
                - javax.ejb.Local (não utiliza protocolos distribuídos para
acessar – apenas mesma JVM)
                - javax.ejb.Remote
                - javax.jms.MessageListener
                - javax.jws.WebService
         . Container EJB, seis serviços primários:
                 - Concorrência
                 - Transação
                 - Persistência
                 - Distribuição de Objetos
                 - Atribuição de Nomes (JNDI)
                 - Segurança
                 - Mensageria Assíncrona
                 - Temporização

        . Serviços que melhoram o desempenho para grande número de clientes e
beans instanciados:
                - Pool de instâncias (Beans Stateless e MDB):
                        . Clientes nunca acessam um bean diretamente, portanto o
container pode criar um pool de instancias e
                        gerenciá-lo reaproveitando recursos. Uma mesma instância
serve vários clientes (um de cada vez).
                - Ativação (Beans Statefull)
                        . As variáveis de instância do bean são persistidas em
um armazenamento secundário, e o bean é removido
                        da memória (apassivação). Quando é invocado outro
método, uma nova instância é criada e seu estado anterior
                        é recuperado do armazenamento (ativação). Porém, o Stub
não perde a conexão durante a apassivação.

                                     Página 1
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                        . O objeto não precisa ser serializável, o fornecedor
escolhe um método de ativação que independa disso.
                        Para atributos transientes, o comportamento depende da
implementação do container.
                        . É fornecido o callback @PrePassivate e @PostActivate.
Serviços de contexto e o EntityManager devem
                        ser mantidos durante o processo de apassivação.
        . Java EE Connectors (JCA)
                . Fornece mecanismo para criação de interfaces entre o container
e sistemas legados, permitindo que os
                legados disparem mensagens para MDBs do conteiner.
        . Concorrência:
                . Beans se sessão não executam em multithread, portanto é
proibido utilizar a palavra synchronized e também é
                proibido criar threads dentro de beans, pois o container precisa
ter certeza que está com o controle sobre o
                comportamento de todas as instancias do bean.

                . Beans de entidade podem ser acessados de forma concorrente, o
container pode utilizar Optimistic Locking ou
                isolamento Serialized no JDBC.
                . Beans de mensagem podem processar mensagens simultaneamente,
onde cada instancia do pool pode processar
                uma mensagem.

- Session Beans
        . Interface Remota
                - Todos os parametros são copiados, inclusive os objetos, mesmo
se estiver na mesma JVM (chamada "por valor")

                  @Remote
                  public interface MyBusinessInterfaceRemote { ... }
        . Interface Local
                - Precisa estar na mesma JVM
                - Os parametros possuem comportamento normal, onde objetos são
passados por referência (chamada "por referência)
                  @Local
                  public interface MyBusinessInterfaceLocal { ... }
       . Obs.:
                - Parametros de tipo objeto precisam extender Serializable ou
Externalizable para poderem ser transferidos
                pela rede
                - Podem lançar exceções. Deve-se lançar apenas exceções de
negócio, e não de subsistemas Java
                - Uma exceção de aplicativo é propagada ao cliente, e qualquer
variável de instância dela deve ser serializavel
                - Todas exceções de runtime são capturadas pelo container e
empacotadas em EJBException
                - Pode declarar @Local(MyBusinessInterfaceLocal.class) no
próprio bean, não precisando ele declarar a
                implementação da interface explicitamente e nem precisando
anotar a interface. Idem para @Remote
       . Descritor de Implantação
               - Fica dentro do JAR do projeto EJB, em: META-INF/ejb-jar.xml

       . Exemplo de EJB via XML
                  <ejb-jar>
                          <enterprise-beans>
                                      Página 2
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                                <session>
                                        <ejb-name>ProcessPaymentBean</ejb-name>
<remote>com.titan.processpayment.ProcessPaymentRemote</remote>
<local>com.titan.processpayment.ProcessPaymentLocal</local>
<ejb-class>com.titan.processpayment.ProcessPaymentBean</ejb-class>
                                        <session-type>Stateless</session-type>
                                </session>
                        </enterprise-beans>
                </ejb-jar>

- SessionContext
        public interface javax.ejb.SessionContext extends javax.ejb.EJBContext {
                MessageContext getMessageContext( ) throws
IllegalStateException;
                <T> getBusinessObject(Class<T> businessInterface) throws
IllegalStateException;
                Class getInvokedBusinessInterface( );
                //METODOS OBSOLETOS - LANÇAM EXCEPTION SE CHAMADOS
                EJBLocalObject getEJBLocalObject( ) throws IllegalStateException
                EJBObject getEJBObject( ) throws IllegalStateException;
        }

                . getBusinessObject
                        Retorna uma referência (do tipo da interface de
parametro) ao objeto EJB atual. É ilegal que um bean
                        envie uma referencia this para outro bean, para isso
serve este método
                . getInvokedBusinessInterface
                        Retorna a classe da interface de negócio invocada para o
bean atual
                . Obs.:
                          - Herda mais todos os métodos de EJBContext
                          - O container injeta o SessionContext via anotação
@Resource
- EJBContext

        public interface EJBContext {
             public Object lookup(String name);
             // security methods
             public java.security.Principal getCallerPrincipal( );
             public boolean isCallerInRole(java.lang.String roleName);

            // transaction methods
            public javax.transaction.UserTransaction getUserTransaction( )
throws java.lang.IllegalStateException;
            public boolean getRollbackOnly( ) throws
java.lang.IllegalStateException;
            public void setRollbackOnly( ) throws
java.lang.IllegalStateException;
                // OBSOLETO
            public TimerService getTimerService( ) throws
java.lang.IllegalStateException;
             // METODOS OBSOLETOS - LANÇAM RuntimeException SE CHAMADOS
             public java.security.Identity getCallerIdentity( );
             public boolean isCallerInRole(java.security.Identity role);
             public java.util.Properties getEnvironment( );
                                     Página 3
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
            public EJBHome getEJBHome( ) java.lang.IllegalStateException;
            public EJBLocalHome getEJBLocalHome( )
java.lang.IllegalStateException;
                public Properties getEnvironment();
        }

                . getCallerPrincipal
                        Retorna o objeto Principal referente a quem está
acessando o bean
               . isCallerInRole
                       Retorna se o usuário atual pertence a determinada role

               . lookup
                       Permite pesquisar entradas no ENC do EJB.
--------------------------------------------------------------------------------
------------------------------------------
- Stateless Session Beans

       @Stateless
       public class MyBean implements MyBusinessInterface {...}
       . Ciclo de Vida (TODO)

        . Precisa de um construtor padrão
        . Métodos de ciclo de vida:
                @PostConstruct
                        Após o conteiner instanciar o bean (não significa sair
do pool)
                @PreDestroy
                        Antes do container destruir o bean (não significa voltar
pro pool). Durante a chamada, ainda estão
                        disponíveis SessionContext e JNDI ENC
        . Obter a referência remota não indica que o bean saiu do pool. O bean
sai do pool e é configurado para o cliente
        apenas depois que o cliente invoca o primeiro método do bean

--------------------------------------------------------------------------------
------------------------------------------

- Statefull Sessson Beans
       @Statefull
       public class MyBean implements MyBusinessInterface {...}

       . Ciclo de Vida (TODO)
       . Precisa de um construtor padrão
       . Métodos de ciclo de vida:
               @PostConstruct
                       Após o conteiner instanciar o bean
               @PreDestroy
                       Antes do container destruir o bean. Durante a chamada,
ainda estão
                       disponíveis SessionContext e JNDI ENC
                @PrePassivate
                        Antes do bean ser apassivado (serializado para
armazenamento de estado). Deve liberar recursos e setar
                        campos transient com valores nulos.
                        Objetos que são passivados e gerenciados
automaticamente:
                                - Tipos primitivos
                                    Página 4
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                               - Qualquer objeto java serializavel
                               - SessionContext
                               - UserTransaction
                               - javax.naming.Context
                               - EntityManager
                               - EntityManagerFactory
                               - Fabricas injetadas por @Resource
                               - Referencias injetadas por @EJB
                @PostActivate
                        Depois do bean ser ativado (desserializado para
recuperação de estado). Foge à regra da desserialização
                        java no que se trata de variáveis transient, cujo valor
assumido será aleatório, e não o valor padrão,
                        portanto este método deve reabrir os recursos e setar
essas variáveis
        . O beans Statefull é removido da memória quando:
                - É chamado o método @Remove
                - O container detecta que deu timeout e o bean expirou (não pode
expirar durante uma transação)
                - @PreDestroy é chamado apenas no caso do @Remove. Em caso de
expiração, depende do fornecedor
                a chamada desse método ou não
        . Apenas obter a referência remota já cria uma sessão dedicada ao
cliente, porém não cria a instância. A
        instância é criada depois de chamar o primeiro método do bean

        . No caso de beans Statefull aninhados, a sessão do filho pertence ao
pai, ou seja, se o cliente
        remove o pai, o pai remove o filho automaticamente
        . Contexto de Persistencia Extendido:
                - Pode apenas em bean Statefull
                - Faz com que todas as Entidades mantenham-se gerenciadas
durante diferentes invocações de métodos
                - Se ele contiver outro bean Statefull aninhado, e esse bean:
tiver interface local e também tiver
                contexto extendido, os dois beans compartilham o mesmo contexto
de persistencia extendido
                (mesmo EntityManager)
- Entity Manager
        @Stateless
        public class MyBean implements MyBusinessInterface {
                @PersistenceContext(unitName="titan",
type=PersistenceContextType.TRANSACTION)
                private EntityManager manager;
                ...
        }

                . Atributo type é opcional, o padrão vem TRANSACTION, mas
podemos optar por EXTENDED.
                        Se for TRANSACTION, diferentes instancias de
EntityManager injetadas em beans diferentes estarão no
                        mesmo contexto de persistência, até que a transação
geral termine
                        O tipo EXTENDED pode ser utilizado apenas em beans
@Statefull, e esse contexto dura o mesmo tempo de
                        vida da instancia do bean (as transações em particular
precisam ser demarcadas).
        . Contexto de Persistência
                Tempo em que as entidade são gerenciadas pelo EntityManager.
Quando o contexto de persistencia acaba,
                todas as entidades tornam-se detached.
                                    Página 5
Resumo_Anotacoes_Certificacao_SCBCD_5.txt

        . Escopo de Transação
                PersistenceContextType.TRANSACTION
                        O contexto de persistência dura exatamente o tempo de
uma transação JTA, pode apenas ser utilizado
                        em servidores J2EE, com entidades injetadas via
@PersistenceContext
                PersistenceContextType.EXTENDED
                        O contexto de persistência permanece ativo durante
várias transações, pode ser utilizado apenas em
                        beans Statefull

       . Arquivo persistence.xml
               É obrigatório:
               <persistence>
                       <persistence-unit name="titan">
<jta-data-source>java:/OracleDS</jta-data-source>
                                <properties>
                                        <propertie
name="org.hibernate.hbm2ddl">update</propertie>
                                </properties>
                        </persistence-unit>
                </persistence>

               Obs.:
                        <persistence-unit>
                                atributo name – obrigatório
                                atributo transaction-type – opcional (conf. JTA
para servers J2EE ou RESOURCE_LOCAL para Java SE)
                        outras tags opcionais:
                                <description>
                                <provider> : provedor de persistência (para J2EE
vem o default do container)
                                <non-jta-data-source>
                                <mapping-file> : outro arquivo de mapeamento
(container procura orm.xml e outros listados aqui)
                                <jar-file> : carregar outro jar de entidades
                                <class> : carregar classes específicas
                                <exclude-unlisted-classes> : não carregar
qualquer classe que não esteja declarada
                                        no persistence.xml (o jar default é
ignorado)
        . Empacotamento
                Sempre um arquivo jar com persistence.xml dentro de seu META-INF
(se houver, o arquivo orm.xml também deve
                estar nessa pasta)
                        . Classpath Java SE <JAR AQUI>
                        . EJB-JAR
                        . WAR > WEB-INF > lib <JAR AQUI>
                        . EAR <JAR AQUI>
                        . EAR > lib <JAR AQUI>
--------------------------------------------------------------------------------
------------------------------------------
- Entity Manager Factory
       @Stateless
       public class FactoryBean implements FactoryBusinessInterface {

               @PersistenceUnit(unitName=”titan”)
               private EntityManagerFactory factory1;
               private EntityManagerFactory factory2;

                                    Página 6
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                   @PersistenceUnit(unitName=”toto”)
                   public void setFactory2(EntityManagerFactory factory2) {...}
         }
        . Não pode chamar método close() no EntityManagerFactory nem no
EntityManager se eles forem injetados pelo container
        (lança IllegalStateException), pois o container cuida dessa limpeza.
        . O container injeta em um atributo ou em um setter
        . Se criar o EntityManager utilizando o factory, as transações serão de
escopo extendido, ou seja, é preciso
        chamar EntityManager.joinTransaction()
--------------------------------------------------------------------------------
------------------------------------------
- Métodos de EntityManager

        persist(Object entity)
                .Enfileira a entidade para criação no banco (não representa o
momento real do insert)
                . É possível chamar persist     fora de uma transação apenas se
o contexto for EXTENDED, nesse caso, a inserção é
                enfileirada até o contexto ser associado com uma transação
                . Se o parâmetro não for uma entidade, lança
IllegalArgumentException
                . Se for invocado fora do contexto de transação e for tipo
TRANSACTION, lança uma TransactionRequiredException

        joinTransaction()
                . Usado apenas se o contexto for criado pela
EntityManagerFactory
                . Associa o contexto de persistência à transação
                . Obs.: se o contexto for gerenciado pelo container, ele é
associado automaticamente (não precisa desse método)

        find(Class<T> entityClass, Object pk) : Entidade
        getReference(Class<T> entityClass, Object pk) : Entidade
                . Retornam uma entidade a partir de sua chave primária
                . O find, se não encontrar retorna null, e utiliza as
configurações de lazy-loading
                . O getReference, se não encontrar lança EntityNotFoundException
                . Se o contexto de persistência estiver ativo, ela é acoplada,
senão ela é desacoplada
         createQuery e createXXXQuery
                 . Executam querys EJB-QL e consultas nativas (retornam um objeto
Query)
                . Entidades retornadas permanegem gerenciadas enquanto o
contexto de persistência estiver ativo
         flush()
                   . Sincroniza as atualizações no banco antes de terminar a
transacao
        merge(Object entity) : Entidade
                . Atualiza uma entidade desacoplada e retorna uma cópia dela
acoplada
                . ATENÇÃO: o objeto de parâmetro nunca é gerenciado pelo
EntityManager, e sim sua cópia que retorna. Se ele
                já estiver gerenciado a mesma instancia, ele atualiza ela e
retorna sua referencia.

         remove(Object entity)
                 Remove a entidade da base e torna ela desacoplada
         refresh(Object entity)
                 . Atualiza a entidade acoplada com os dados da base
                                     Página 7
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                . Se ela não for acoplada ao próprio EntityManager que invoca o
método, é lançada IllegalArgumentException
                . Se o objeto não estiver mais no banco devido outra Thread ou
Processo ter removido ele,
                será lançado EntityNotFoundException

        contains(Object entity) : Boolean
                . Retorna true se a entidade estiver acoplada, false caso
contrario.
       clear()
                 . Desacopla todas as entidades atuais gerenciadas pelo
EntityManager
                 . Suas modificações são perdidas, portanto é prudente chamar
flush() antes.
        setFlushMode(FlushModeType tp)
                . Pode receber FlushModeType.AUTO ou FlushModeType.COMMIT
                        . AUTO - é o padrão, onde a implementação da JPA decide
quando quer fazer o flush(), onde é certo apenas que
                        ele fará no final da transação, mas também fazer antes
                        . COMMIT - força para que ele sincronize apenas no final
da transação. COMMIT Melhora a performance pois cada
                        atualização requer um bloqueio, e fazer todas de uma vez
é mais rápido
        getDelegate() : EntityManagerImpl
                . Retorna uma instancia ao objeto do fornecedor do implementador
EntityManager, que pode proporcionar
                extensões à JPA padrão
--------------------------------------------------------------------------------
------------------------------------------
- EntityTransaction
        É a API de transação fornecida como alternativa à JTA. Ela pode ser
usada apenas se o atributo transaction-type
        for RESOURCE_LOCAL. Permite utilizar begin(), commit() e rollback()
manualmente.

       EntityTransaction et = myEntityManager.getTransaction();
       et.begin();
       myEntityManager.persist(myEntity);
       et.commit();
        . O método begin() lança IllegalStateException se já houver uma
transação ativa, commit() e rollback() lançam
        a mesma exceção se não houver transação ativa.
- Criando Entidades

        @Entity
        @Table(name="CUSTOMER_TABLE",
                catalog="TITAN",
                schema="TITAN",
                uniqueConstraints=@UniqueConstraint(columnNames={"EMP_ID",
"EMP_NAME"})
        )
        public class Customer {
                @Id
                @GeneratedValue
                @Column(name="CUST_ID", nullable=false,
columnDefinition="integer")
                private int id;
                 @Column(name="FIRST_NAME", length=20, nullable=false)
                 private String firstName;
                                     Página 8
Resumo_Anotacoes_Certificacao_SCBCD_5.txt

               ...
       }
        <entity-mappings>
                <entity class="com.titan.domain.Customer" access="PROPERTY">
<!-- PROPERTY e FIELD não se misturam -->
                        <table name="CUSTOMER_TABLE">
                                <unique-constraint>
<column-name>SOME_OTHER_ATTRIBUTE</column_name>
                                </unique-constraint>
                        </table>
                        <attributes>
                                <id name="id">
                                        <column name="CUST_ID" nullable="false"
column-definition="integer"/>
                                        <generated-value strategy="AUTO"/>
                                </id>
                                <basic name="firstName">
                                        <column name="FIRST_NAME"
nullable="false" length="20"/>
                                </basic>
                        </attributes>
                </entity>
        </entity-mappings>

--------------------------------------------------------------------------------
------------------------------------------

- Tipos de geradores de PK
       @GeneratedValue ou @GeneratedValue(strategy=GeneratorType.AUTO)

               <attributes>
                       <id name="id">
                               <generated-value strategy="AUTO"/>
                       </id>
               </attributes>

        @TableGenerator(name="CUST_GENERATOR"
                table="GENERATOR_TABLE"
                pkColumnName="PRIMARY_KEY_COLUMN"
                valueColumnName="VALUE_COLUMN"
                pkColumnValue="CUST_ID"
                allocationSize=10
        )
        @GeneratedValue(strategy=GenerationType.TABLE,
generator="CUST_GENERATOR")
                <table-generator name="CUST_GENERATOR"
                        table="GENERATOR_TABLE"
                        pk-column-name="PRIMARY_KEY_COLUMN"
                        value-column-name="VALUE_COLUMN"
                        pk-column-value="CUST_ID"
                        allocation-size="10" />
                <attributes>
                        <id name="id">
                                <generated-value strategy="TABLE"
generator="CUST_GENERATOR"/>
                        </id>
                </attributes>

        @SequenceGenerator(name="CUSTOMER_SEQUENCE", sequenceName="CUST_SEQ")
        @GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="CUSTOMER_SEQUENCE")
               <sequence-generator name="CUSTOMER_SEQUENCE"
                                   Página 9
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                        sequence-name="CUST_SEQ"
                        initial-value="0"
                        allocation-size="50"/>
                <attributes>
                        <id name="id">
                                <generated-value strategy="SEQUENCE"
generator="CUSTOMER_SEQUENCE"/>
                        </id>
                </attributes>
--------------------------------------------------------------------------------
------------------------------------------
- PK Compostas: Por PK Class

       public class CustomerPK implements java.io.Serializable {
               private String lastName;
               private long ssn;
               public String getLastName( ) { return this.lastName; }
               public void setLastName(String lastName) { this.lastName =
lastName; }
               public long getSsn( ) { return ssn; }
               public void setSsn(long ssn) { this.ssn = ssn; }

               public boolean equals(Object obj) {
                       if (obj == this) return true;
                       if (!(obj instanceof CustomerPK)) return false;
                       CustomerPK pk = (CustomerPK)obj;
                       if (!lastName.equals(pk.lastName)) return false;
                       if (ssn != pk.ssn) return false;
                       return true;
               }

               public int hashCode( ) {
                       return lastName.hashCode( ) + (int)ssn;
               }
       }

       @Entity
       @IdClass(CustomerPK.class)
       public class Customer {
               private String firstName;
               private String lastName;
               private long ssn;
               @Id
               public String getLastName( ) { return lastName; }
               public void setLastName(String lastName) { this.lastName =
lastName; }
               @Id
               public long getSsn( ) { return ssn; }
               public void setSsn(long ssn) { this.ssn = ssn; }
       }
       Requerimentos para a PK Class:
               . It must be serializable
               . It must have a public no-arg constructor
               . It must implement the equals( ) and hashCode( ) methods.
- PK Compostas: Por Embeddable Class

       @Embeddable
       public class CustomerPK implements java.io.Serializable {
               private String lastName;
               private long ssn;
                                   Página 10
Resumo_Anotacoes_Certificacao_SCBCD_5.txt

               public String getLastName( ) { return this.lastName; }
               public void setLastName(String lastName) { this.lastName =
lastName; }
               public long getSsn( ) { return ssn; }
               public void setSsn(long ssn) { this.ssn = ssn; }
               public boolean equals(Object obj) {
                       if (obj == this) return true;
                       if (!(obj instanceof CustomerPK)) return false;
                       CustomerPK pk = (CustomerPK)obj;
                       if (!lastName.equals(pk.lastName)) return false;
                       if (ssn != pk.ssn) return false;
                       return true;
               }
               public int hashCode( ) {
                       return lastName.hashCode( ) + (int)ssn;
               }
       }
       @Entity
       public class Customer {
               private String firstName;
               private CustomerPK pk;

               @EmbeddedId
               public PK getPk( ) { return pk; }
               public void setPk(CustomerPK pk) { this.pk = pk; }
       }
        Obs.: Podemos sobrescrever as anotações @Column feitas na classe da PK
(não podemos utilizar @Column na classe entidade,
        pois o nome da coluna á definida na classe de PK)
                @EmbeddedId
                @AttributeOverrides({
                        @AttributeOverride(name="lastName",
column=@Column(name="LAST_NAME"),
                        @AttributeOverride(name="ssn",
column=@Column(name="SSN"))
                })
--------------------------------------------------------------------------------
------------------------------------------
- Mapeando Atributos
       @Transient
               Campo não é criado na base
        @Basic(fetch=FetchType.LAZY, optional=false)
                Se o campo é obrigatório, e permite lazy loading do campo (porém
a especificação não garante o lazy loading real,
                depende da implementação)
        @Temporal(TemporalType.TIME)
                Define o tipo real a gerar na base para um tipo de data java
(DATE, TIME, TIMESTAMP)
       @Lob
                Define que será um tipo binário (blob) ou um tipo sequencial de
caracteres (clob). O tipo real gerado depende do
                tipo de atributo:
                        BLOB: byte[], Byte[], or java.io.Serializable
                        CLOB: char[], Character[], or java.lang.String
       @Enumerated(EnumType.STRING)
                                   Página 11
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                Para mapear um atributo do tipo enum. Pode ser ORDINAL ou
STRING, onde ORDINAL grava o numero do indice do campo
                no enum e STRING grava o proprio nome do enum.
--------------------------------------------------------------------------------
------------------------------------------
- Mapeamentos Multi-Table
        @Entity
        @SecondaryTable(name="ADDRESS_TABLE",
pkJoinColumns={@PrimaryKeyJoinColumn(name="ADDRESS_ID")})
        public class Customer {
                private long id;
                private String firstName;
                private String street;
                private String city;
                ...
                @Column(name="STREET", table="ADDRESS_TABLE")
                public String getStreet( ) { return street; }
                public void setStreet(String street) { this.street = street; }
               @Column(name="CITY", table="ADDRESS_TABLE")
               public String getCity( ) { return city; }
               public void setCity(String city) { this.city = city; }
               ...
       }

        Obs.: É suportado mais de uma tabela secundária:
                @SecondaryTables({
                        @SecondaryTable(name="ADDRESS_TABLE",
pkJoinColumns={@PrimaryKeyJoinColumn (name="ADDRESS_ID")}),
                        @SecondaryTable(name="CREDIT_CARD_TABLE",
pkJoinColumns={@PrimaryKeyJoinColumn (name="CC_ID")})
                })
--------------------------------------------------------------------------------
------------------------------------------

- Campos de Embeddable Objects

       @Embeddable
       public class Address {
          private String street;
          private String city;
          private String state;
       }
       @Entity
       public class Customer {
               private long id;
               private String firstName;
               private String lastName;
               @Embedded
               private Address address;
       }
        Obs.: como as colunas geradas pela classe embedded são definidas dentro
dela, também vale o conceito de
        @AttributeOverrides para definir outras caracteristicas de coluna dentro
da classe utilizadora

--------------------------------------------------------------------------------
------------------------------------------
- Unidirecional "Um-Para-Um"

                                   Página 12
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
@Entity
public class Customer {
...
        @OneToOne(cascade={CascadeType.ALL})
        private Address address;
...
}

<entity-mappings>
        <entity class="com.titan.domain.Customer" access="FIELD"> <!-- ou
access="PROPERTY" -->
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <one-to-one name="address"
targetEntity="com.titan.domain.Address" fetch="LAZY" optional="true">
                                <cascade>ALL</cascade> <!-- ou <cascade-all/>
-->
                                <join-column name="ADDRESS_ID"/> <!-- ou
<primary-key-join-column/> -->
                        </one-to-one>
                </attributes>
        </entity>
</entity-mappings>
--------------------------------------------------------------------------------
------------------------------------------

- Bidirecional "Um-Para-Um"
@Entity
public class Customer {
...
        @OneToOne(cascade={CascadeType.ALL})
        private CreditCard creditCard;
...
}
@Entity
public class CreditCard {
...
        @OneToOne(mappedBy="creditCard")
    private Customer customer;
...
}
<entity-mappings>
        <entity class="com.titan.domain.Customer" access="FIELD">
                ...
        </entity>
        <entity class="com.titan.domain.CreditCard" access="FIELD">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <one-to-one name="customer"
target-entity="com.titan.domain.Customer" mapped-by="creditCard"/>
                </attributes>
        </entity>
</entity-mappings>
--------------------------------------------------------------------------------
------------------------------------------
- Unidirecional "Um-Para-Muitos"
@Entity
                                   Página 13
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
public class Customer {
...
        @OneToMany(cascade={CascadeType.ALL})
    @JoinColumn(name="CUSTOMER_ID")
    private Collection<Phone> phoneNumbers = new ArrayList<Phone>( );
...
}
<entity-mappings>
        <entity class="com.titan.domain.Customer" access="FIELD">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <one-to-many name="phones"
targetEntity="com.titan.domain.Phone">
                                <cascade-all/>
                                <join-column name="CUSTOMER_ID"/> <!-- ou
<join-table name="CUSTOMER_PHONE"> -->
                        </one-to-many>
                </attributes>
        </entity>
</entity-mappings>
--------------------------------------------------------------------------------
------------------------------------------

- Unidirecional "Muitos-Para-Um"

@Entity
public class Cruise {
...
    @ManyToOne
    @JoinColumn(name="SHIP_ID")
        private Ship ship;
...
}
<entity-mappings>
        <entity class="com.titan.domain.Cruise" access="FIELD">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <many-to-one name="ship"
target-entity="com.titan.domain.Ship" fetch="EAGER">
                                <join-column name="SHIP_ID"/>
                        </many-to-one>
                </attributes>
        </entity>
</entity-mappings>
--------------------------------------------------------------------------------
------------------------------------------
- Bidirecional "Um-Para-Muitos" / "Muitos-Para-Um"
@Entity
public class Reservation {
...
        @ManyToOne
    @JoinColumn(name="CRUISE_ID")
    private Cruise cruise;
...
}
@Entity
public class Cruise {
                                    Página 14
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
...
          @OneToMany(mappedBy="cruise")
      private Collection<Reservation> reservations = new ArrayList<Reservation>(
);
...
}
<entity-mappings>
        <entity class="com.titan.domain.Cruise" access="FIELD">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <one-to-many name="ship"
target-entity="com.titan.domain.Reservation" fetch="LAZY" mapped-by="cruise" />
                </attributes>
        </entity>
        <entity class="com.titan.domain.Reservation" access="FIELD">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <many-to-one name="cruise"
target-entity="com.titan.domain.Cruise" fetch="EAGER">
                                <join-column name="CRUISE_ID"/>
                        </many-to-one>
                </attributes>
        </entity>
</entity-mappings>

--------------------------------------------------------------------------------
------------------------------------------

- Unidirecional "Muitos-Para-Muitos"

@Entity
public class Reservation {
...
        @ManyToMany
    private Set<Customer> customers = new HashSet<Customer>( );
...
}

<entity-mappings>
        <entity class="com.titan.domain.Reservation" access="PROPERTY">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <many-to-many name="cabins"
target-entity="com.titan.domain.Cabin" fetch="LAZY" />
                </attributes>
        </entity>
</entity-mappings>
--------------------------------------------------------------------------------
------------------------------------------
- Bidirecional "Muitos-Para-Muitos"
@Entity
public class Reservation {
...
        @ManyToMany
    @JoinTable(name="RESERVATION_CUSTOMER",
                joinColumns={@JoinColumn(name="RESERVATION_ID")},
                inverseJoinColumns={@JoinColumn(name="CUSTOMER_ID")}
        )
                                    Página 15
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
      private Set<Customer> customers = new HashSet<Customer>( );
...
}
@Entity
public class Customer {
...
        @ManyToMany(mappedBy="customers")
    private Collection<Reservation> reservations = new ArrayList<Reservation>(
);
...
}
<entity-mappings>
        <entity class="com.titan.domain.Reservation" access="FIELD">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <many-to-many name="customers"
target-entity="com.titan.domain.Customer" fetch="LAZY">
                                <join-table name="RESERVATION_CUSTOMER">
                                        <join-column name="RESERVATION_ID"/>
                                        <inverse-join-column
name="CUSTOMER_ID"/>
                                </join-table>
                        </many-to-many>
                </attributes>
        </entity>
        <entity class="com.titan.domain.Customer" access="FIELD">
                <attributes>
                        <id name="id">
                                <generated-value/>
                        </id>
                        <many-to-many name="cruise"
target-entity="com.titan.domain.Reservation" fetch="LAZY" mapped-by="customers"
/>
                </attributes>
        </entity>
</entity-mappings>

--------------------------------------------------------------------------------
------------------------------------------

        @PrimaryKeyJoinColumn
                Utilizado no OneToOne, quando queremos que a associação não
utilize um campo de chave estrangeira, neste
                caso a associação será feita gravando IDs de mesmo valor nas
duas tabelas
           @PrimaryKeyJoinColumns({
           @PrimaryKeyJoinColumn(name="ADDR_ID"),
           @PrimaryKeyJoinColumn(name="ADDR_ZIP")
      })

        @JoinColumn(name="TOTO_ID")
                Indica a coluna que receberá a chave primária da outra tabela.
Se quiser que referencia outra coluna que não
                seja a chave primária da tabela, utilizar o atributo
referencedColumnName (porem coluna nao pode ter repetição)
           @JoinColumns({
           @JoinColumn(name="ADDR_ID"),
           @JoinColumn(name="ADDR_ZIP")
      })
                  É utilizado para chaves primárias compostas por mais de uma
coluna

                                      Página 16
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
        @JoinTable
                É utilizada uma tabela de junção de IDs para relacionamentos
Um-Para-Muitos e Muitos-Para-Um
                        Um-Para-Muitos: @JoinTable é padrão
                        Muitos-Para-Um: @JoinColumn é padrão
                        Muitos-Para-Muitos: apenas @JoinTable
       @OrderBy("lastname ASC, firstname DESC")
               Permite ordenação, serve apenas para relacionamento com List
        @MapKey(name="number")
                É utilizado para relacionamento com Map. O atributo name será o
da key do Map, e a entidade relacionada será o value
        FetchType.EAGER e FetchType.LAZY (cuidados)
                Se a entidade estiver "detached" e seu relacionamento LAZY não
for carregado, e tanter ser acessado, será lançada
                uma exceção do provedor de persistência (uma chamada ao .size()
da coleção do relacionamento garante o load da coleção,
                ou o uso do operador FETCH JOIN da ejbql)
                        Cruise detachedCruise = ... ;
                        try {
                                int numReservations =
detachedCruise.getReservations().size();
                        } catch (SomeVendorLazyInitializationException ex) { }

        CascadeType - ALL, PERSIST, MERGE, REMOVE, REFRESH
                Realiza a respectiva operação do EntityManager para todas as
entidades relacionadas. Aumenta a carga de calls na base e
                pode causar efeitos indesejáveis
- Herança: Single Table Per Class
        Schema: é gerada uma tabela contendo todos os atributos de toda a
hierarquia, adicionando
        uma coluna discriminadora, que identifica qual é o tipo.
       Person > Customer > Employee

        @Entity
        @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
        @DiscriminatorColumn(name="DISCRIMINATOR",
discriminatorType=DiscriminatorType.STRING)
        @DiscriminatorValue("PERSON")
        public class Person { ... }
       @Entity
       @DiscriminatorValue("CUST")
       public class Customer extends Person { ... }
       @Entity
       public class Employee extends Customer { ... }

       Obs.:
                @DiscriminatorColumn
                        Pode ser STRING, CHAR ou INTEGER. Não é obrigatório, se
omitido o default é STRING e o nome é gerado
                        pelo fornecedor.
                @DiscriminatorValue
                        Não é obrigatório, se omitido utiliza o nome da classe.
                Vantagens:
                        É simples e performática, não requer joins e é boa para
selects polimorficos.
                Desvantagens:
                        Todas as colunas de todas as subclasses precisam ser
NULLABLE, e não possui um modelo normalizado.

                                    Página 17
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
- Herança: Table Per Concrete Class

        Schema: é gerada uma tabela para cada classe concreta, cada tabela
contendo todos os atributos dessa
        classe e todos seus atributos herdados.

        Person > Customer > Employee
        @Entity
        @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
        public class Person { ... }

        @Entity
        public class Customer extends Person { ... }
        @Entity
        public class Employee extends Customer { ... }
        Obs.:
                Vantagens:
                        Pode ter constraints NOT NULL em qualquer campo, e o
legado pode estar modelado dessa forma.
                Desvantagens:
                        É mais lento, não é normalizado, possui campos
redundantes e tem baixa performance num
                        select polimorfico.

- Herança: Table Per SubClass

        Schema: é gerada uma tabela para cada classe, cada tabela contendo
apenas os atributos da classe, onde
        todas as tabelas são associadas pelas suas chaves primárias.
        Person > Customer > Employee

        @Entity
        @Inheritance(strategy=InheritanceType.JOINED)
        public class Person { ... }

        @Entity
        public class Customer extends Person { ... }
        @Entity
        @PrimaryKeyJoinColumn(name="EMP_PK")
        public class Employee extends Customer { ... }
        Obs.:
                A anotação @PrimaryKeyJoinColumn é obrigatória se as colunas das
chaves primárias possuirem nomes diferentes
                nas tabelas.
                Vantagens:
                        Pode ter constraints NOT NULL em qualquer campo e seu
modelo é normalizado.
                Desvantagens:
                        É mais lento que a SINGLE_TABLE.
- Herança: Nonentity Base Classes
        @MappedSuperclass
        public class Person {
                @Id
                @GeneratedValue
                private int id;
                private String lastname;
                ...
        }

                                    Página 18
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
          @Entity
          @AttributeOverride(name="lastname", column=@Column(name="SURNAME"))
          public class Customer extends Person { ... }
          Obs.:
                A superclasse não é uma entidade e nem é persistida, ela apenas
fornece atributos persistentes
                para as suas subclasses, que podem ser sobrecarregados com o
@AttributeOverrides / @AttributeOverride
- Metodos de Callback

          @PrePersist
                  - Quando uma entidade é agendada para inserção no banco de dados
                          . Depois de persist()
                          . Depois de merge() caso haja inserção aninhada em
cascata
        @PostPersist
                - Quando a inserção real no banco de dados ocorre efetivamente
                        . Depois do flush() se houver inserção infileirada
                        . Depois que o contexto de persistencia atualiza o banco
de dados
                        (se for FlushType.COMMIT, é no final da transação)
          @PostLoad
                  - Depois da entidade ser hidradata com os dados da base
                          . Depois do find(), getReference() ou uma consulta
EJB-QL

        @PreUpdate
                - Antes da entidade ser atualizada no banco de dados
                        . Antes do flush() ou antes de o contexto de
persistencia atualizar o banco de dados

        @PostUpdate
                - Depois da entidade ser atualizada no banco de dados
                        . Depois do flush() ou depois de o contexto de
persistencia atualizar o banco de dados

          @PreRemove
                  - Quando uma entidade é agendada para remoção do banco de dados
                          . Depois de remove()
                          . Depois de merge() caso haja remoção aninhada em
cascata

        @PostRemove
                - Quando a exclusão real no banco de dados ocorre efetivamente
                        . Depois do flush() se houver exclusão infileirada
                        . Depois que o contexto de persistencia atualiza o banco
de dados
                        (se for FlushType.COMMIT, é no final da transação)

          Obs.:
                Na classe de entidade: qualquer método que retorne void e não
receba argumentos
                Na classe listener: qualquer método que retorne void e receba
como argumento um Object (conterá a instância
                da entidade em questão)
--------------------------------------------------------------------------------
------------------------------------------

- Listeners de Entidade
          public class MeuListener1 {
                  ...
                  @PostPersist
                                        Página 19
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                  public void postInsert(Object entity) { ...     }
                  ...
       }
       public class MeuListener2 {
               ...
               @PostPersist
               public void postPersist(Object entity) { ...       }
                  @PostLoad
                  public void postLoad(Object entity) { ...       }
                  ...
       }
       @Entity
       @EntityListeners({MeuListener1.class, MeuListener2.class})
       public class MyEntity {
               @PostPersist
               public void afterInsert() { ... }
       }

       Obs.:
                Chamados na ordem em que foram declarados em @EntityListeners ou
no XML, por ultimo o da entidade
                        postInsert() + postPersist() + afterInsert()

- Herança de Listeners

       @Entity
       @EntityListeners({MeuListener1.class})
       public class Person {
               @PostPersist
               public void parentAfterInsert() { ... }
       }

       @Entity
       @EntityListeners({MeuListener2.class})
       public class Customer extends Person {
               @PostPersist
               public void childAfterInsert() { ... }
       }
       Obs.:
                  Ordem de chamada:
                          PostPersist   de   MeuListener1
                          PostPersist   de   MeuListener2
                          PostPersist   de   Person
                          PostPersist   de   Customer

                  Outras anotations:
                          @ExcludeDefaultListeners
                                  Ignora os "Listeners Padrão" setados na unidade
de persistencia
                          @ExcludeSuperclassListeners
                                  Ignora os listeners herdados
- Declarando Listeners com XML
        <entity class="com.titan.domain.Cabin">
                <entity-listeners>
                        <entity-listener
class="com.titan.listeners.TitanAuditLogger" />
                        <entity-listener
class="com.titan.listeners.EntityJmxNotifier">
                                <pre-persist name="beforeInsert"/>
                                <post-load name="afterLoading"/>
                        </entity-listener>
                                    Página 20
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
               </entity-listeners>
       </entity>
- Declarando "Listeners Padrão"
        Os listeners declarados dessa forma serão aplicados à todas entidades da
unidade de persistencia:
                <entity-mappings>
                        <entity-listeners>
                                <entity-listener
class="com.titan.listeners.EntityJmxNotifier">
                                        <pre-persist name="beforeInsert"/>
                                        <post-load name="afterLoading"/>
                                </entity-listener>
                        </entity-listeners>
                </entity-mappings>
- Conceitos Gerais EJBQL
        . Pode comparar primitivo com Wrapper e comparar valores temporais
        . Comparação de entidades na base é feita pela chave primaria
        . Clausula IN no from: itera a lista e faz join (corresponde a INNER
JOIN ou somente JOIN)
        . Operadores valem apenas no WHERE
        . Clausula IN no where: verifica se valor está dentro da lista de
LITERAIS: IN('X', 'Y', 'Z')
        . Relacionamento "Um-Para-Um" ou campo basico: IS NULL
        . Relacionamento baseado em coleção (muitos): IS EMPTY
        . Cuidado INNER JOIN com IS EMPTY (pag 136)
        . Cuidado: order by e campos que pode (pag 141)
        . Operações em lote (chamar antes: flush e clear)
- Interface Query

        public interface Query {
           public List getResultList( );
           public Object getSingleResult( );
           public int executeUpdate( );
           public Query setMaxResults(int maxResult);
           public Query setFirstResult(int startPosition);
           public Query setHint(String hintName, Object value);
           public Query setParameter(String name, Object value);
           public Query setParameter(String name, Date value, TemporalType
temporalType);
           public Query setParameter(String name, Calendar value, TemporalType
temporalType);
           public Query setParameter(int position, Object value);
           public Query setParameter(int position, Date value, TemporalType
temporalType);
           public Query setParameter(int position, Calendar value, TemporalType
temporalType);
           public Query setFlushMode(FlushModeType flushMode);
        }
        . Retornando Resultados
                Método getSingleResult
                        try {
                                Query query = entityManager.creatQuery(
                       "from Customer c where c.firstName='Bill' and
c.lastName='Burke'");
                                Customer cust = (Customer)query.getSingleResult(
);
                        } catch (EntityNotFoundException notFound) {
                        } catch (NonUniqueResultException nonUnique) {}
                       - Utilizado para retornar apenas um registro:
                               . Não encontrou nenhum registro:
                                   Página 21
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
EntityNotFoundException
                                . Encontrou mais de um registro:
NonUniqueResultException
                Método getResultList
                        Query query = entityManager.creatQuery(
               "from Customer c where c.firstName='Bill' and
c.lastName='Burke'");
                        List bills = query.getResultList( );
                        - Utilizado para retornar uma coleção de registros:
                                . Não encontrou nenhum registro: retorna uma
lista vazia
        . Parametros
                Parametros Nomeados
                        Query query = entityManager.createQuery(
                "from Customer c where c.firstName=:first and
c.lastName=:last");
                        query.setParameter("first", first);
                        query.setParameter("last", last);
                 Parametros Indexados
                         Query query = entityManager.createQuery(
                 "from Customer c where c.firstName=?1 and c.lastName=?2");
                         query.setParameter(1, first);
                         query.setParameter(2, last);

                . Parametros Temporais
                        Query query = entityManager.createQuery(
                "from Customer c where c.dataNascimento=?1");
                        query.setParameter(1, new java.util.Date,
TemporalType.DATE); //DATE, TIME, TIMESTAMP

       . Paginação de Registros
               setFirstResult: seta o índice do primeiro registro a trazer
               setMaxResults: seta a quantidade máxima de registros a trazer
                        Query query = entityManager.createQuery("from Customer
c");
                        List customers =
query.setMaxResults(max).setFirstResult(index).getResultList( );
                Obs.: é perigoso trazer muitos registros de uma vez, pois todos
ficam gerenciados pelo EntityManager
                e o sistema fica pesado, recomenda-se trazer aos poucos dando
clear() no EntityManager
       . Hints
                 Utilizado para setar na query um atributo específico de
fornecedor
                        Query query = manager.createQuery("from Customer c");
                        query.setHint("org.hibernate.timeout", 1000);
        . FlushMode
                query.setFlushMode(FlushModeType.COMMIT);
                        Indica que não deve haver nenhum flush antes da execução
desta query
                query.setFlushMode(FlushModeType.AUTO);
                        É o default, deixa o container livre para fazer flush
antes da query, se desejar

--------------------------------------------------------------------------------
------------------------------------------
- Clausulas EJB-QL

                                    Página 22
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
       . Considerações Gerais
               - As clausulas não são case-sensitive
               - Os nomes de classes e atributos são case-sensitive
        . Abstract Schema Name
                @Entity public class Customer {...}              ->
entityManager.createQuery("SELECT c FROM Customer AS c");
                @Entity(name="Cust") public class Customer {...}           ->
entityManager.createQuery("SELECT c FROM Cust AS c");
       . Simple Queryes

                 SELECT OBJECT( c ) FROM Customer AS c
                 SELECT c FROM Customer AS c
                 SELECT c FROM Customer c
                ERRO: SELECT customer FROM Customer AS customer
                        O identificador não pode ter nome igual ao nome da
entidade, independente do case dos caracteres
                SELECT c.firstName, c.lastName FROM Customer AS c
                        Obs.: se a entidade for mapeada como tipo FIELD, acessa
por nome do atributo, se for como
                        tipo PROPERTY, acessa pelo nome do método JavaBean
transformado em nome de atributo

                 Obs.:
                        Se a query retornar uma entidade, os registros retornam
como um List de entidades
                        Se a query retornar campos escalares, os registros
retornam como um List de Object[]
       . Navegando Entidades

                SELECT c.creditCard.creditCompany.address FROM Customer AS c
                        Efeito: Retorna o "address" da "creditCompany" da
"creditCard" de todos "Customer"
                        Obs.: Permite navegar por relacionamento "unário" ou por
atributo @Embedded
                        Exemplo 1:
                                @Entity
                                public class Address {
                                        private ZipCode zip;
                                }
                                ERRO: SELECT c.address.zip.mainCode FROM
Customer AS c

                                Para tornar o select válido, deveria modificar o
atributo para:
                                        @Embedded
                                        private ZipCode zip;
                         Exemplo 2:
                                 @Entity
                                 public class Customer {
                                         @OneToMany
                                         private List<Phone> phones;
                                 }
                                ERRO: SELECT c.phones.number FROM Customer AS c

                                Isso seria o mesmo que customer.getPhones(
).getNumber( ); o que é INVALIDO.
       . Constructor Expressions

                                    Página 23
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
               public class Name {
                       private String first;
                       private String last;
                       public Name(String first, String last) {
                               this.first = first;
                               this.last = last;
                       }
               }
               SELECT new myPackage.Name(c.firstName, c.lastName) FROM Customer
c
                        Efeito: Retorna uma List de objetos "Name" preenchidos
como indicado no construtor
        . Clausula IN / INNER JOIN / JOIN / LEFT JOIN / XXX JOIN FETCH /
DISTINCT
                SELECT r FROM Customer AS c, IN( c.reservations ) r
                        Efeito: Retorna todas reservas de todos clientes
                        Obs.: É idêndico a:
                                =       SELECT r FROM Customer AS c, INNER JOIN
c.reservations r
                                =       SELECT r FROM Customer AS c, JOIN
c.reservations r
                SELECT c.firstName, c.lastName, p.number FROM Customer c INNER
JOIN c.phoneNumbers p
                        Como no SQL, INNER JOIN irá retornar apenas campos onde
existe associação não nula,
                        ou seja, irá retornar apenas clientes que possuem
telefones associados
                SELECT c.firstName, c.lastName, p.number FROM Customer c LEFT
JOIN c.phoneNumbers p
                        Como no SQL, LEFT JOIN irá retornar também campos onde
existe associação nula,
                        ou seja, irá retornar todos clientes e, caso não possua
telefone associado, retornará null
                        no objeto associativo

                SELECT c FROM Customer c LEFT JOIN FETCH c.phones
                        Adicionando FETCH após o JOIN indica que se o
relacionamento for LAZY, deverá carregar mesmo assim
                        Evita o problema N+1, onde se executassemos getPhones()
seriam feito N selects, desta forma é feito
                        apenas um select.
               SELECT DISTINCT cust FROM Reservation AS res, IN (res.customers)
cust
                       Não retorna instancias duplicadas no resultado

       . Clausula WHERE / BETWEEN / IN / LIKE / IS NULL / IS EMPTY / MEMBER OF
                SELECT c FROM Customer AS c WHERE
c.creditCard.creditCompany.name = 'Capital One'
                SELECT s FROM Ship AS s WHERE s.tonnage = 100000.00
                SELECT c FROM Customer AS c WHERE c.hasGoodCredit = TRUE
                SELECT r FROM Reservation AS r WHERE (r.amountPaid * .01) >
300.00
                SELECT r FROM Reservation r, IN ( r.customers ) AS cust WHERE
cust = :specificCustomer

               SELECT s FROM Ship AS s WHERE s.tonnage BETWEEN 80000.00 AND
130000.00
                SELECT c FROM Customer AS c WHERE c.address.state IN ('FL',
'TX', 'MI', 'WI', 'MN')
                SELECT c FROM Customer AS c WHERE c.address.state NOT IN ('FL',
                                    Página 24
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
'TX', 'MI', 'WI', 'MN')
                SELECT c FROM Customer AS c WHERE c.address.state IN ( ?1, ?2,
?3, 'WI', 'MN')
                    SELECT c FROM Customer AS c WHERE c.address IS NULL
                    SELECT c FROM Customer AS c WHERE c.address IS NOT NULL
                    SELECT crs FROM Cruise AS crs WHERE crs.reservations IS EMPTY
                    SELECT crs FROM Cruise AS crs WHERE crs.reservations IS NOT
EMPTY
                    Obs.: Não pode utilizar IS EMPTY em um campo especificado no
JOIN
                           ERRO: SELECT r FROM Reservation AS r INNER JOIN
r.customers AS c
                                           WHERE r.customers IS NOT EMPTY AND
c.address.city = 'Boston'
                    Obs.: Na clausula like, % indica N caracteres e _ indica um
caractere
                    SELECT OBJECT( c ) FROM Customer AS c WHERE c.lastName LIKE
'%-%'
                    SELECT OBJECT( c ) FROM Customer AS c WHERE c.lastName LIKE
'Joan_'
                Obs.: Clausula MEMBER OF é como se fosse o IN para tipos de
coleção (contains)
                SELECT crs FROM Cruise AS crs, IN (crs.reservations) AS res,
Customer AS cust
                        WHERE cust = :myCustomer AND cust MEMBER OF
res.customers
          . Clausulas Funcionais
                    LOWER(String)
                    UPPER(String)
                    TRIM([[LEADING | TRAILING | BOTH] [trim_char] FROM] String)
                    CONCAT(String1, String2)
                    LENGTH(String)
                    LOCATE(String1, String2 [, start])
                    SUBSTRING(String1, start, length)

                    ABS(number)
                    SQRT(double)
                    MOD(int, int)
                    CURRENT_DATE
                    CURRENT_TIME
                    CURRENT_TIMESTAMP

          . Clausulas Agregadoras
                    Obs.: se COUNT avalia uma coleção vazia, ele retorna zero
                    SELECT COUNT( c ) FROM Customers AS c WHERE c.address.state =
'WI'
                SELECT COUNT(c.address.zip) FROM Customers AS c WHERE
c.address.zip LIKE '554%'
                Obs.: MAX e MIN comparam qualquer tipo de dado (utiliza valor ou
tamanho em bytes)
                SELECT MAX( r.amountPaid ) FROM Reservation AS r
                SELECT MAX( r.amountPaid ) FROM Reservation AS r
                    Obs.: SUM e AVG servem apenas para numericos e wrappers
                    SELECT SUM(r.amountPaid) FROM Cruise c join c.reservations r
WHERE     c = :cr
                Obs.: quando utilizado com agregação, o DISTINCT é aplicado
antes de agregar os dados
                                    Página 25
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                SELECT DISTINCT COUNT(c.address.zip) FROM Customers AS c WHERE
c.address.zip LIKE '554%'
                        Efeito: conta apenas os registros com zip diferentes
                SELECT   c FROM Customers AS   c ORDER BY c.lastName
                SELECT   c FROM Customers AS   c WHERE c.address.city = 'Boston' AND
c.address.state = 'MA'   ORDER BY c.lastName
                SELECT   c FROM Customers AS   c ORDER BY c.lastName DESC
                SELECT   c FROM Customers AS   c ORDER BY c.lastName ASC,
c.firstName DESC
                Cuidado:
                        SELECT addr.zip FROM Address AS addr ORDER BY addr.zip
                        SELECT c.address FOR Customer AS c WHERE c.lastName =
'Smith' ORDER BY c.address.zip
                          ERRO: SELECT c FROM Customer AS c ORDER BY
c.address.city
                                 Se a query retorna uma coleção, no campo order
by podem ser utilizados apenas
                                 campos basicos desta coleção
                          ERRO: SELECT c.address.city FROM Customer AS c ORDER BY
c.address.state
                                 O campo especificado em order by precisa estar
sendo trazido no select

                SELECT cr.name, COUNT (res) FROM Cruise cr JOIN cr.reservations
res GROUP BY cr.name
                        HAVING count(res) > 10
       . Subqueries
                SELECT COUNT(res) FROM Reservation res WHERE res.amountPaid >
(SELECT avg(r.amountPaid) FROM Reservation r)

                FROM Cruise cr WHERE 100000 < ( SELECT SUM(res.amountPaid) FROM
cr.reservations res )

                FROM Cruise cr WHERE 0 < ALL ( SELECT res.amountPaid from
cr.reservations res )
                        Efeito: Seleciona cruzeiros em que todas suas reservas
possuam valor de pagamento

                FROM Cruise cr WHERE 0 = ANY ( SELECT res.amountPaid from
cr.reservations res )
                        Efeito: Seleciona cruzeiros em que exista ao menos uma
reserva com valor zerado

                  Obs.: SOME = ANY = NOT ALL
                FROM Cruise cr WHERE EXISTS (SELECT res FROM cr.reservations
WHERE res.amountPaid = 0)
                        Obs.: Clausula EXISTS verifica se a subquery retornou
algum registro
                        Efeito: Seleciona os cruseiros que tenham alguma reserva
sem pagamento
       . UPDATE e DELETE em lote
                  UPDATE Reservation res SET res.amountPaid = (res.amountPaid +
10)
                WHERE EXISTS ( SELECT c FROM res.customers c WHERE c.firstName =
'Bill' AND c.lastName='Burke' )
                DELETE FROM Reservation res WHERE EXISTS ( SELECT c FROM
res.customers c WHERE c.firstName = 'Bill'
                AND c.lastName='Burke' )
                                    Página 26
Resumo_Anotacoes_Certificacao_SCBCD_5.txt

- Scalar Native Queries
          Query createNativeQuery(String sql)
          . Usada para valores escalares, retorna um List de Object[] contendo os
valores
- Simple Entity Native Queries
          Query createNativeQuery(String sql, Class entityClass)

        Query query = manager.createNativeQuery("SELECT p.phone_PK,
p.phone_number, p.type
        FROM PHONE AS p", Phone.class);

        . Espera que os nomes dos campos retornados correspondam em nome e tipo
com os atributos persistentes
        da entidade em questão, então a associação é feita automaticamente
        . É obrigatório retornar TODOS os atributos da entidade na query

- Complex Native Queries
          Query createNativeQuery(String sql, String mappingName)
        @Entity
        @SqlResultSetMapping(name="customerAndCreditCardMapping",
      entities={ @EntityResult(entityClass=Customer.class),
                 @EntityResult(entityClass=CreditCard.class,
                                        fields={@FieldResult(name="id",
column="CC_ID"),
                            @FieldResult(name="number", column="number")}
     )})
        public class Customer {...}

        Query query = manager.createNativeQuery( "SELECT c.id, c.firstName,
cc.id As CC_ID, cc.number
                FROM CUST_TABLE c, CREDIT_CARD_TABLE cc WHERE c.credit_card_id =
cc.id",
                "customerAndCreditCardMapping");

          . O mapeamento deve estar definido na entidade
          . Mapeamento via XML:

                <entity-mappings>
                        <sql-result-set-mapping
name="customerAndCreditCardMapping">
                                <entity-result
entity-class="com.titan.domain.Customer"/>
                                <entity-result
entity-class="com.titan.domain.CreditCard"/>
                                        <field-result name="id" column="CC_ID"/>
                                        <field-result name="number"
column="number"/>
                                </entity-result>
                        </sql-result-set-mapping>
                </entity-mappings>
          . Misturando resultado de Entidade e resultado Escalar:
                 @SqlResultSetMapping(name="reservationCount",
                         entities=@EntityResult(name="com.titan.domain.Cruise",
                         fields=@FieldResult(name="id", column="id")),
                         columns=@ColumnResult(name="resCount"))
                 @Entity
                 public class Cruise {...}
--------------------------------------------------------------------------------
                                    Página 27
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
------------------------------------------
- Queryes Nomeadas
        . EJBQL Named Queryes

                @NamedQueries({
                        @NamedQuery(name="getAverageReservation",
                                query="SELECT AVG( r.amountPaid) FROM Cruise As
c, JOIN c.reservations r WHERE c = :cruise"),
                        @NamedQuery(name="findFullyPaidCruises",
                                query="FROM Cruise cr WHERE 0 < ALL (SELECT
res.amountPaid from cr.reservations res)")
                })
                @Entity
                public class Cruise {...}
                Ou Via XML:
                        <entity-mappings>
                                <named-query name="getAverageReservation">
                                        <query>
                                                SELECT AVG( r.amountPaid) FROM
Cruise As c JOIN c.reservations r WHERE c = :cruise
                                        </query>
                                </named-query>
                        </entity-mappings>

        . SQL Native Named Queryes

                @NamedNativeQuery(name="findCustAndCCNum",
                        query="SELECT c.id, c.firstName, c.lastName, cc.number
AS CC_NUM
                                FROM CUST_TABLE c, CREDIT_CARD_TABLE cc
                                WHERE c.credit_card_id = cc.id",
                        resultSetMapping="customerAndCCNumMapping")
                @SqlResultSetMapping(name="customerAndCCNumMapping",
                        entities={@EntityResult(entityClass=Customer.class)},
                        columns={@ColumnResult(name="CC_NUM")}
                )
                @Entity
                public class Customer {...}
                Ou via XML:
                        <entity-mappings>
                                <named-native-query name="findCustAndCCNum"
result-set-mapping="customerAndCCNumMapping">
                                        <query>
                                                SELECT c.id, c.firstName,
c.lastName, cc.number AS CC_NUM FROM CUST_TABLE c,
                                                CREDIT_CARD_TABLE cc WHERE
c.credit_card_id = cc.id
                                        </query>
                                </named-native-query>
                        </entity-mappings>
- Sistema JMS
        . Provedor JMS
                Sistema de rotamento de mensagens
        . Clientes JMS
                Produtor (envia) e consumidor (recebe)
        . Características JMS
                - Assíncrono (cliente não espera resposta)
                - Não é propagada transação do produtor pro receptor
                - Não é propagada segurança nem credenciais do produtor pro
receptor
                - Se o receptor estiver desconectado, o roteador garante a
                                    Página 28
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
entrega da mensagem
                - Ciclo de Vida: idêntico ao do Stateless Bean, também em pool
de instâncias
                (também com @PostConstruct e @PreDestroy)
       @Resource(mappedName="ConnectionFactoryName")
       private ConnectionFactory connectionFactory;
       @Resource(mappedName="TopicName")
       private Topic topic;
        ...
        Connection connect = factory.createConnection( );
        Session session = connect.createSession(true, 0); // 0 ->
Session.AUTO_ACKNOWLEDGE
       MessageProducer producer = session.createProducer(topic);
       TextMessage textMsg = session.createTextMessage( );
       textMsg.setText("my message");
       producer.send(textMsg);
       connect.close( );
        . ConnectionFactory
                Fornece uma factory para criar conexões JMS com um provedor
específico
        . Connection
                Conexão efetica com o provedor JMS
        . Session
                - Sessão para agrupar ações de envio/recebimento de mensagens
                - Método createSession(boolean transacted, int acknowledgeMode)
- muitos provedores utilizam true
                e 0 (Session.AUTO_ACKNOWLEDGE) por padrão, porém não é garantido
                - Obs.: O objeto session não é thread-safe, pode apenas um
objeto session JMS por Thread
        . Topic / Queue
                Nome do channel do Topic ou da Queue.
                        - Topic
                                . Tipo publish/subscribe
                                . Muitos receptores (a mensagem é entregue à
todos que assinam)
                                . Modelo push (o receptor é notificado da
mensagem)
                        - Queue:
                                . Tipo peer-to-peer
                                . Um receptor (a mensagem é entregue apenas uma
vez, ao primeiro que receber)
                                . Conceitualmente é pull (receptor solicita a
mensagem), mas também pode ser push, depende do
                                fornecedor
       . Tipos de Mensagem
               - Sempre compostas por um Header e um Corpo:
                       TextMessage textMsg = session.createTextMessage();
                       MapMessage mapMsg = session.createMapMessage();
                       ObjectMessage objMsg = session.createObjectMessage();
                       (outras...)
               - Exemplo de Header:
                       textMessage.setJMSReplyTo(theAnotherQueue);
       . Cliente JMS Java SE
                ConnectionFactory factory = (ConnectionFactory)
jndiContext.lookup("ConnectionFactoryNameGoesHere");
        Topic topic = (Topic)jndiContext.lookup("TopicNameGoesHere");
        Connection connect = factory.createConnection( );
        Session session = connect.createSession(false,
Session.AUTO_ACKNOWLEDGE);
        MessageConsumer consumer = session.createConsumer(topic);
                                    Página 29
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
        consumer.setMessageListener(this); //ou qualquer instancia que
implemente javax.jms.MessageListener
        connect.start( );

               public void onMessage(Message message) {
                       TextMessage textMsg = (TextMessage)message;
                       String text = textMsg.getText();
               }
- Message Driven Beans

        . Bean especial para consumir mensagens
        . Não se deve utilizar um Session Bean para consumir mensagens (mas é
possível, através dos métodos
        MessageConsumer.receive(), MessageConsumer.receive(long timeout) ou
MessageConsumer.receiveNoWait()
        . Anotação
                @Target(TYPE) @Retention(RUNTIME)
                public @interface MessageDriven {
                        String name() default ""; //nome do MDB
                        Class messageListenerInterface default Object.class;
//pode setar como javax.jms.MessageListener e não
                                        //implementar a interface explicitamente
                        ActivationConfigProperty[] activationConfig() default
{}; //configurações específicas de MDB
                        String mappedName(); //se preferir pode especificar o
destino aqui
                        String description();
                }
        . MessageDrivenContext
                - Extende o EJBContext, é semelhante ao SessionContext porém não
adiciona nenhuma operação
                - Pode-se utilizar apenas os métodos transacionais. Os métodos
de segurança lançam uma
                RuntimeException, pois na JMS não há propagação de segurança

        . Interface javax.jms.MessageListener
                Único método: public void onMessage(Message message)
        @MessageDriven(
                activationConfig={
                        @ActivationConfigProperty(
                                propertyName="destinationType",
                                propertyValue="javax.jms.Queue"),
                        @ActivationConfigProperty(
                                propertyName="destinationName",
                                propertyValue="jms/TitanQueue"),
                        @ActivationConfigProperty(
                                propertyName="messageSelector",
                                propertyValue="MessageFormat = 'Version 3.4'"),
                        @ActivationConfigProperty(
                                propertyName="acknowledgeMode",
                                propertyValue="Auto-acknowledge")
        })
        public class ReservationProcessorBean implements
javax.jms.MessageListener {
               @Resource(mappedName="ConnectionFactory")
               private ConnectionFactory connectionFactory;

               public void onMessage(Message message) {
                       try {
                               MapMessage reservationMsg = (MapMessage)message;

                                   Página 30
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                                int customerPk =
reservationMsg.getInt("CustomerID");
                                int cruisePk =
reservationMsg.getInt("CruiseID");
                                int cabinPk = reservationMsg.getInt("CabinID");

                                double price =
reservationMsg.getDouble("Price");
                        } catch(Exception e) { throw new EJBException(e); }
                }
        }

        . Atributos ActivationConfigProperty
                - messageSelector
                        Pode utilizar uma query sintaxe SQL para filtrar quais
mensagens o bean vai consumir de acordo com
                        propriedades setadas na mensagem
                - acknowledgeMode
                        AUTO_ACKNOWLEDGE - é computado recebimento logo após a
mensagem ser entregue e processada
                        DUPS_OK_ACKNOWLEDGE - é computado o recebimento em lote,
de forma otimizada (o MDB precisa ter
                        preparo para tratar mensagens duplicatas)
                - subscriptionDurability
                        Durable - tolerantes à desconexão do container, a
mensagem é armazenada e entregue depois
                        NonDurable - o contrário, qualquer mensagem recebida
enquanto desconectado será perdida

       . Descritor XML
       <enterprise-beans>
               <message-driven>
                       <ejb-name>ReservationProcessorBean</ejb-name>

<ejb-class>com.titan.reservationprocessor.ReservationProcessorBean</ejb-class>
<messaging-type>javax.jms.MessageListener</messaging-type>
                        <transaction-type>Container</transaction-type>

<message-destination-type>javax.jms.Queue</message-destination-type>
                        <activation-config>
                                <activation-property>

<activation-config-property-name>destinationType</activation-config-property-nam
e>
<activation-config-property-value>javax.jms.Queue</activation-config-property-va
lue>
                                <activation-property>
                                <activation-property>

<activation-config-property-name>destinationName</activation-config-property-nam
e>
<activation-config-property-value>jms/TitanQueue</activation-config-property-val
ue>
                                <activation-property>
                                <activation-property>
<activation-config-property-name>messageSelector</activation-config-property-nam
e>

<activation-config-property-value>MessageFormat = 'Version
3.4'</activation-config-property-value>
                                <activation-property>
                                <activation-property>

                                   Página 31
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
<activation-config-property-name>acknowledgeMode</activation-config-property-nam
e>

<activation-config-property-value>Auto-acknowledge</activation-config-property-v
alue>
                                <activation-property>
                        </activation-config>
       </message-driven>
   </enterprise-beans>
</ejb-jar>

--------------------------------------------------------------------------------
------------------------------------------
- Ouvindo um Timer
        @Stateless
        public class ShipMaintenanceBean implements ShipMaintenanceRemote
implements javax.ejb.TimedObject {
                ...
                public void ejbTimeout(javax.ejb.Timer timer) { ... }
        }
       ou...

       @Stateless
       public class ShipMaintenanceBean implements ShipMaintenanceRemote {
               ...
               @Timeout
               public void myTimeout(javax.ejb.Timer timer) { ... }
       }

- Criando um Timer

        . O próprio bean se registra para ouvir o timer
        . O timer pode ser criado em Stateless e MessageDriven beans
        . CUIDADO: não se deve criar timers em @PostConstruct nem @PreDestroy
(são chamados para cada
        instância do pool), nem utilizando variáveis estáticas para verificar se
já foi criado (problema do cluster)
        . O timer deve ser criado apenas através de métodos de negócio invocados
pelo cliente

        . Um timer service pode ser obtido através do
EJBContext.getTimerService(), ou injetado pelo container:
               @Resource
               TimerService timerService;
       . Interface TimerService

               - public Timer createTimer(Date expiration, Serializable info)
                       . Ação única
                       . Expira na data especificada
               - public Timer createTimer(long duration, Serializable info)
                       . Ação única
                       . Expira depois de passado o tempo especificado em
milisegundos
                - public Timer createTimer(Date initialExpiration, long
intervalDuration, Serializable info)
                        . De intervalo
                        . Expira na data especificada e subsequentemente a cada
intervalo especificado em intervalDuration
               - public Timer createTimer(long initialDuration, long
                                   Página 32
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
intervalDuration, Serializable info)
                        . De intervalo
                        . Expira depois de passado o tempo initialDuration e
subsequentemente a cada intervalo
                        especificado em intervalDuration

                - public Collection getTimers()
                        . Retorna uma coleção contendo todos os timers agendados
para o beans em questão (apenas os timers
                        do bean que chamou o método)

                 Obs.: Todos os métodos TimerService lançam as exceções:
                         . IllegalArgumentException: parâmetros negativos ou null
                         . IllegalStateException: chamado de onde não é permitido
                         . EJBException: encapsula qualquer outra exceção de
sistema
          . Interface Timer
                 - public void cancel()
                         Cancela o timer
                 - public Serializable getInfo()
                         Recupera o objeto passado na criação do timer
                 - public Date getNextTimeout()
                         Recupera a data em que ocorrerá a próxima expiração

                 - public long getTimeRemaining()
                         Recupera o tempo restante para a próxima expiração
                 - public TimerHandle getHandle()
                         Recupera uma referência serializável à instância deste
timer

                Obs.: Todos os métodos Timer lançam as exceções:
                        . NoSuchObjectLocalException: se invocado qualquer
método em um timer de ação única expirado ou um timer
                        cancelado
                        . EJBException: encapsula qualquer outra exceção de
sistema
          . Reagendando temporizadores: precisa cancelar e criar um novo

        . Transação
                - É transacional no escopo da transação atual, ou seja, se
ocorrer rollback em um método que cria o timer,
                sua criação será desfeita
                - É boa prática o método de @Timeout ser transacional
RequiresNew, para assegurar que ele está no escopo
                transacional do container
- Interceptors

          . Criando Classes Interceptadoras
                 public class Profiler {
                         @AroundInvoke
                         public Object profile(InvocationContext invocation)
throws Exception {
                                 long startTime = System.currentTimeMillis( );
                                 try {
                                         return invocation.proceed( );
                                 } finally {
                                         long endTime = System.currentTimeMillis(
) - startTime;
                                         System.out.println("Method " +
                                     Página 33
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
invocation.getMethod( ) + " took " + endTime + " (ms)");
                                }
                        }
                }

        . Interface InvocationContext
                public interface InvocationContext {
                        public Object getTarget( );
                        public Method getMethod( );
                        public Object[] getParameters( );
                        public void setParameters(Object[] newArgs);
                        public java.util.Map<String, Object> getContextData( );
                        public Object proceed( ) throws Exception;
                }
                        . getTarget - retorna uma referência à instância do bean
alvo
                        . getMethod - retorna um objeto java.lang.reflect.Method
do método que foi chamado
                        . getParameters - retorna os parâmetros que foram
enviados ao método
                        . setParameters - modifica tais parâmetros (usar com
cuidado)
                        . getContextData - retorna um objeto Map que fica ativo
durante toda a pilha de chamada, onde podemos
                        compartilhar valores com outros interceptors
                        . proceed - continua a pilha de chamada (próximo
interceptor ou método original)
        . Aplicando Interceptors
                - Nível de Classe (intercepta todos os métodos do bean)

                        @Stateless
                        @Interceptors(Profiler.class)
                        public class MyBean implements MyBeanRemote { ... }

                - Nível de Método (intercepta apenas o método anotado)

                        @Stateless
                        public class MyBean implements MyBeanRemote {

                                @Interceptors(Profiler.class)
                                public void myMethod() { ... }
                        }

                - Aplicando via XML
                        <ejb-jar>
                                <assembly-descriptor>
                                        <interceptor-binding>
<ejb-name>TravelAgentBean</ejb-name>
                                                <!--
<exclude-default-interceptors> e <exclude-class-interceptors> -->
<interceptor-class>com.titan.Profiler</interceptor-class>
<method-name>bookPassage</method-name>
                                                  <method-params>

<method-param>com.titan.CreditCardDO</method-param>
<method-param>double</method-param>
                                                  </method-params>
                                      Página 34
Resumo_Anotacoes_Certificacao_SCBCD_5.txt
                                       </interceptor-binding>
                               </assembly-descriptor>
                       </ejb-jar>
                                  . Obs:
                                           - <method-name> é utilizado apenas para
aplicar a nivel de método
                                           - <method-params> é útil se houver
overload no método especificado
               - Interceptors Padrão

                        . Recebem um curinga (*). São aplicados para todos os
métodos de todos os beans do ejb-jar.
                       <ejb-jar>
                               <assembly-descriptor>
                                       <interceptor-binding>
                                               <ejb-name>*</ejb-name>
<interceptor-class>com.titan.Profiler</interceptor-class>
                                        </interceptor-binding>
                                </assembly-descriptor>
                        </ejb-jar>
               - Desativando Interceptors

                       . @ExcludeDefaultInterceptors
                               Ignora os interceptors-padrão da implantação

                       . @ExcludeClassInterceptors
                               Ignora os interceptors de nivel de classe do
bean

--------------------------------------------------------------------------------
------------------------------------------
- Interceptors e Injeção de Dependência (ENC)

        . O interceptor compartilha o mesmo JNDI ENC do bean que está
interceptando
        . O EJBContext também é compartilhado
       . Injeção no Interceptor
               - Via Annotations
                       public class AuditInterceptor {
                               @Resource
                               EJBContext ctx;
                                  @PersistenceContext(unitName="auditdb")
                                  EntityManager manager;
                                @AroundInvoke
                                public Object audit(InvocationContext
invocation) throws Exception { ... }
                        }
               - Via XML
                       <ejb-jar>
                               <interceptors>
                                       <interceptor>
<interceptor-class>com.titan.interceptors.AuditInterceptor</interceptor-class>
                                                <around-invoke>

                                     Página 35
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB
Resumo Anotações Certificação EJB

Mais conteúdo relacionado

Mais procurados

Introdução ao Desenvolvimento de aplicações WEB com JSP
Introdução ao Desenvolvimento de aplicações WEB com JSPIntrodução ao Desenvolvimento de aplicações WEB com JSP
Introdução ao Desenvolvimento de aplicações WEB com JSPManoel Afonso
 
Cactus - Testes em J2EE com Jakarta Cactus
Cactus - Testes em J2EE com Jakarta CactusCactus - Testes em J2EE com Jakarta Cactus
Cactus - Testes em J2EE com Jakarta CactusDenis L Presciliano
 
Sistemas Distribuídos - Comunicação Distribuída - EJB
Sistemas Distribuídos - Comunicação Distribuída - EJBSistemas Distribuídos - Comunicação Distribuída - EJB
Sistemas Distribuídos - Comunicação Distribuída - EJBAdriano Teixeira de Souza
 
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)Helder da Rocha
 
Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5Gilberto Holms
 
PDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NETPDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NETslides_teltools
 
Java Web 3 - Servlets e JSP 1
Java Web 3 - Servlets e JSP 1Java Web 3 - Servlets e JSP 1
Java Web 3 - Servlets e JSP 1Eduardo Mendes
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - BrazilStephen Chin
 
Minicurso de Segurança em Java EE 7
Minicurso de Segurança em Java EE 7Minicurso de Segurança em Java EE 7
Minicurso de Segurança em Java EE 7Helder da Rocha
 
Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0
Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0
Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0Elvis Rocha
 
Build Automation Evolved
Build Automation EvolvedBuild Automation Evolved
Build Automation EvolvedMarcelo Diniz
 
Java Web 5 - JSP, Expression Language e Taglibs
Java Web 5 - JSP, Expression Language e TaglibsJava Web 5 - JSP, Expression Language e Taglibs
Java Web 5 - JSP, Expression Language e TaglibsEduardo Mendes
 
XML Free Programming - Brazil
XML Free Programming - BrazilXML Free Programming - Brazil
XML Free Programming - BrazilStephen Chin
 
Java Web 4 - Servlets e JSP 2
Java Web 4 - Servlets e JSP 2Java Web 4 - Servlets e JSP 2
Java Web 4 - Servlets e JSP 2Eduardo Mendes
 

Mais procurados (20)

Curso de JSP
Curso de JSPCurso de JSP
Curso de JSP
 
Introdução ao Desenvolvimento de aplicações WEB com JSP
Introdução ao Desenvolvimento de aplicações WEB com JSPIntrodução ao Desenvolvimento de aplicações WEB com JSP
Introdução ao Desenvolvimento de aplicações WEB com JSP
 
Cactus - Testes em J2EE com Jakarta Cactus
Cactus - Testes em J2EE com Jakarta CactusCactus - Testes em J2EE com Jakarta Cactus
Cactus - Testes em J2EE com Jakarta Cactus
 
J530 5 stateless
J530 5 statelessJ530 5 stateless
J530 5 stateless
 
Sistemas Distribuídos - Comunicação Distribuída - EJB
Sistemas Distribuídos - Comunicação Distribuída - EJBSistemas Distribuídos - Comunicação Distribuída - EJB
Sistemas Distribuídos - Comunicação Distribuída - EJB
 
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
 
Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5
 
PDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NETPDC - Engenharia - Plataforma Microsoft .NET
PDC - Engenharia - Plataforma Microsoft .NET
 
Java Web 3 - Servlets e JSP 1
Java Web 3 - Servlets e JSP 1Java Web 3 - Servlets e JSP 1
Java Web 3 - Servlets e JSP 1
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil
 
Minicurso de Segurança em Java EE 7
Minicurso de Segurança em Java EE 7Minicurso de Segurança em Java EE 7
Minicurso de Segurança em Java EE 7
 
Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0
Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0
Java EE 6 JPA 2.0, EJB 3.1 e CDI 1.0
 
Java Server Pages
Java Server PagesJava Server Pages
Java Server Pages
 
Build Automation Evolved
Build Automation EvolvedBuild Automation Evolved
Build Automation Evolved
 
Java Web 5 - JSP, Expression Language e Taglibs
Java Web 5 - JSP, Expression Language e TaglibsJava Web 5 - JSP, Expression Language e Taglibs
Java Web 5 - JSP, Expression Language e Taglibs
 
servlet-introducao
servlet-introducaoservlet-introducao
servlet-introducao
 
JSP com tags padrão
JSP com tags padrãoJSP com tags padrão
JSP com tags padrão
 
Cactus xp
Cactus xpCactus xp
Cactus xp
 
XML Free Programming - Brazil
XML Free Programming - BrazilXML Free Programming - Brazil
XML Free Programming - Brazil
 
Java Web 4 - Servlets e JSP 2
Java Web 4 - Servlets e JSP 2Java Web 4 - Servlets e JSP 2
Java Web 4 - Servlets e JSP 2
 

Destaque

Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5Gilberto Holms
 
BalanceLine4j Framework Overview
BalanceLine4j Framework OverviewBalanceLine4j Framework Overview
BalanceLine4j Framework OverviewGilberto Holms
 
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBossApostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBossGilberto Holms
 
FFPOJO Framework Overview
FFPOJO Framework OverviewFFPOJO Framework Overview
FFPOJO Framework OverviewGilberto Holms
 
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5Gilberto Holms
 
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g DeveloperResumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g DeveloperGilberto Holms
 

Destaque (6)

Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5
 
BalanceLine4j Framework Overview
BalanceLine4j Framework OverviewBalanceLine4j Framework Overview
BalanceLine4j Framework Overview
 
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBossApostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
 
FFPOJO Framework Overview
FFPOJO Framework OverviewFFPOJO Framework Overview
FFPOJO Framework Overview
 
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
 
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g DeveloperResumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
 

Semelhante a Resumo Anotações Certificação EJB

Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)Adriano Teixeira de Souza
 
Repensando padrões e boas práticas java ee
Repensando padrões e boas práticas java eeRepensando padrões e boas práticas java ee
Repensando padrões e boas práticas java eeAdriano Tavares
 
Spring + Tapestry Um novo paradigma de desenvolvimento web
Spring + Tapestry Um novo paradigma de desenvolvimento webSpring + Tapestry Um novo paradigma de desenvolvimento web
Spring + Tapestry Um novo paradigma de desenvolvimento webelliando dias
 
Minicurso Java Server Faces
Minicurso Java Server FacesMinicurso Java Server Faces
Minicurso Java Server FacesJoão Longo
 
Apresentação jsf 2.0
Apresentação jsf 2.0Apresentação jsf 2.0
Apresentação jsf 2.0Paulo Neto
 
Produtividade com JavaServer Faces
Produtividade com JavaServer FacesProdutividade com JavaServer Faces
Produtividade com JavaServer FacesEduardo Bregaida
 
Apache Wicket - Desenvolvimento WEB orientado a componentes
Apache Wicket - Desenvolvimento WEB orientado a componentesApache Wicket - Desenvolvimento WEB orientado a componentes
Apache Wicket - Desenvolvimento WEB orientado a componentesCI&T
 
UOL Tech Day: Testes de Integração com OpenEJB
UOL Tech Day: Testes de Integração com OpenEJBUOL Tech Day: Testes de Integração com OpenEJB
UOL Tech Day: Testes de Integração com OpenEJBGabriel Ozeas
 
Rapid Application Development com Tapestry 5
Rapid Application Development com Tapestry 5Rapid Application Development com Tapestry 5
Rapid Application Development com Tapestry 5Marcelo Rodrigues
 
TechDay - Sistemas WEB em Java - Rogério N. Jr.
TechDay - Sistemas WEB em Java - Rogério N. Jr.TechDay - Sistemas WEB em Java - Rogério N. Jr.
TechDay - Sistemas WEB em Java - Rogério N. Jr.Rogério Napoleão Jr.
 
ApresentaçãO Ejb (Enterprise Java Beans)
ApresentaçãO Ejb (Enterprise Java Beans)ApresentaçãO Ejb (Enterprise Java Beans)
ApresentaçãO Ejb (Enterprise Java Beans)mauriciopel
 

Semelhante a Resumo Anotações Certificação EJB (20)

Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
 
GUJavaSC - Mini-curso Java EE
GUJavaSC - Mini-curso Java EEGUJavaSC - Mini-curso Java EE
GUJavaSC - Mini-curso Java EE
 
Repensando padrões e boas práticas java ee
Repensando padrões e boas práticas java eeRepensando padrões e boas práticas java ee
Repensando padrões e boas práticas java ee
 
Spring + Tapestry Um novo paradigma de desenvolvimento web
Spring + Tapestry Um novo paradigma de desenvolvimento webSpring + Tapestry Um novo paradigma de desenvolvimento web
Spring + Tapestry Um novo paradigma de desenvolvimento web
 
Cdi conceitos
Cdi conceitosCdi conceitos
Cdi conceitos
 
EJB
EJBEJB
EJB
 
J2EE e Datasources
J2EE e DatasourcesJ2EE e Datasources
J2EE e Datasources
 
Minicurso Java Server Faces
Minicurso Java Server FacesMinicurso Java Server Faces
Minicurso Java Server Faces
 
JAVABEANS.pdf
JAVABEANS.pdfJAVABEANS.pdf
JAVABEANS.pdf
 
Apresentação jsf 2.0
Apresentação jsf 2.0Apresentação jsf 2.0
Apresentação jsf 2.0
 
Produtividade com JavaServer Faces
Produtividade com JavaServer FacesProdutividade com JavaServer Faces
Produtividade com JavaServer Faces
 
Apache Wicket - Desenvolvimento WEB orientado a componentes
Apache Wicket - Desenvolvimento WEB orientado a componentesApache Wicket - Desenvolvimento WEB orientado a componentes
Apache Wicket - Desenvolvimento WEB orientado a componentes
 
UOL Tech Day: Testes de Integração com OpenEJB
UOL Tech Day: Testes de Integração com OpenEJBUOL Tech Day: Testes de Integração com OpenEJB
UOL Tech Day: Testes de Integração com OpenEJB
 
J2EE Na Vida Real
J2EE Na Vida RealJ2EE Na Vida Real
J2EE Na Vida Real
 
Hibernate conceitos
Hibernate conceitosHibernate conceitos
Hibernate conceitos
 
Rapid Application Development com Tapestry 5
Rapid Application Development com Tapestry 5Rapid Application Development com Tapestry 5
Rapid Application Development com Tapestry 5
 
TechDay - Sistemas WEB em Java - Rogério N. Jr.
TechDay - Sistemas WEB em Java - Rogério N. Jr.TechDay - Sistemas WEB em Java - Rogério N. Jr.
TechDay - Sistemas WEB em Java - Rogério N. Jr.
 
Serra StarTec 2013 - Java EE
Serra StarTec 2013 - Java EESerra StarTec 2013 - Java EE
Serra StarTec 2013 - Java EE
 
ApresentaçãO Ejb (Enterprise Java Beans)
ApresentaçãO Ejb (Enterprise Java Beans)ApresentaçãO Ejb (Enterprise Java Beans)
ApresentaçãO Ejb (Enterprise Java Beans)
 
JSF & REST
JSF & RESTJSF & REST
JSF & REST
 

Resumo Anotações Certificação EJB

  • 1. Resumo_Anotacoes_Certificacao_SCBCD_5.txt =============================================================================== Resumo Anotações para Certificação SCBCD 5.0 Autor: Gilberto Augusto Holms @gibaholms gibaholms85@gmail.com http://gibaholms.wordpress.com/ =============================================================================== - Introdução . EJB: Modelo de componentes padrão do lado do servidor para aplicativos de negócio distribuídos - Escalonáveis - Transacionais - Seguros com multi-usuários . Bean de Entidade (JPA): - A JPA pode funcionar sozinha, porém o container EJB3 fornece integração adicional. - É um POJO, e não um componente (como era no 2.1). - Obrigatório uma chave primária ( @Id ), que pode ser um primitivo ou uma classe. - As anotations podem estar tanto nos atributos quanto nos métodos GETTER. . Persistence.xml - É obrigatório - Sobrescreve as annotations - Deployado num JAR junto com as entidades - Pode declarar várias Persistence Units - Persistence Unit -> composta por Entidades, representa uma base de dados . Interfaces de Negocio -> obrigatório ao menos uma interface de negócio - javax.ejb.Local (não utiliza protocolos distribuídos para acessar – apenas mesma JVM) - javax.ejb.Remote - javax.jms.MessageListener - javax.jws.WebService . Container EJB, seis serviços primários: - Concorrência - Transação - Persistência - Distribuição de Objetos - Atribuição de Nomes (JNDI) - Segurança - Mensageria Assíncrona - Temporização . Serviços que melhoram o desempenho para grande número de clientes e beans instanciados: - Pool de instâncias (Beans Stateless e MDB): . Clientes nunca acessam um bean diretamente, portanto o container pode criar um pool de instancias e gerenciá-lo reaproveitando recursos. Uma mesma instância serve vários clientes (um de cada vez). - Ativação (Beans Statefull) . As variáveis de instância do bean são persistidas em um armazenamento secundário, e o bean é removido da memória (apassivação). Quando é invocado outro método, uma nova instância é criada e seu estado anterior é recuperado do armazenamento (ativação). Porém, o Stub não perde a conexão durante a apassivação. Página 1
  • 2. Resumo_Anotacoes_Certificacao_SCBCD_5.txt . O objeto não precisa ser serializável, o fornecedor escolhe um método de ativação que independa disso. Para atributos transientes, o comportamento depende da implementação do container. . É fornecido o callback @PrePassivate e @PostActivate. Serviços de contexto e o EntityManager devem ser mantidos durante o processo de apassivação. . Java EE Connectors (JCA) . Fornece mecanismo para criação de interfaces entre o container e sistemas legados, permitindo que os legados disparem mensagens para MDBs do conteiner. . Concorrência: . Beans se sessão não executam em multithread, portanto é proibido utilizar a palavra synchronized e também é proibido criar threads dentro de beans, pois o container precisa ter certeza que está com o controle sobre o comportamento de todas as instancias do bean. . Beans de entidade podem ser acessados de forma concorrente, o container pode utilizar Optimistic Locking ou isolamento Serialized no JDBC. . Beans de mensagem podem processar mensagens simultaneamente, onde cada instancia do pool pode processar uma mensagem. - Session Beans . Interface Remota - Todos os parametros são copiados, inclusive os objetos, mesmo se estiver na mesma JVM (chamada "por valor") @Remote public interface MyBusinessInterfaceRemote { ... } . Interface Local - Precisa estar na mesma JVM - Os parametros possuem comportamento normal, onde objetos são passados por referência (chamada "por referência) @Local public interface MyBusinessInterfaceLocal { ... } . Obs.: - Parametros de tipo objeto precisam extender Serializable ou Externalizable para poderem ser transferidos pela rede - Podem lançar exceções. Deve-se lançar apenas exceções de negócio, e não de subsistemas Java - Uma exceção de aplicativo é propagada ao cliente, e qualquer variável de instância dela deve ser serializavel - Todas exceções de runtime são capturadas pelo container e empacotadas em EJBException - Pode declarar @Local(MyBusinessInterfaceLocal.class) no próprio bean, não precisando ele declarar a implementação da interface explicitamente e nem precisando anotar a interface. Idem para @Remote . Descritor de Implantação - Fica dentro do JAR do projeto EJB, em: META-INF/ejb-jar.xml . Exemplo de EJB via XML <ejb-jar> <enterprise-beans> Página 2
  • 3. Resumo_Anotacoes_Certificacao_SCBCD_5.txt <session> <ejb-name>ProcessPaymentBean</ejb-name> <remote>com.titan.processpayment.ProcessPaymentRemote</remote> <local>com.titan.processpayment.ProcessPaymentLocal</local> <ejb-class>com.titan.processpayment.ProcessPaymentBean</ejb-class> <session-type>Stateless</session-type> </session> </enterprise-beans> </ejb-jar> - SessionContext public interface javax.ejb.SessionContext extends javax.ejb.EJBContext { MessageContext getMessageContext( ) throws IllegalStateException; <T> getBusinessObject(Class<T> businessInterface) throws IllegalStateException; Class getInvokedBusinessInterface( ); //METODOS OBSOLETOS - LANÇAM EXCEPTION SE CHAMADOS EJBLocalObject getEJBLocalObject( ) throws IllegalStateException EJBObject getEJBObject( ) throws IllegalStateException; } . getBusinessObject Retorna uma referência (do tipo da interface de parametro) ao objeto EJB atual. É ilegal que um bean envie uma referencia this para outro bean, para isso serve este método . getInvokedBusinessInterface Retorna a classe da interface de negócio invocada para o bean atual . Obs.: - Herda mais todos os métodos de EJBContext - O container injeta o SessionContext via anotação @Resource - EJBContext public interface EJBContext { public Object lookup(String name); // security methods public java.security.Principal getCallerPrincipal( ); public boolean isCallerInRole(java.lang.String roleName); // transaction methods public javax.transaction.UserTransaction getUserTransaction( ) throws java.lang.IllegalStateException; public boolean getRollbackOnly( ) throws java.lang.IllegalStateException; public void setRollbackOnly( ) throws java.lang.IllegalStateException; // OBSOLETO public TimerService getTimerService( ) throws java.lang.IllegalStateException; // METODOS OBSOLETOS - LANÇAM RuntimeException SE CHAMADOS public java.security.Identity getCallerIdentity( ); public boolean isCallerInRole(java.security.Identity role); public java.util.Properties getEnvironment( ); Página 3
  • 4. Resumo_Anotacoes_Certificacao_SCBCD_5.txt public EJBHome getEJBHome( ) java.lang.IllegalStateException; public EJBLocalHome getEJBLocalHome( ) java.lang.IllegalStateException; public Properties getEnvironment(); } . getCallerPrincipal Retorna o objeto Principal referente a quem está acessando o bean . isCallerInRole Retorna se o usuário atual pertence a determinada role . lookup Permite pesquisar entradas no ENC do EJB. -------------------------------------------------------------------------------- ------------------------------------------ - Stateless Session Beans @Stateless public class MyBean implements MyBusinessInterface {...} . Ciclo de Vida (TODO) . Precisa de um construtor padrão . Métodos de ciclo de vida: @PostConstruct Após o conteiner instanciar o bean (não significa sair do pool) @PreDestroy Antes do container destruir o bean (não significa voltar pro pool). Durante a chamada, ainda estão disponíveis SessionContext e JNDI ENC . Obter a referência remota não indica que o bean saiu do pool. O bean sai do pool e é configurado para o cliente apenas depois que o cliente invoca o primeiro método do bean -------------------------------------------------------------------------------- ------------------------------------------ - Statefull Sessson Beans @Statefull public class MyBean implements MyBusinessInterface {...} . Ciclo de Vida (TODO) . Precisa de um construtor padrão . Métodos de ciclo de vida: @PostConstruct Após o conteiner instanciar o bean @PreDestroy Antes do container destruir o bean. Durante a chamada, ainda estão disponíveis SessionContext e JNDI ENC @PrePassivate Antes do bean ser apassivado (serializado para armazenamento de estado). Deve liberar recursos e setar campos transient com valores nulos. Objetos que são passivados e gerenciados automaticamente: - Tipos primitivos Página 4
  • 5. Resumo_Anotacoes_Certificacao_SCBCD_5.txt - Qualquer objeto java serializavel - SessionContext - UserTransaction - javax.naming.Context - EntityManager - EntityManagerFactory - Fabricas injetadas por @Resource - Referencias injetadas por @EJB @PostActivate Depois do bean ser ativado (desserializado para recuperação de estado). Foge à regra da desserialização java no que se trata de variáveis transient, cujo valor assumido será aleatório, e não o valor padrão, portanto este método deve reabrir os recursos e setar essas variáveis . O beans Statefull é removido da memória quando: - É chamado o método @Remove - O container detecta que deu timeout e o bean expirou (não pode expirar durante uma transação) - @PreDestroy é chamado apenas no caso do @Remove. Em caso de expiração, depende do fornecedor a chamada desse método ou não . Apenas obter a referência remota já cria uma sessão dedicada ao cliente, porém não cria a instância. A instância é criada depois de chamar o primeiro método do bean . No caso de beans Statefull aninhados, a sessão do filho pertence ao pai, ou seja, se o cliente remove o pai, o pai remove o filho automaticamente . Contexto de Persistencia Extendido: - Pode apenas em bean Statefull - Faz com que todas as Entidades mantenham-se gerenciadas durante diferentes invocações de métodos - Se ele contiver outro bean Statefull aninhado, e esse bean: tiver interface local e também tiver contexto extendido, os dois beans compartilham o mesmo contexto de persistencia extendido (mesmo EntityManager) - Entity Manager @Stateless public class MyBean implements MyBusinessInterface { @PersistenceContext(unitName="titan", type=PersistenceContextType.TRANSACTION) private EntityManager manager; ... } . Atributo type é opcional, o padrão vem TRANSACTION, mas podemos optar por EXTENDED. Se for TRANSACTION, diferentes instancias de EntityManager injetadas em beans diferentes estarão no mesmo contexto de persistência, até que a transação geral termine O tipo EXTENDED pode ser utilizado apenas em beans @Statefull, e esse contexto dura o mesmo tempo de vida da instancia do bean (as transações em particular precisam ser demarcadas). . Contexto de Persistência Tempo em que as entidade são gerenciadas pelo EntityManager. Quando o contexto de persistencia acaba, todas as entidades tornam-se detached. Página 5
  • 6. Resumo_Anotacoes_Certificacao_SCBCD_5.txt . Escopo de Transação PersistenceContextType.TRANSACTION O contexto de persistência dura exatamente o tempo de uma transação JTA, pode apenas ser utilizado em servidores J2EE, com entidades injetadas via @PersistenceContext PersistenceContextType.EXTENDED O contexto de persistência permanece ativo durante várias transações, pode ser utilizado apenas em beans Statefull . Arquivo persistence.xml É obrigatório: <persistence> <persistence-unit name="titan"> <jta-data-source>java:/OracleDS</jta-data-source> <properties> <propertie name="org.hibernate.hbm2ddl">update</propertie> </properties> </persistence-unit> </persistence> Obs.: <persistence-unit> atributo name – obrigatório atributo transaction-type – opcional (conf. JTA para servers J2EE ou RESOURCE_LOCAL para Java SE) outras tags opcionais: <description> <provider> : provedor de persistência (para J2EE vem o default do container) <non-jta-data-source> <mapping-file> : outro arquivo de mapeamento (container procura orm.xml e outros listados aqui) <jar-file> : carregar outro jar de entidades <class> : carregar classes específicas <exclude-unlisted-classes> : não carregar qualquer classe que não esteja declarada no persistence.xml (o jar default é ignorado) . Empacotamento Sempre um arquivo jar com persistence.xml dentro de seu META-INF (se houver, o arquivo orm.xml também deve estar nessa pasta) . Classpath Java SE <JAR AQUI> . EJB-JAR . WAR > WEB-INF > lib <JAR AQUI> . EAR <JAR AQUI> . EAR > lib <JAR AQUI> -------------------------------------------------------------------------------- ------------------------------------------ - Entity Manager Factory @Stateless public class FactoryBean implements FactoryBusinessInterface { @PersistenceUnit(unitName=”titan”) private EntityManagerFactory factory1; private EntityManagerFactory factory2; Página 6
  • 7. Resumo_Anotacoes_Certificacao_SCBCD_5.txt @PersistenceUnit(unitName=”toto”) public void setFactory2(EntityManagerFactory factory2) {...} } . Não pode chamar método close() no EntityManagerFactory nem no EntityManager se eles forem injetados pelo container (lança IllegalStateException), pois o container cuida dessa limpeza. . O container injeta em um atributo ou em um setter . Se criar o EntityManager utilizando o factory, as transações serão de escopo extendido, ou seja, é preciso chamar EntityManager.joinTransaction() -------------------------------------------------------------------------------- ------------------------------------------ - Métodos de EntityManager persist(Object entity) .Enfileira a entidade para criação no banco (não representa o momento real do insert) . É possível chamar persist fora de uma transação apenas se o contexto for EXTENDED, nesse caso, a inserção é enfileirada até o contexto ser associado com uma transação . Se o parâmetro não for uma entidade, lança IllegalArgumentException . Se for invocado fora do contexto de transação e for tipo TRANSACTION, lança uma TransactionRequiredException joinTransaction() . Usado apenas se o contexto for criado pela EntityManagerFactory . Associa o contexto de persistência à transação . Obs.: se o contexto for gerenciado pelo container, ele é associado automaticamente (não precisa desse método) find(Class<T> entityClass, Object pk) : Entidade getReference(Class<T> entityClass, Object pk) : Entidade . Retornam uma entidade a partir de sua chave primária . O find, se não encontrar retorna null, e utiliza as configurações de lazy-loading . O getReference, se não encontrar lança EntityNotFoundException . Se o contexto de persistência estiver ativo, ela é acoplada, senão ela é desacoplada createQuery e createXXXQuery . Executam querys EJB-QL e consultas nativas (retornam um objeto Query) . Entidades retornadas permanegem gerenciadas enquanto o contexto de persistência estiver ativo flush() . Sincroniza as atualizações no banco antes de terminar a transacao merge(Object entity) : Entidade . Atualiza uma entidade desacoplada e retorna uma cópia dela acoplada . ATENÇÃO: o objeto de parâmetro nunca é gerenciado pelo EntityManager, e sim sua cópia que retorna. Se ele já estiver gerenciado a mesma instancia, ele atualiza ela e retorna sua referencia. remove(Object entity) Remove a entidade da base e torna ela desacoplada refresh(Object entity) . Atualiza a entidade acoplada com os dados da base Página 7
  • 8. Resumo_Anotacoes_Certificacao_SCBCD_5.txt . Se ela não for acoplada ao próprio EntityManager que invoca o método, é lançada IllegalArgumentException . Se o objeto não estiver mais no banco devido outra Thread ou Processo ter removido ele, será lançado EntityNotFoundException contains(Object entity) : Boolean . Retorna true se a entidade estiver acoplada, false caso contrario. clear() . Desacopla todas as entidades atuais gerenciadas pelo EntityManager . Suas modificações são perdidas, portanto é prudente chamar flush() antes. setFlushMode(FlushModeType tp) . Pode receber FlushModeType.AUTO ou FlushModeType.COMMIT . AUTO - é o padrão, onde a implementação da JPA decide quando quer fazer o flush(), onde é certo apenas que ele fará no final da transação, mas também fazer antes . COMMIT - força para que ele sincronize apenas no final da transação. COMMIT Melhora a performance pois cada atualização requer um bloqueio, e fazer todas de uma vez é mais rápido getDelegate() : EntityManagerImpl . Retorna uma instancia ao objeto do fornecedor do implementador EntityManager, que pode proporcionar extensões à JPA padrão -------------------------------------------------------------------------------- ------------------------------------------ - EntityTransaction É a API de transação fornecida como alternativa à JTA. Ela pode ser usada apenas se o atributo transaction-type for RESOURCE_LOCAL. Permite utilizar begin(), commit() e rollback() manualmente. EntityTransaction et = myEntityManager.getTransaction(); et.begin(); myEntityManager.persist(myEntity); et.commit(); . O método begin() lança IllegalStateException se já houver uma transação ativa, commit() e rollback() lançam a mesma exceção se não houver transação ativa. - Criando Entidades @Entity @Table(name="CUSTOMER_TABLE", catalog="TITAN", schema="TITAN", uniqueConstraints=@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"}) ) public class Customer { @Id @GeneratedValue @Column(name="CUST_ID", nullable=false, columnDefinition="integer") private int id; @Column(name="FIRST_NAME", length=20, nullable=false) private String firstName; Página 8
  • 9. Resumo_Anotacoes_Certificacao_SCBCD_5.txt ... } <entity-mappings> <entity class="com.titan.domain.Customer" access="PROPERTY"> <!-- PROPERTY e FIELD não se misturam --> <table name="CUSTOMER_TABLE"> <unique-constraint> <column-name>SOME_OTHER_ATTRIBUTE</column_name> </unique-constraint> </table> <attributes> <id name="id"> <column name="CUST_ID" nullable="false" column-definition="integer"/> <generated-value strategy="AUTO"/> </id> <basic name="firstName"> <column name="FIRST_NAME" nullable="false" length="20"/> </basic> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ - Tipos de geradores de PK @GeneratedValue ou @GeneratedValue(strategy=GeneratorType.AUTO) <attributes> <id name="id"> <generated-value strategy="AUTO"/> </id> </attributes> @TableGenerator(name="CUST_GENERATOR" table="GENERATOR_TABLE" pkColumnName="PRIMARY_KEY_COLUMN" valueColumnName="VALUE_COLUMN" pkColumnValue="CUST_ID" allocationSize=10 ) @GeneratedValue(strategy=GenerationType.TABLE, generator="CUST_GENERATOR") <table-generator name="CUST_GENERATOR" table="GENERATOR_TABLE" pk-column-name="PRIMARY_KEY_COLUMN" value-column-name="VALUE_COLUMN" pk-column-value="CUST_ID" allocation-size="10" /> <attributes> <id name="id"> <generated-value strategy="TABLE" generator="CUST_GENERATOR"/> </id> </attributes> @SequenceGenerator(name="CUSTOMER_SEQUENCE", sequenceName="CUST_SEQ") @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CUSTOMER_SEQUENCE") <sequence-generator name="CUSTOMER_SEQUENCE" Página 9
  • 10. Resumo_Anotacoes_Certificacao_SCBCD_5.txt sequence-name="CUST_SEQ" initial-value="0" allocation-size="50"/> <attributes> <id name="id"> <generated-value strategy="SEQUENCE" generator="CUSTOMER_SEQUENCE"/> </id> </attributes> -------------------------------------------------------------------------------- ------------------------------------------ - PK Compostas: Por PK Class public class CustomerPK implements java.io.Serializable { private String lastName; private long ssn; public String getLastName( ) { return this.lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public long getSsn( ) { return ssn; } public void setSsn(long ssn) { this.ssn = ssn; } public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof CustomerPK)) return false; CustomerPK pk = (CustomerPK)obj; if (!lastName.equals(pk.lastName)) return false; if (ssn != pk.ssn) return false; return true; } public int hashCode( ) { return lastName.hashCode( ) + (int)ssn; } } @Entity @IdClass(CustomerPK.class) public class Customer { private String firstName; private String lastName; private long ssn; @Id public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Id public long getSsn( ) { return ssn; } public void setSsn(long ssn) { this.ssn = ssn; } } Requerimentos para a PK Class: . It must be serializable . It must have a public no-arg constructor . It must implement the equals( ) and hashCode( ) methods. - PK Compostas: Por Embeddable Class @Embeddable public class CustomerPK implements java.io.Serializable { private String lastName; private long ssn; Página 10
  • 11. Resumo_Anotacoes_Certificacao_SCBCD_5.txt public String getLastName( ) { return this.lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public long getSsn( ) { return ssn; } public void setSsn(long ssn) { this.ssn = ssn; } public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof CustomerPK)) return false; CustomerPK pk = (CustomerPK)obj; if (!lastName.equals(pk.lastName)) return false; if (ssn != pk.ssn) return false; return true; } public int hashCode( ) { return lastName.hashCode( ) + (int)ssn; } } @Entity public class Customer { private String firstName; private CustomerPK pk; @EmbeddedId public PK getPk( ) { return pk; } public void setPk(CustomerPK pk) { this.pk = pk; } } Obs.: Podemos sobrescrever as anotações @Column feitas na classe da PK (não podemos utilizar @Column na classe entidade, pois o nome da coluna á definida na classe de PK) @EmbeddedId @AttributeOverrides({ @AttributeOverride(name="lastName", column=@Column(name="LAST_NAME"), @AttributeOverride(name="ssn", column=@Column(name="SSN")) }) -------------------------------------------------------------------------------- ------------------------------------------ - Mapeando Atributos @Transient Campo não é criado na base @Basic(fetch=FetchType.LAZY, optional=false) Se o campo é obrigatório, e permite lazy loading do campo (porém a especificação não garante o lazy loading real, depende da implementação) @Temporal(TemporalType.TIME) Define o tipo real a gerar na base para um tipo de data java (DATE, TIME, TIMESTAMP) @Lob Define que será um tipo binário (blob) ou um tipo sequencial de caracteres (clob). O tipo real gerado depende do tipo de atributo: BLOB: byte[], Byte[], or java.io.Serializable CLOB: char[], Character[], or java.lang.String @Enumerated(EnumType.STRING) Página 11
  • 12. Resumo_Anotacoes_Certificacao_SCBCD_5.txt Para mapear um atributo do tipo enum. Pode ser ORDINAL ou STRING, onde ORDINAL grava o numero do indice do campo no enum e STRING grava o proprio nome do enum. -------------------------------------------------------------------------------- ------------------------------------------ - Mapeamentos Multi-Table @Entity @SecondaryTable(name="ADDRESS_TABLE", pkJoinColumns={@PrimaryKeyJoinColumn(name="ADDRESS_ID")}) public class Customer { private long id; private String firstName; private String street; private String city; ... @Column(name="STREET", table="ADDRESS_TABLE") public String getStreet( ) { return street; } public void setStreet(String street) { this.street = street; } @Column(name="CITY", table="ADDRESS_TABLE") public String getCity( ) { return city; } public void setCity(String city) { this.city = city; } ... } Obs.: É suportado mais de uma tabela secundária: @SecondaryTables({ @SecondaryTable(name="ADDRESS_TABLE", pkJoinColumns={@PrimaryKeyJoinColumn (name="ADDRESS_ID")}), @SecondaryTable(name="CREDIT_CARD_TABLE", pkJoinColumns={@PrimaryKeyJoinColumn (name="CC_ID")}) }) -------------------------------------------------------------------------------- ------------------------------------------ - Campos de Embeddable Objects @Embeddable public class Address { private String street; private String city; private String state; } @Entity public class Customer { private long id; private String firstName; private String lastName; @Embedded private Address address; } Obs.: como as colunas geradas pela classe embedded são definidas dentro dela, também vale o conceito de @AttributeOverrides para definir outras caracteristicas de coluna dentro da classe utilizadora -------------------------------------------------------------------------------- ------------------------------------------ - Unidirecional "Um-Para-Um" Página 12
  • 13. Resumo_Anotacoes_Certificacao_SCBCD_5.txt @Entity public class Customer { ... @OneToOne(cascade={CascadeType.ALL}) private Address address; ... } <entity-mappings> <entity class="com.titan.domain.Customer" access="FIELD"> <!-- ou access="PROPERTY" --> <attributes> <id name="id"> <generated-value/> </id> <one-to-one name="address" targetEntity="com.titan.domain.Address" fetch="LAZY" optional="true"> <cascade>ALL</cascade> <!-- ou <cascade-all/> --> <join-column name="ADDRESS_ID"/> <!-- ou <primary-key-join-column/> --> </one-to-one> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ - Bidirecional "Um-Para-Um" @Entity public class Customer { ... @OneToOne(cascade={CascadeType.ALL}) private CreditCard creditCard; ... } @Entity public class CreditCard { ... @OneToOne(mappedBy="creditCard") private Customer customer; ... } <entity-mappings> <entity class="com.titan.domain.Customer" access="FIELD"> ... </entity> <entity class="com.titan.domain.CreditCard" access="FIELD"> <attributes> <id name="id"> <generated-value/> </id> <one-to-one name="customer" target-entity="com.titan.domain.Customer" mapped-by="creditCard"/> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ - Unidirecional "Um-Para-Muitos" @Entity Página 13
  • 14. Resumo_Anotacoes_Certificacao_SCBCD_5.txt public class Customer { ... @OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name="CUSTOMER_ID") private Collection<Phone> phoneNumbers = new ArrayList<Phone>( ); ... } <entity-mappings> <entity class="com.titan.domain.Customer" access="FIELD"> <attributes> <id name="id"> <generated-value/> </id> <one-to-many name="phones" targetEntity="com.titan.domain.Phone"> <cascade-all/> <join-column name="CUSTOMER_ID"/> <!-- ou <join-table name="CUSTOMER_PHONE"> --> </one-to-many> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ - Unidirecional "Muitos-Para-Um" @Entity public class Cruise { ... @ManyToOne @JoinColumn(name="SHIP_ID") private Ship ship; ... } <entity-mappings> <entity class="com.titan.domain.Cruise" access="FIELD"> <attributes> <id name="id"> <generated-value/> </id> <many-to-one name="ship" target-entity="com.titan.domain.Ship" fetch="EAGER"> <join-column name="SHIP_ID"/> </many-to-one> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ - Bidirecional "Um-Para-Muitos" / "Muitos-Para-Um" @Entity public class Reservation { ... @ManyToOne @JoinColumn(name="CRUISE_ID") private Cruise cruise; ... } @Entity public class Cruise { Página 14
  • 15. Resumo_Anotacoes_Certificacao_SCBCD_5.txt ... @OneToMany(mappedBy="cruise") private Collection<Reservation> reservations = new ArrayList<Reservation>( ); ... } <entity-mappings> <entity class="com.titan.domain.Cruise" access="FIELD"> <attributes> <id name="id"> <generated-value/> </id> <one-to-many name="ship" target-entity="com.titan.domain.Reservation" fetch="LAZY" mapped-by="cruise" /> </attributes> </entity> <entity class="com.titan.domain.Reservation" access="FIELD"> <attributes> <id name="id"> <generated-value/> </id> <many-to-one name="cruise" target-entity="com.titan.domain.Cruise" fetch="EAGER"> <join-column name="CRUISE_ID"/> </many-to-one> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ - Unidirecional "Muitos-Para-Muitos" @Entity public class Reservation { ... @ManyToMany private Set<Customer> customers = new HashSet<Customer>( ); ... } <entity-mappings> <entity class="com.titan.domain.Reservation" access="PROPERTY"> <attributes> <id name="id"> <generated-value/> </id> <many-to-many name="cabins" target-entity="com.titan.domain.Cabin" fetch="LAZY" /> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ - Bidirecional "Muitos-Para-Muitos" @Entity public class Reservation { ... @ManyToMany @JoinTable(name="RESERVATION_CUSTOMER", joinColumns={@JoinColumn(name="RESERVATION_ID")}, inverseJoinColumns={@JoinColumn(name="CUSTOMER_ID")} ) Página 15
  • 16. Resumo_Anotacoes_Certificacao_SCBCD_5.txt private Set<Customer> customers = new HashSet<Customer>( ); ... } @Entity public class Customer { ... @ManyToMany(mappedBy="customers") private Collection<Reservation> reservations = new ArrayList<Reservation>( ); ... } <entity-mappings> <entity class="com.titan.domain.Reservation" access="FIELD"> <attributes> <id name="id"> <generated-value/> </id> <many-to-many name="customers" target-entity="com.titan.domain.Customer" fetch="LAZY"> <join-table name="RESERVATION_CUSTOMER"> <join-column name="RESERVATION_ID"/> <inverse-join-column name="CUSTOMER_ID"/> </join-table> </many-to-many> </attributes> </entity> <entity class="com.titan.domain.Customer" access="FIELD"> <attributes> <id name="id"> <generated-value/> </id> <many-to-many name="cruise" target-entity="com.titan.domain.Reservation" fetch="LAZY" mapped-by="customers" /> </attributes> </entity> </entity-mappings> -------------------------------------------------------------------------------- ------------------------------------------ @PrimaryKeyJoinColumn Utilizado no OneToOne, quando queremos que a associação não utilize um campo de chave estrangeira, neste caso a associação será feita gravando IDs de mesmo valor nas duas tabelas @PrimaryKeyJoinColumns({ @PrimaryKeyJoinColumn(name="ADDR_ID"), @PrimaryKeyJoinColumn(name="ADDR_ZIP") }) @JoinColumn(name="TOTO_ID") Indica a coluna que receberá a chave primária da outra tabela. Se quiser que referencia outra coluna que não seja a chave primária da tabela, utilizar o atributo referencedColumnName (porem coluna nao pode ter repetição) @JoinColumns({ @JoinColumn(name="ADDR_ID"), @JoinColumn(name="ADDR_ZIP") }) É utilizado para chaves primárias compostas por mais de uma coluna Página 16
  • 17. Resumo_Anotacoes_Certificacao_SCBCD_5.txt @JoinTable É utilizada uma tabela de junção de IDs para relacionamentos Um-Para-Muitos e Muitos-Para-Um Um-Para-Muitos: @JoinTable é padrão Muitos-Para-Um: @JoinColumn é padrão Muitos-Para-Muitos: apenas @JoinTable @OrderBy("lastname ASC, firstname DESC") Permite ordenação, serve apenas para relacionamento com List @MapKey(name="number") É utilizado para relacionamento com Map. O atributo name será o da key do Map, e a entidade relacionada será o value FetchType.EAGER e FetchType.LAZY (cuidados) Se a entidade estiver "detached" e seu relacionamento LAZY não for carregado, e tanter ser acessado, será lançada uma exceção do provedor de persistência (uma chamada ao .size() da coleção do relacionamento garante o load da coleção, ou o uso do operador FETCH JOIN da ejbql) Cruise detachedCruise = ... ; try { int numReservations = detachedCruise.getReservations().size(); } catch (SomeVendorLazyInitializationException ex) { } CascadeType - ALL, PERSIST, MERGE, REMOVE, REFRESH Realiza a respectiva operação do EntityManager para todas as entidades relacionadas. Aumenta a carga de calls na base e pode causar efeitos indesejáveis - Herança: Single Table Per Class Schema: é gerada uma tabela contendo todos os atributos de toda a hierarquia, adicionando uma coluna discriminadora, que identifica qual é o tipo. Person > Customer > Employee @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="DISCRIMINATOR", discriminatorType=DiscriminatorType.STRING) @DiscriminatorValue("PERSON") public class Person { ... } @Entity @DiscriminatorValue("CUST") public class Customer extends Person { ... } @Entity public class Employee extends Customer { ... } Obs.: @DiscriminatorColumn Pode ser STRING, CHAR ou INTEGER. Não é obrigatório, se omitido o default é STRING e o nome é gerado pelo fornecedor. @DiscriminatorValue Não é obrigatório, se omitido utiliza o nome da classe. Vantagens: É simples e performática, não requer joins e é boa para selects polimorficos. Desvantagens: Todas as colunas de todas as subclasses precisam ser NULLABLE, e não possui um modelo normalizado. Página 17
  • 18. Resumo_Anotacoes_Certificacao_SCBCD_5.txt - Herança: Table Per Concrete Class Schema: é gerada uma tabela para cada classe concreta, cada tabela contendo todos os atributos dessa classe e todos seus atributos herdados. Person > Customer > Employee @Entity @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public class Person { ... } @Entity public class Customer extends Person { ... } @Entity public class Employee extends Customer { ... } Obs.: Vantagens: Pode ter constraints NOT NULL em qualquer campo, e o legado pode estar modelado dessa forma. Desvantagens: É mais lento, não é normalizado, possui campos redundantes e tem baixa performance num select polimorfico. - Herança: Table Per SubClass Schema: é gerada uma tabela para cada classe, cada tabela contendo apenas os atributos da classe, onde todas as tabelas são associadas pelas suas chaves primárias. Person > Customer > Employee @Entity @Inheritance(strategy=InheritanceType.JOINED) public class Person { ... } @Entity public class Customer extends Person { ... } @Entity @PrimaryKeyJoinColumn(name="EMP_PK") public class Employee extends Customer { ... } Obs.: A anotação @PrimaryKeyJoinColumn é obrigatória se as colunas das chaves primárias possuirem nomes diferentes nas tabelas. Vantagens: Pode ter constraints NOT NULL em qualquer campo e seu modelo é normalizado. Desvantagens: É mais lento que a SINGLE_TABLE. - Herança: Nonentity Base Classes @MappedSuperclass public class Person { @Id @GeneratedValue private int id; private String lastname; ... } Página 18
  • 19. Resumo_Anotacoes_Certificacao_SCBCD_5.txt @Entity @AttributeOverride(name="lastname", column=@Column(name="SURNAME")) public class Customer extends Person { ... } Obs.: A superclasse não é uma entidade e nem é persistida, ela apenas fornece atributos persistentes para as suas subclasses, que podem ser sobrecarregados com o @AttributeOverrides / @AttributeOverride - Metodos de Callback @PrePersist - Quando uma entidade é agendada para inserção no banco de dados . Depois de persist() . Depois de merge() caso haja inserção aninhada em cascata @PostPersist - Quando a inserção real no banco de dados ocorre efetivamente . Depois do flush() se houver inserção infileirada . Depois que o contexto de persistencia atualiza o banco de dados (se for FlushType.COMMIT, é no final da transação) @PostLoad - Depois da entidade ser hidradata com os dados da base . Depois do find(), getReference() ou uma consulta EJB-QL @PreUpdate - Antes da entidade ser atualizada no banco de dados . Antes do flush() ou antes de o contexto de persistencia atualizar o banco de dados @PostUpdate - Depois da entidade ser atualizada no banco de dados . Depois do flush() ou depois de o contexto de persistencia atualizar o banco de dados @PreRemove - Quando uma entidade é agendada para remoção do banco de dados . Depois de remove() . Depois de merge() caso haja remoção aninhada em cascata @PostRemove - Quando a exclusão real no banco de dados ocorre efetivamente . Depois do flush() se houver exclusão infileirada . Depois que o contexto de persistencia atualiza o banco de dados (se for FlushType.COMMIT, é no final da transação) Obs.: Na classe de entidade: qualquer método que retorne void e não receba argumentos Na classe listener: qualquer método que retorne void e receba como argumento um Object (conterá a instância da entidade em questão) -------------------------------------------------------------------------------- ------------------------------------------ - Listeners de Entidade public class MeuListener1 { ... @PostPersist Página 19
  • 20. Resumo_Anotacoes_Certificacao_SCBCD_5.txt public void postInsert(Object entity) { ... } ... } public class MeuListener2 { ... @PostPersist public void postPersist(Object entity) { ... } @PostLoad public void postLoad(Object entity) { ... } ... } @Entity @EntityListeners({MeuListener1.class, MeuListener2.class}) public class MyEntity { @PostPersist public void afterInsert() { ... } } Obs.: Chamados na ordem em que foram declarados em @EntityListeners ou no XML, por ultimo o da entidade postInsert() + postPersist() + afterInsert() - Herança de Listeners @Entity @EntityListeners({MeuListener1.class}) public class Person { @PostPersist public void parentAfterInsert() { ... } } @Entity @EntityListeners({MeuListener2.class}) public class Customer extends Person { @PostPersist public void childAfterInsert() { ... } } Obs.: Ordem de chamada: PostPersist de MeuListener1 PostPersist de MeuListener2 PostPersist de Person PostPersist de Customer Outras anotations: @ExcludeDefaultListeners Ignora os "Listeners Padrão" setados na unidade de persistencia @ExcludeSuperclassListeners Ignora os listeners herdados - Declarando Listeners com XML <entity class="com.titan.domain.Cabin"> <entity-listeners> <entity-listener class="com.titan.listeners.TitanAuditLogger" /> <entity-listener class="com.titan.listeners.EntityJmxNotifier"> <pre-persist name="beforeInsert"/> <post-load name="afterLoading"/> </entity-listener> Página 20
  • 21. Resumo_Anotacoes_Certificacao_SCBCD_5.txt </entity-listeners> </entity> - Declarando "Listeners Padrão" Os listeners declarados dessa forma serão aplicados à todas entidades da unidade de persistencia: <entity-mappings> <entity-listeners> <entity-listener class="com.titan.listeners.EntityJmxNotifier"> <pre-persist name="beforeInsert"/> <post-load name="afterLoading"/> </entity-listener> </entity-listeners> </entity-mappings> - Conceitos Gerais EJBQL . Pode comparar primitivo com Wrapper e comparar valores temporais . Comparação de entidades na base é feita pela chave primaria . Clausula IN no from: itera a lista e faz join (corresponde a INNER JOIN ou somente JOIN) . Operadores valem apenas no WHERE . Clausula IN no where: verifica se valor está dentro da lista de LITERAIS: IN('X', 'Y', 'Z') . Relacionamento "Um-Para-Um" ou campo basico: IS NULL . Relacionamento baseado em coleção (muitos): IS EMPTY . Cuidado INNER JOIN com IS EMPTY (pag 136) . Cuidado: order by e campos que pode (pag 141) . Operações em lote (chamar antes: flush e clear) - Interface Query public interface Query { public List getResultList( ); public Object getSingleResult( ); public int executeUpdate( ); public Query setMaxResults(int maxResult); public Query setFirstResult(int startPosition); public Query setHint(String hintName, Object value); public Query setParameter(String name, Object value); public Query setParameter(String name, Date value, TemporalType temporalType); public Query setParameter(String name, Calendar value, TemporalType temporalType); public Query setParameter(int position, Object value); public Query setParameter(int position, Date value, TemporalType temporalType); public Query setParameter(int position, Calendar value, TemporalType temporalType); public Query setFlushMode(FlushModeType flushMode); } . Retornando Resultados Método getSingleResult try { Query query = entityManager.creatQuery( "from Customer c where c.firstName='Bill' and c.lastName='Burke'"); Customer cust = (Customer)query.getSingleResult( ); } catch (EntityNotFoundException notFound) { } catch (NonUniqueResultException nonUnique) {} - Utilizado para retornar apenas um registro: . Não encontrou nenhum registro: Página 21
  • 22. Resumo_Anotacoes_Certificacao_SCBCD_5.txt EntityNotFoundException . Encontrou mais de um registro: NonUniqueResultException Método getResultList Query query = entityManager.creatQuery( "from Customer c where c.firstName='Bill' and c.lastName='Burke'"); List bills = query.getResultList( ); - Utilizado para retornar uma coleção de registros: . Não encontrou nenhum registro: retorna uma lista vazia . Parametros Parametros Nomeados Query query = entityManager.createQuery( "from Customer c where c.firstName=:first and c.lastName=:last"); query.setParameter("first", first); query.setParameter("last", last); Parametros Indexados Query query = entityManager.createQuery( "from Customer c where c.firstName=?1 and c.lastName=?2"); query.setParameter(1, first); query.setParameter(2, last); . Parametros Temporais Query query = entityManager.createQuery( "from Customer c where c.dataNascimento=?1"); query.setParameter(1, new java.util.Date, TemporalType.DATE); //DATE, TIME, TIMESTAMP . Paginação de Registros setFirstResult: seta o índice do primeiro registro a trazer setMaxResults: seta a quantidade máxima de registros a trazer Query query = entityManager.createQuery("from Customer c"); List customers = query.setMaxResults(max).setFirstResult(index).getResultList( ); Obs.: é perigoso trazer muitos registros de uma vez, pois todos ficam gerenciados pelo EntityManager e o sistema fica pesado, recomenda-se trazer aos poucos dando clear() no EntityManager . Hints Utilizado para setar na query um atributo específico de fornecedor Query query = manager.createQuery("from Customer c"); query.setHint("org.hibernate.timeout", 1000); . FlushMode query.setFlushMode(FlushModeType.COMMIT); Indica que não deve haver nenhum flush antes da execução desta query query.setFlushMode(FlushModeType.AUTO); É o default, deixa o container livre para fazer flush antes da query, se desejar -------------------------------------------------------------------------------- ------------------------------------------ - Clausulas EJB-QL Página 22
  • 23. Resumo_Anotacoes_Certificacao_SCBCD_5.txt . Considerações Gerais - As clausulas não são case-sensitive - Os nomes de classes e atributos são case-sensitive . Abstract Schema Name @Entity public class Customer {...} -> entityManager.createQuery("SELECT c FROM Customer AS c"); @Entity(name="Cust") public class Customer {...} -> entityManager.createQuery("SELECT c FROM Cust AS c"); . Simple Queryes SELECT OBJECT( c ) FROM Customer AS c SELECT c FROM Customer AS c SELECT c FROM Customer c ERRO: SELECT customer FROM Customer AS customer O identificador não pode ter nome igual ao nome da entidade, independente do case dos caracteres SELECT c.firstName, c.lastName FROM Customer AS c Obs.: se a entidade for mapeada como tipo FIELD, acessa por nome do atributo, se for como tipo PROPERTY, acessa pelo nome do método JavaBean transformado em nome de atributo Obs.: Se a query retornar uma entidade, os registros retornam como um List de entidades Se a query retornar campos escalares, os registros retornam como um List de Object[] . Navegando Entidades SELECT c.creditCard.creditCompany.address FROM Customer AS c Efeito: Retorna o "address" da "creditCompany" da "creditCard" de todos "Customer" Obs.: Permite navegar por relacionamento "unário" ou por atributo @Embedded Exemplo 1: @Entity public class Address { private ZipCode zip; } ERRO: SELECT c.address.zip.mainCode FROM Customer AS c Para tornar o select válido, deveria modificar o atributo para: @Embedded private ZipCode zip; Exemplo 2: @Entity public class Customer { @OneToMany private List<Phone> phones; } ERRO: SELECT c.phones.number FROM Customer AS c Isso seria o mesmo que customer.getPhones( ).getNumber( ); o que é INVALIDO. . Constructor Expressions Página 23
  • 24. Resumo_Anotacoes_Certificacao_SCBCD_5.txt public class Name { private String first; private String last; public Name(String first, String last) { this.first = first; this.last = last; } } SELECT new myPackage.Name(c.firstName, c.lastName) FROM Customer c Efeito: Retorna uma List de objetos "Name" preenchidos como indicado no construtor . Clausula IN / INNER JOIN / JOIN / LEFT JOIN / XXX JOIN FETCH / DISTINCT SELECT r FROM Customer AS c, IN( c.reservations ) r Efeito: Retorna todas reservas de todos clientes Obs.: É idêndico a: = SELECT r FROM Customer AS c, INNER JOIN c.reservations r = SELECT r FROM Customer AS c, JOIN c.reservations r SELECT c.firstName, c.lastName, p.number FROM Customer c INNER JOIN c.phoneNumbers p Como no SQL, INNER JOIN irá retornar apenas campos onde existe associação não nula, ou seja, irá retornar apenas clientes que possuem telefones associados SELECT c.firstName, c.lastName, p.number FROM Customer c LEFT JOIN c.phoneNumbers p Como no SQL, LEFT JOIN irá retornar também campos onde existe associação nula, ou seja, irá retornar todos clientes e, caso não possua telefone associado, retornará null no objeto associativo SELECT c FROM Customer c LEFT JOIN FETCH c.phones Adicionando FETCH após o JOIN indica que se o relacionamento for LAZY, deverá carregar mesmo assim Evita o problema N+1, onde se executassemos getPhones() seriam feito N selects, desta forma é feito apenas um select. SELECT DISTINCT cust FROM Reservation AS res, IN (res.customers) cust Não retorna instancias duplicadas no resultado . Clausula WHERE / BETWEEN / IN / LIKE / IS NULL / IS EMPTY / MEMBER OF SELECT c FROM Customer AS c WHERE c.creditCard.creditCompany.name = 'Capital One' SELECT s FROM Ship AS s WHERE s.tonnage = 100000.00 SELECT c FROM Customer AS c WHERE c.hasGoodCredit = TRUE SELECT r FROM Reservation AS r WHERE (r.amountPaid * .01) > 300.00 SELECT r FROM Reservation r, IN ( r.customers ) AS cust WHERE cust = :specificCustomer SELECT s FROM Ship AS s WHERE s.tonnage BETWEEN 80000.00 AND 130000.00 SELECT c FROM Customer AS c WHERE c.address.state IN ('FL', 'TX', 'MI', 'WI', 'MN') SELECT c FROM Customer AS c WHERE c.address.state NOT IN ('FL', Página 24
  • 25. Resumo_Anotacoes_Certificacao_SCBCD_5.txt 'TX', 'MI', 'WI', 'MN') SELECT c FROM Customer AS c WHERE c.address.state IN ( ?1, ?2, ?3, 'WI', 'MN') SELECT c FROM Customer AS c WHERE c.address IS NULL SELECT c FROM Customer AS c WHERE c.address IS NOT NULL SELECT crs FROM Cruise AS crs WHERE crs.reservations IS EMPTY SELECT crs FROM Cruise AS crs WHERE crs.reservations IS NOT EMPTY Obs.: Não pode utilizar IS EMPTY em um campo especificado no JOIN ERRO: SELECT r FROM Reservation AS r INNER JOIN r.customers AS c WHERE r.customers IS NOT EMPTY AND c.address.city = 'Boston' Obs.: Na clausula like, % indica N caracteres e _ indica um caractere SELECT OBJECT( c ) FROM Customer AS c WHERE c.lastName LIKE '%-%' SELECT OBJECT( c ) FROM Customer AS c WHERE c.lastName LIKE 'Joan_' Obs.: Clausula MEMBER OF é como se fosse o IN para tipos de coleção (contains) SELECT crs FROM Cruise AS crs, IN (crs.reservations) AS res, Customer AS cust WHERE cust = :myCustomer AND cust MEMBER OF res.customers . Clausulas Funcionais LOWER(String) UPPER(String) TRIM([[LEADING | TRAILING | BOTH] [trim_char] FROM] String) CONCAT(String1, String2) LENGTH(String) LOCATE(String1, String2 [, start]) SUBSTRING(String1, start, length) ABS(number) SQRT(double) MOD(int, int) CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP . Clausulas Agregadoras Obs.: se COUNT avalia uma coleção vazia, ele retorna zero SELECT COUNT( c ) FROM Customers AS c WHERE c.address.state = 'WI' SELECT COUNT(c.address.zip) FROM Customers AS c WHERE c.address.zip LIKE '554%' Obs.: MAX e MIN comparam qualquer tipo de dado (utiliza valor ou tamanho em bytes) SELECT MAX( r.amountPaid ) FROM Reservation AS r SELECT MAX( r.amountPaid ) FROM Reservation AS r Obs.: SUM e AVG servem apenas para numericos e wrappers SELECT SUM(r.amountPaid) FROM Cruise c join c.reservations r WHERE c = :cr Obs.: quando utilizado com agregação, o DISTINCT é aplicado antes de agregar os dados Página 25
  • 26. Resumo_Anotacoes_Certificacao_SCBCD_5.txt SELECT DISTINCT COUNT(c.address.zip) FROM Customers AS c WHERE c.address.zip LIKE '554%' Efeito: conta apenas os registros com zip diferentes SELECT c FROM Customers AS c ORDER BY c.lastName SELECT c FROM Customers AS c WHERE c.address.city = 'Boston' AND c.address.state = 'MA' ORDER BY c.lastName SELECT c FROM Customers AS c ORDER BY c.lastName DESC SELECT c FROM Customers AS c ORDER BY c.lastName ASC, c.firstName DESC Cuidado: SELECT addr.zip FROM Address AS addr ORDER BY addr.zip SELECT c.address FOR Customer AS c WHERE c.lastName = 'Smith' ORDER BY c.address.zip ERRO: SELECT c FROM Customer AS c ORDER BY c.address.city Se a query retorna uma coleção, no campo order by podem ser utilizados apenas campos basicos desta coleção ERRO: SELECT c.address.city FROM Customer AS c ORDER BY c.address.state O campo especificado em order by precisa estar sendo trazido no select SELECT cr.name, COUNT (res) FROM Cruise cr JOIN cr.reservations res GROUP BY cr.name HAVING count(res) > 10 . Subqueries SELECT COUNT(res) FROM Reservation res WHERE res.amountPaid > (SELECT avg(r.amountPaid) FROM Reservation r) FROM Cruise cr WHERE 100000 < ( SELECT SUM(res.amountPaid) FROM cr.reservations res ) FROM Cruise cr WHERE 0 < ALL ( SELECT res.amountPaid from cr.reservations res ) Efeito: Seleciona cruzeiros em que todas suas reservas possuam valor de pagamento FROM Cruise cr WHERE 0 = ANY ( SELECT res.amountPaid from cr.reservations res ) Efeito: Seleciona cruzeiros em que exista ao menos uma reserva com valor zerado Obs.: SOME = ANY = NOT ALL FROM Cruise cr WHERE EXISTS (SELECT res FROM cr.reservations WHERE res.amountPaid = 0) Obs.: Clausula EXISTS verifica se a subquery retornou algum registro Efeito: Seleciona os cruseiros que tenham alguma reserva sem pagamento . UPDATE e DELETE em lote UPDATE Reservation res SET res.amountPaid = (res.amountPaid + 10) WHERE EXISTS ( SELECT c FROM res.customers c WHERE c.firstName = 'Bill' AND c.lastName='Burke' ) DELETE FROM Reservation res WHERE EXISTS ( SELECT c FROM res.customers c WHERE c.firstName = 'Bill' AND c.lastName='Burke' ) Página 26
  • 27. Resumo_Anotacoes_Certificacao_SCBCD_5.txt - Scalar Native Queries Query createNativeQuery(String sql) . Usada para valores escalares, retorna um List de Object[] contendo os valores - Simple Entity Native Queries Query createNativeQuery(String sql, Class entityClass) Query query = manager.createNativeQuery("SELECT p.phone_PK, p.phone_number, p.type FROM PHONE AS p", Phone.class); . Espera que os nomes dos campos retornados correspondam em nome e tipo com os atributos persistentes da entidade em questão, então a associação é feita automaticamente . É obrigatório retornar TODOS os atributos da entidade na query - Complex Native Queries Query createNativeQuery(String sql, String mappingName) @Entity @SqlResultSetMapping(name="customerAndCreditCardMapping", entities={ @EntityResult(entityClass=Customer.class), @EntityResult(entityClass=CreditCard.class, fields={@FieldResult(name="id", column="CC_ID"), @FieldResult(name="number", column="number")} )}) public class Customer {...} Query query = manager.createNativeQuery( "SELECT c.id, c.firstName, cc.id As CC_ID, cc.number FROM CUST_TABLE c, CREDIT_CARD_TABLE cc WHERE c.credit_card_id = cc.id", "customerAndCreditCardMapping"); . O mapeamento deve estar definido na entidade . Mapeamento via XML: <entity-mappings> <sql-result-set-mapping name="customerAndCreditCardMapping"> <entity-result entity-class="com.titan.domain.Customer"/> <entity-result entity-class="com.titan.domain.CreditCard"/> <field-result name="id" column="CC_ID"/> <field-result name="number" column="number"/> </entity-result> </sql-result-set-mapping> </entity-mappings> . Misturando resultado de Entidade e resultado Escalar: @SqlResultSetMapping(name="reservationCount", entities=@EntityResult(name="com.titan.domain.Cruise", fields=@FieldResult(name="id", column="id")), columns=@ColumnResult(name="resCount")) @Entity public class Cruise {...} -------------------------------------------------------------------------------- Página 27
  • 28. Resumo_Anotacoes_Certificacao_SCBCD_5.txt ------------------------------------------ - Queryes Nomeadas . EJBQL Named Queryes @NamedQueries({ @NamedQuery(name="getAverageReservation", query="SELECT AVG( r.amountPaid) FROM Cruise As c, JOIN c.reservations r WHERE c = :cruise"), @NamedQuery(name="findFullyPaidCruises", query="FROM Cruise cr WHERE 0 < ALL (SELECT res.amountPaid from cr.reservations res)") }) @Entity public class Cruise {...} Ou Via XML: <entity-mappings> <named-query name="getAverageReservation"> <query> SELECT AVG( r.amountPaid) FROM Cruise As c JOIN c.reservations r WHERE c = :cruise </query> </named-query> </entity-mappings> . SQL Native Named Queryes @NamedNativeQuery(name="findCustAndCCNum", query="SELECT c.id, c.firstName, c.lastName, cc.number AS CC_NUM FROM CUST_TABLE c, CREDIT_CARD_TABLE cc WHERE c.credit_card_id = cc.id", resultSetMapping="customerAndCCNumMapping") @SqlResultSetMapping(name="customerAndCCNumMapping", entities={@EntityResult(entityClass=Customer.class)}, columns={@ColumnResult(name="CC_NUM")} ) @Entity public class Customer {...} Ou via XML: <entity-mappings> <named-native-query name="findCustAndCCNum" result-set-mapping="customerAndCCNumMapping"> <query> SELECT c.id, c.firstName, c.lastName, cc.number AS CC_NUM FROM CUST_TABLE c, CREDIT_CARD_TABLE cc WHERE c.credit_card_id = cc.id </query> </named-native-query> </entity-mappings> - Sistema JMS . Provedor JMS Sistema de rotamento de mensagens . Clientes JMS Produtor (envia) e consumidor (recebe) . Características JMS - Assíncrono (cliente não espera resposta) - Não é propagada transação do produtor pro receptor - Não é propagada segurança nem credenciais do produtor pro receptor - Se o receptor estiver desconectado, o roteador garante a Página 28
  • 29. Resumo_Anotacoes_Certificacao_SCBCD_5.txt entrega da mensagem - Ciclo de Vida: idêntico ao do Stateless Bean, também em pool de instâncias (também com @PostConstruct e @PreDestroy) @Resource(mappedName="ConnectionFactoryName") private ConnectionFactory connectionFactory; @Resource(mappedName="TopicName") private Topic topic; ... Connection connect = factory.createConnection( ); Session session = connect.createSession(true, 0); // 0 -> Session.AUTO_ACKNOWLEDGE MessageProducer producer = session.createProducer(topic); TextMessage textMsg = session.createTextMessage( ); textMsg.setText("my message"); producer.send(textMsg); connect.close( ); . ConnectionFactory Fornece uma factory para criar conexões JMS com um provedor específico . Connection Conexão efetica com o provedor JMS . Session - Sessão para agrupar ações de envio/recebimento de mensagens - Método createSession(boolean transacted, int acknowledgeMode) - muitos provedores utilizam true e 0 (Session.AUTO_ACKNOWLEDGE) por padrão, porém não é garantido - Obs.: O objeto session não é thread-safe, pode apenas um objeto session JMS por Thread . Topic / Queue Nome do channel do Topic ou da Queue. - Topic . Tipo publish/subscribe . Muitos receptores (a mensagem é entregue à todos que assinam) . Modelo push (o receptor é notificado da mensagem) - Queue: . Tipo peer-to-peer . Um receptor (a mensagem é entregue apenas uma vez, ao primeiro que receber) . Conceitualmente é pull (receptor solicita a mensagem), mas também pode ser push, depende do fornecedor . Tipos de Mensagem - Sempre compostas por um Header e um Corpo: TextMessage textMsg = session.createTextMessage(); MapMessage mapMsg = session.createMapMessage(); ObjectMessage objMsg = session.createObjectMessage(); (outras...) - Exemplo de Header: textMessage.setJMSReplyTo(theAnotherQueue); . Cliente JMS Java SE ConnectionFactory factory = (ConnectionFactory) jndiContext.lookup("ConnectionFactoryNameGoesHere"); Topic topic = (Topic)jndiContext.lookup("TopicNameGoesHere"); Connection connect = factory.createConnection( ); Session session = connect.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(topic); Página 29
  • 30. Resumo_Anotacoes_Certificacao_SCBCD_5.txt consumer.setMessageListener(this); //ou qualquer instancia que implemente javax.jms.MessageListener connect.start( ); public void onMessage(Message message) { TextMessage textMsg = (TextMessage)message; String text = textMsg.getText(); } - Message Driven Beans . Bean especial para consumir mensagens . Não se deve utilizar um Session Bean para consumir mensagens (mas é possível, através dos métodos MessageConsumer.receive(), MessageConsumer.receive(long timeout) ou MessageConsumer.receiveNoWait() . Anotação @Target(TYPE) @Retention(RUNTIME) public @interface MessageDriven { String name() default ""; //nome do MDB Class messageListenerInterface default Object.class; //pode setar como javax.jms.MessageListener e não //implementar a interface explicitamente ActivationConfigProperty[] activationConfig() default {}; //configurações específicas de MDB String mappedName(); //se preferir pode especificar o destino aqui String description(); } . MessageDrivenContext - Extende o EJBContext, é semelhante ao SessionContext porém não adiciona nenhuma operação - Pode-se utilizar apenas os métodos transacionais. Os métodos de segurança lançam uma RuntimeException, pois na JMS não há propagação de segurança . Interface javax.jms.MessageListener Único método: public void onMessage(Message message) @MessageDriven( activationConfig={ @ActivationConfigProperty( propertyName="destinationType", propertyValue="javax.jms.Queue"), @ActivationConfigProperty( propertyName="destinationName", propertyValue="jms/TitanQueue"), @ActivationConfigProperty( propertyName="messageSelector", propertyValue="MessageFormat = 'Version 3.4'"), @ActivationConfigProperty( propertyName="acknowledgeMode", propertyValue="Auto-acknowledge") }) public class ReservationProcessorBean implements javax.jms.MessageListener { @Resource(mappedName="ConnectionFactory") private ConnectionFactory connectionFactory; public void onMessage(Message message) { try { MapMessage reservationMsg = (MapMessage)message; Página 30
  • 31. Resumo_Anotacoes_Certificacao_SCBCD_5.txt int customerPk = reservationMsg.getInt("CustomerID"); int cruisePk = reservationMsg.getInt("CruiseID"); int cabinPk = reservationMsg.getInt("CabinID"); double price = reservationMsg.getDouble("Price"); } catch(Exception e) { throw new EJBException(e); } } } . Atributos ActivationConfigProperty - messageSelector Pode utilizar uma query sintaxe SQL para filtrar quais mensagens o bean vai consumir de acordo com propriedades setadas na mensagem - acknowledgeMode AUTO_ACKNOWLEDGE - é computado recebimento logo após a mensagem ser entregue e processada DUPS_OK_ACKNOWLEDGE - é computado o recebimento em lote, de forma otimizada (o MDB precisa ter preparo para tratar mensagens duplicatas) - subscriptionDurability Durable - tolerantes à desconexão do container, a mensagem é armazenada e entregue depois NonDurable - o contrário, qualquer mensagem recebida enquanto desconectado será perdida . Descritor XML <enterprise-beans> <message-driven> <ejb-name>ReservationProcessorBean</ejb-name> <ejb-class>com.titan.reservationprocessor.ReservationProcessorBean</ejb-class> <messaging-type>javax.jms.MessageListener</messaging-type> <transaction-type>Container</transaction-type> <message-destination-type>javax.jms.Queue</message-destination-type> <activation-config> <activation-property> <activation-config-property-name>destinationType</activation-config-property-nam e> <activation-config-property-value>javax.jms.Queue</activation-config-property-va lue> <activation-property> <activation-property> <activation-config-property-name>destinationName</activation-config-property-nam e> <activation-config-property-value>jms/TitanQueue</activation-config-property-val ue> <activation-property> <activation-property> <activation-config-property-name>messageSelector</activation-config-property-nam e> <activation-config-property-value>MessageFormat = 'Version 3.4'</activation-config-property-value> <activation-property> <activation-property> Página 31
  • 32. Resumo_Anotacoes_Certificacao_SCBCD_5.txt <activation-config-property-name>acknowledgeMode</activation-config-property-nam e> <activation-config-property-value>Auto-acknowledge</activation-config-property-v alue> <activation-property> </activation-config> </message-driven> </enterprise-beans> </ejb-jar> -------------------------------------------------------------------------------- ------------------------------------------ - Ouvindo um Timer @Stateless public class ShipMaintenanceBean implements ShipMaintenanceRemote implements javax.ejb.TimedObject { ... public void ejbTimeout(javax.ejb.Timer timer) { ... } } ou... @Stateless public class ShipMaintenanceBean implements ShipMaintenanceRemote { ... @Timeout public void myTimeout(javax.ejb.Timer timer) { ... } } - Criando um Timer . O próprio bean se registra para ouvir o timer . O timer pode ser criado em Stateless e MessageDriven beans . CUIDADO: não se deve criar timers em @PostConstruct nem @PreDestroy (são chamados para cada instância do pool), nem utilizando variáveis estáticas para verificar se já foi criado (problema do cluster) . O timer deve ser criado apenas através de métodos de negócio invocados pelo cliente . Um timer service pode ser obtido através do EJBContext.getTimerService(), ou injetado pelo container: @Resource TimerService timerService; . Interface TimerService - public Timer createTimer(Date expiration, Serializable info) . Ação única . Expira na data especificada - public Timer createTimer(long duration, Serializable info) . Ação única . Expira depois de passado o tempo especificado em milisegundos - public Timer createTimer(Date initialExpiration, long intervalDuration, Serializable info) . De intervalo . Expira na data especificada e subsequentemente a cada intervalo especificado em intervalDuration - public Timer createTimer(long initialDuration, long Página 32
  • 33. Resumo_Anotacoes_Certificacao_SCBCD_5.txt intervalDuration, Serializable info) . De intervalo . Expira depois de passado o tempo initialDuration e subsequentemente a cada intervalo especificado em intervalDuration - public Collection getTimers() . Retorna uma coleção contendo todos os timers agendados para o beans em questão (apenas os timers do bean que chamou o método) Obs.: Todos os métodos TimerService lançam as exceções: . IllegalArgumentException: parâmetros negativos ou null . IllegalStateException: chamado de onde não é permitido . EJBException: encapsula qualquer outra exceção de sistema . Interface Timer - public void cancel() Cancela o timer - public Serializable getInfo() Recupera o objeto passado na criação do timer - public Date getNextTimeout() Recupera a data em que ocorrerá a próxima expiração - public long getTimeRemaining() Recupera o tempo restante para a próxima expiração - public TimerHandle getHandle() Recupera uma referência serializável à instância deste timer Obs.: Todos os métodos Timer lançam as exceções: . NoSuchObjectLocalException: se invocado qualquer método em um timer de ação única expirado ou um timer cancelado . EJBException: encapsula qualquer outra exceção de sistema . Reagendando temporizadores: precisa cancelar e criar um novo . Transação - É transacional no escopo da transação atual, ou seja, se ocorrer rollback em um método que cria o timer, sua criação será desfeita - É boa prática o método de @Timeout ser transacional RequiresNew, para assegurar que ele está no escopo transacional do container - Interceptors . Criando Classes Interceptadoras public class Profiler { @AroundInvoke public Object profile(InvocationContext invocation) throws Exception { long startTime = System.currentTimeMillis( ); try { return invocation.proceed( ); } finally { long endTime = System.currentTimeMillis( ) - startTime; System.out.println("Method " + Página 33
  • 34. Resumo_Anotacoes_Certificacao_SCBCD_5.txt invocation.getMethod( ) + " took " + endTime + " (ms)"); } } } . Interface InvocationContext public interface InvocationContext { public Object getTarget( ); public Method getMethod( ); public Object[] getParameters( ); public void setParameters(Object[] newArgs); public java.util.Map<String, Object> getContextData( ); public Object proceed( ) throws Exception; } . getTarget - retorna uma referência à instância do bean alvo . getMethod - retorna um objeto java.lang.reflect.Method do método que foi chamado . getParameters - retorna os parâmetros que foram enviados ao método . setParameters - modifica tais parâmetros (usar com cuidado) . getContextData - retorna um objeto Map que fica ativo durante toda a pilha de chamada, onde podemos compartilhar valores com outros interceptors . proceed - continua a pilha de chamada (próximo interceptor ou método original) . Aplicando Interceptors - Nível de Classe (intercepta todos os métodos do bean) @Stateless @Interceptors(Profiler.class) public class MyBean implements MyBeanRemote { ... } - Nível de Método (intercepta apenas o método anotado) @Stateless public class MyBean implements MyBeanRemote { @Interceptors(Profiler.class) public void myMethod() { ... } } - Aplicando via XML <ejb-jar> <assembly-descriptor> <interceptor-binding> <ejb-name>TravelAgentBean</ejb-name> <!-- <exclude-default-interceptors> e <exclude-class-interceptors> --> <interceptor-class>com.titan.Profiler</interceptor-class> <method-name>bookPassage</method-name> <method-params> <method-param>com.titan.CreditCardDO</method-param> <method-param>double</method-param> </method-params> Página 34
  • 35. Resumo_Anotacoes_Certificacao_SCBCD_5.txt </interceptor-binding> </assembly-descriptor> </ejb-jar> . Obs: - <method-name> é utilizado apenas para aplicar a nivel de método - <method-params> é útil se houver overload no método especificado - Interceptors Padrão . Recebem um curinga (*). São aplicados para todos os métodos de todos os beans do ejb-jar. <ejb-jar> <assembly-descriptor> <interceptor-binding> <ejb-name>*</ejb-name> <interceptor-class>com.titan.Profiler</interceptor-class> </interceptor-binding> </assembly-descriptor> </ejb-jar> - Desativando Interceptors . @ExcludeDefaultInterceptors Ignora os interceptors-padrão da implantação . @ExcludeClassInterceptors Ignora os interceptors de nivel de classe do bean -------------------------------------------------------------------------------- ------------------------------------------ - Interceptors e Injeção de Dependência (ENC) . O interceptor compartilha o mesmo JNDI ENC do bean que está interceptando . O EJBContext também é compartilhado . Injeção no Interceptor - Via Annotations public class AuditInterceptor { @Resource EJBContext ctx; @PersistenceContext(unitName="auditdb") EntityManager manager; @AroundInvoke public Object audit(InvocationContext invocation) throws Exception { ... } } - Via XML <ejb-jar> <interceptors> <interceptor> <interceptor-class>com.titan.interceptors.AuditInterceptor</interceptor-class> <around-invoke> Página 35