Zarządzaniee encjami

Transkrypt

Zarządzaniee encjami
Zarządzanie encjami
1. Komponenty i JBoss
●
komponenty EJB,
●
program kliencki.
2. Usługa EntityManager
●
encje zarządzane i niezarządzane,
●
kontekst transakcji,
●
podstawowe usługi,
●
transakcje poza JEE.
1
Komponenty i JBoss
Struktura programu:
1. Serwer (titan.jar):
●
komponent encyjny: Cabin
●
deskryptor utrwalania: persistance.xml
●
komponent sesyjny: TravelAgent
2. Klient:
●
biblioteki,
●
konfguracja JNDI,
●
program korzystający z komponentów.
2
Komponent encyjny: Cabin
package com.titan.domain;
import
import
import
import
javax.persistence.Entity;
javax.persistence.Table;
javax.persistence.Column;
javax.persistence.Id;
@Entity
@Table(name = "CABIN")
public class Cabin implements java.io.Serializable {
private int id;
private String name;
private int deckLevel;
private int shipId;
private int bedCount;
3
Komponent encyjny: Cabin
@Id
@Column(name = "ID")
public int getId() { return id; }
public void setId(int pk) { id = pk;
}
@Column(name = "NAME")
public String getName() { return name;
}
public void setName(String str) { name = str;
}
@Column(name = "DECK_LEVEL")
public int getDeckLevel() { return deckLevel;
}
public void setDeckLevel(int level) { deckLevel = level;}
@Column(name = "SHIP_ID")
public int getShipId() { return shipId; }
public void setShipId(int sid) { shipId = sid;
}
}
@Column(name = "BED_COUNT")
public int getBedCount() { return bedCount; }
public void setBedCount(int bed) { bedCount = bed; }
4
Deskryptor utwalania
Plik persistence.xml znajduje się w podkatalogu META-INF
<?xml version="1.0" encoding="UTF-8"?>
<persistence>
<persistence-unit name="titan">
<jta-data-source>java:/DefaultDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>
5
Komponent sesyjny:
TravelAgent
package com.titan.travelagent;
import javax.ejb.Remote;
import com.titan.domain.Cabin;
@Remote
public interface TravelAgentRemote {
public void createCabin(Cabin cabin);
public Cabin findCabin(int pKey);
}
public void updateCabin(Cabin cabin);
6
Komponent sesyjny:
TravelAgent
package com.titan.travelagent;
import
import
import
import
javax.ejb.Stateless;
javax.persistence.EntityManager;
javax.persistence.PersistenceContext;
com.titan.domain.Cabin;
@Stateless
public class TravelAgentBean implements TravelAgentRemote {
@PersistenceContext(unitName = "titan")
private EntityManager manager;
public void createCabin(Cabin cabin) {
manager.persist(cabin);
}
public Cabin findCabin(int pKey) {
return manager.find(Cabin.class, pKey);
}
public void updateCabin(Cabin cabin) {
manager.merge(cabin);
}
}
7
Biblioteki dla klienta
Do prawidłowego działania niezbędne są biblioteki (narzędzia)
pozwalające korzystać z usług kontenera, a w przypadku
oprogramowania klienckiego ze zdalnych komponentów. Biblioteki są
udostępniane przez producenta kontenera EJB. W przypadku serwera
JBoss należy użyć z następujących plików:
●
ejb3-persistence.jar
●
jboss-aop-jdk50-client.jar
●
jboss-aspect-jdk50-client.jar
●
jboss-ejb3-client.jar
●
jboss-ejb3x.jar
●
jbossall-client.jar
które można znaleźć w podkatalogu client/ serwera.
8
Konfguracja JNDI u klienta
Konfguracja JNDI zapisana jest w pliku jndi.properties. Aby
zachować takie ustawienia dla wszystkich programów korzystających
z JNDI plik należy umieścić na ścieżce klas.
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=127.0.0.1
9
Program klienta
package com.titan.clients;
import java.io.IOException;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.titan.domain.Cabin;
import com.titan.travelagent.TravelAgentRemote;
public class Client {
static{
Properties p = new Properties();
try {
p.load(Client.class.getResourceAsStream(
}
"jndi.properties"));
} catch (IOException e) { e.printStackTrace(); }
System.getProperties().putAll(p);
10
Program kliencki
public static Context getInitialContext() throws NamingException {
return new InitialContext();
}
public static void main(String[] args) {
try {
Context jndiContext = getInitialContext();
Object ref = jndiContext.lookup("TravelAgentBean/remote");
TravelAgentRemote dao = (TravelAgentRemote) ref;
Cabin c = dao.findCabin(1);
if (c==null){
System.out.println("new cabin");
c = new Cabin();
11
Program kliencki
c.setId(1);
c.setName("Master Suite");
c.setDeckLevel(1);
c.setShipId(1);
c.setBedCount(3);
dao.createCabin(c);
}else{
System.out.println("present cabin");
}
System.out.println(c.getName());
System.out.println(c.getDeckLevel());
System.out.println(c.getShipId());
System.out.println(c.getBedCount());
}
}
} catch (javax.naming.NamingException ne) {
ne.printStackTrace();
}
12
build.xml
<?xml version="1.0"?>
<project name="wzorce-03" default="ejbjar" basedir=".">
<property environment="env"/>
<property name="src.dir" value="${basedir}/src"/>
<property name="lib.dir" value="${basedir}/lib"/>
<property name="classes.dir" value="${basedir}/bin"/>
<property name="build.dir" value="${basedir}/build"/>
<target name="ejbjar">
<jar jarfile="${build.dir}/titan.jar">
<fileset dir="${classes.dir}">
<include name="com/titan/domain/*.class"/>
<include name="com/titan/travelagent/*.class"/>
</fileset>
<fileset dir="${src.dir}/">
<include name="META-INF/persistence.xml"/>
</fileset>
</jar>
</target>
13
build.xml
<target name="run.client">
<java classname="com.titan.clients.Client" fork="yes" dir=".">
<classpath>
<fileset dir="${classes.dir}">
<include name="${lib.dir}/*.jar"/>
</fileset>
</classpath>
</java>
</target>
</project>
14
Usługa EntityManager
Menadżer encji udostępnia metody pozwalające wykonywać
podstawowe operacje na tych obiektach. Do operacji tych należą:
●
utrwalanie,
●
wyszukiwanie,
●
scalanie,
●
usuwanie,
●
synchronizacja,
●
blokowanie dostępu.
źródło:
http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html
15
Utrwalanie
Utrwalenie POJO dokonuje się za pomocą metody void persist(Object).
W jej wyniku menadżer umieszcza w kolejce odpowiednie żądanie
zapisu obiektu w bazie danych. Moment rzeczywistego zapisu zależy od
kontenera i innych okoliczności (transakcje). Ponadto metoda ta
dołącza POJO do zbioru zarządzanych encji.
Typowe wyjątki:
IllegalArgumentException – argument nie jest encją,
EntityExistsException – encja już istnieje,
TransactionRequiredException – wywołanie poza kontekstem transakcji.
16
Encje zarządzane
i niezarządzane
Po utworzeniu obiektu Cabin za pomocą konstruktora jest on zwykłym
POJO. Zmiany atrybutów nie mają żadnego wpływu na zawartość bazy
danych. Encja jest niezarządzana (odłączona).
Dopiero
wywołanie
metody
EntityManager.persist()
powoduje
związanie stanu obiektu z bazą danych. Od tej chwili encja jest
zarządzana (dołączona do zbioru zarządzanych encji) w ramach
określonego kontekstu transakcyjnego.
Cabin c = new Cabin();
...
//
manager.persist(c);
//
...
//
return c;
//
encja niezarządzana
utrwalenie i początek zarządzania
encja zarządzana
zwykle koniec zarządzania
17
Odnajdywanie – klucz główny
Do uzyskania referencji do encji na podstawie klucza głównego służą
metody:
<T> T find(Class<T>, Object) – zwraca referencję do encji lub null,
<T> T getReference(Class<T>, Object) – zwraca referencję do encji,
której stan może być załadowany dopiero w momencie odwołania się
do niego (lazy fetched). W przypadku nieodnalezienia encji zwracany
jest wyjątek EntityNotFoundException. Ze względu na sposób działania
metody,
wyjątek
może
zostać
zwrócony
dopiero
w
momencie
odwołania się do stanu encji.
18
Odnajdywanie – język QL
Do uzyskania referencji można skorzystać także z zapytań wyrażonych
w języku QL (Query Language).
Query query = manager.createQuery("from Cabin c where id=2");
Cabin c = (Cabin)query.getSingleResult( );
Wszystkie encje zwracane przez find(), getReference(), czy też
zapytania QL są zarządzane dopóki kontekst zarządzania, w którym
zostały odczytane jest aktywny.
19
Kontekst transakcji
i zarządzanie
Adnotacja @TransactionAttribute(TransactionAttributeType.REQUIRED)
powoduje, że metoda someMethod() zostanie wykonana jako transakcja.
@PersistenceContext(unitName = "titan")
EntityManager entityManager;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
// kontekst transakcji
public Cabin someMethod() {
Cabin c = entityManager.find(Cabin.class, 1);
// uzyskanie referencji do encji
// zarządzanej
c.setName("new name");
return c;
}
//
//
//
//
zmiana automatycznie zapisana
w bazie danych
koniec transakcji – encja
niezarządzana
wszelkie zmiany na zwróconej referencji nie będą odwzorowane w bazie
danych, aż do kolejnego wywołania odpowiedniej metody
20
Scalanie encji
Encje odłączone można ponownie związać z utrwalonym stanem
w bazie danych korzystając z metody <T> T merge(T).
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Cabin update(Cabin c) {
// c – encja (odłączona lub dołączona)
Cabin copy = manager.merge(c);
// copy - encja zarządzana (przyłączona) z atrybutami
// skopiowanymi z c
// c - encja odłączona
copy.setName("name1");
// nazwa zmieniona w obiekcie i bazie
c.setName("name2");
// nazwa zmieniona tylko w obiekcie
}
21
Usuwanie encji
Usuwanie pojedynczej encji można zrealizować za pomocą operacji
void remove(Object). Powoduje ono dodanie do kolejki odpowiedniej
operacji DELETE wykonywanej na bazie danych.
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Cabin removeCabin(int key) {
Cabin cabin = manager.find(Cabin.class, key);
manager.remove(cabin);
return cabin;
}
Operację remove() można „odwrócić” wywołując metodę persist() z tą
samą encją w roli argumentu.
22
Odświeżanie encji
Jeżeli chcemy odświeżyć stan zarządzanej encji na podstawie informacji
w bazie danych używamy metody void refresh(Object).
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void someMethod(int id) {
Cabin cabin = manager.find(Cabin.class, id);
manager.refresh(cabin);
}
W przypadku braku encji w bazie lub wśród obiektów zarządzanych
zwracany jest IllegalArgumentException.
23
Inne operacje
Interfejs EntityManager określa także inne metody. Najczęściej używane
to:
●
boolean contains(Object) – sprawdza, czy encja jest zarządzana,
●
void clear() - odłącza wszystkie zarządzane encje,
●
void flush() - synchronizuje bazę danych ze stanem encji.
Synchronizacja odbywa się w zależności od parametru ustawionego
metodą: setFlushMode(FlushModeType). Domyślny typ to AUTO
odpowiadający synchronizacji na poziomie zapytań. Typ COMMIT określa
synchronizację na poziomie transakcji.
●
EntityTransaction getTransaction() - zwraca obiekt do zarządzania
transakcjami na poziomie zasobów.
24
Transakcje
Transakcje w ramach contenera JEE są zarządzane poprzez JTA (Java
Transaction Api). W środowisku niezgodnym z JEE (np. w programach
klienckich) transakcjami można zarządzać poprzez interfejs
EntityTransaction.
public interface EntityTransaction {
public void begin( );
public void commit( );
public void rollback( );
public boolean isActive( );
}
25
Transakcje
...
// uzyskanie interfejsu EntityManagerFactory
EntityManagerFactory factory = Persistence
.createEntityManagerFactory("titan");
// uzyskanie kontekstu utrwalania
EntityManager manager = factory.createEntityManager();
...
// uzyskanie interfejsu do zarządzania transakcjami
EntityTransaction transaction = (EntityTransaction) manager
.getTransaction();
transaction.begin(); // początek transakcji
...
manager.persist(cabin_1);
...
transaction.commit(); // koniec transakcji
26
Podsumowanie
Usługa EntityManager umożliwia zarządzanie komponentami encyjnymi
realizując podstawowe operacje, takie jak: utrwalanie, synchronizacja,
usuwanie. Ponadto EntityManager udostępnia interfejs transakcyjny.
Usługa EntityManager jest dostępna zarówno dla komponentów
działających w ramach kontenera EJB jak również dla programów
klienckich.
27

Podobne dokumenty