Zarzadzanie encjami.

Transkrypt

Zarzadzanie 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,
●
konfiguracja JNDI,
●
program korzystający z komponentów.
2
EntityBean: 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
EntityBean: 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 utrwalania
Plik persistance.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
SessionBean: 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
SessionBean: 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
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
Klient - konfiguracja JNDI
Konfiguracja 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=149.156.74.236
9
Program kliencki
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://java.sun.com/javaee/5/docs/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");
// zmiana automatycznie zapisana
// w bazie danych
return c;
// 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