Komponenter Föreläsning 4 Enterprise Java Beans (EJB) En mjukvarukomponent är en fristående modul (objekt) med följande egenskaper: Distribuerbar Välavgränsad funktionalitet Återanvändbar Driftsättningsbar Komponenterna hanteras av en s k Container vilken hanterar Lagring, sökning Sköter kommunikationen mellan klienter och komponenterna med t ex JNDI och RMI. Säkerhet Skalbarhet Containern är en del av orion EJB En EJB är en distribuerbar server-side komponent som dessutom erbjuder databeständighet (persistens) EJB är inte en implementation från SUN endast en specifikation (nuvarande är 2.1). Det är upp till applikationsservern att stödja denna specifikation. Dokumentationen består därför främst av olika interface som bean-programmeraren åtar sig att implementera. En EJB består av En vanlig Javaklass med affärslogik Två (tre) Java interface, mot klienten: Remote (Local) Home (Local-Home) Descriptor-fil (ejb-jar.xml) Olika sorters böner Session Beans (för kännedom) Stateful Stateless Message driven beans (ingår ej i kursen) Entity Beans Bean-Managed Container-Managed Session Beans Stateless Session Beans home interface:et måste ha en create metod utan argument Session Beans beskriver ofta processer eller tjänster som använder sig av ett eller flera anrop till Entiy beans Har inte ett tillstånd En sessionsböna kan delas av fler användare Resultatet påverkas inte av vilken instans som hanterar anropet Stateful Session Beans Håller reda på information mellan förfrågningar, d v s behåller ett tillstånd Kan ha create metoder som tar argument Skickas runt mellan servrar Är mycket lik en stateless men med den skillnaden att den behåller tillstånd, kan alltså ha instansvariabler Eftersom det primära syftet för en sessionsböna är att representera en klient i en J2EE server, kommer de flesta bönerna vara stateful Sun I webapplikater representeras vanligtvis klienten av en JSP-JavaBean och därför kommer inte session beans att behandlas mer... 1
Entitetsbönor Representerar data som speglas i en databas Ett objekt som motsvarar någon typ av substantiv Kund, Konto, Bil osv Objektets instansvariabler blir kolumner i tabellen med samma namn som EJB:n Att skapa en EJB leder därför till att en rad adderas till databasen Sköter persistens Eftersom en entity böna sparas i någon slags datakälla existerar den längre än applikationen Överlever systemkrascher Flera samtidiga användare Kräver primärnyckel CMP Automatisk generering av SQL, t e x när klienten skapar en ny entity bean genererar containern en INSERT-sats Koden Bean-utvecklaren skriver innehåller alltså ingen SQL Som ett resultat av detta är denna sortens böna oberoende av databasen vilket gör att den är helt portabel mellan olika DB och applikationsservrar Fördelar Mindre kod -> Mindre buggar Mindre beroenden -> mer portabel Nackdelar Svårare att göra komplexa beroenden i SQL BMP Med Bean-Managed Persistence skriver man själv SQL-satserna för bönan En instansiering av ett nytt objekt kommer exempelvis att utföra en INSERT sats Blir allt ovanligare efterhand som CMP utvecklas Tillvägagångssätt Vid första driftsättning skapar Containern automatiskt upp tabellerna när orion startar. Om man ändrar instansvariablerna(=ändrad tabell) måste man droppa tabellen manuellt i databasen. För att skriva en Entity böna behövs följande: Entity Bean Klass (StudenterEJB) Home Interface (StudenterHome) Remote Interface (Studenter) I många webapplikationer är distribuerbarhet ej nödvändigt, dvs bönor används endast inom en instans av applikationsservern(= en container), då används istället Entity Bean Klass (StudenterEJB) Local Home Interface (StudenterHome) Local Interface (Studenter) Översiktsbild EntityBean klassen JavaBean StudenterHome-Interface Create() findbyprimarykey() Studenter -Interface setenamn() setfnamn() getenamn() getfnamn() StudenterEJB ejbcreate() EntityBean klassen ärver av EnterpriseBean interface:et. EntityBean interface:et deklarerar ett antal metoder, så som ejbstore och ejbload, som man måste implementera i sin entity bean klass Identiskt för både distribuerade och lokala entitetsbönor StudenterEJB uppfyller dessa entity bean krav Den impementerar en eller fler ejbcreate och matchande ejbpostcreate metoder Den har implementationen av affärslogiken. Den har en tom konstruktor 2
Home Interface Home interface:et definierar de metoder som tillåter en klient att skapa och hitta en entity böna Ärver av EJBHome interfacet för RMI, EJBLocalHome för lokala bönor Varje create metod i home interface:et måste formas efter följande krav: Den har samma antal och typ av argument som dess matchande ejbcreate metod i enterprise beans klassen Den returnerar remote interface:et av bönan throws satsen har samma exceptions som throws satsen i motsvarande ejbcreate och ejbpostcreate metoder throws satsen inneåller dessutom javax.ejb.createexception (samt för distribuerade bönor java.rmi.remoteexception) Varje finder metod i home interface:et måste formas efter följande krav: Den returnerar remote interface:et av bönan eller en Collection av dylika throws satsen innehåller dessutom javax.ejb.remoteexception (samt för distribuerade bönor java.rmi.finderexception) I EJB 2.0+ finns stöd för EJB-QL vilket ger möjlighet till mer generella findermetoder, illustreras i exemplet findbyprimarykey() är automatisk implementerade av containern, findall() tvingas man implementera själv sedan orion 2.0+. Remote Interface Tillhandahåller de metoder som kan anropas efter att en böna har skapats upp Remote interface:et ärver av javax.ejb.ejbobject för RMI, javax.ejb.ejblocalobject för lokala bönor. Ejbmaker.jar En wizard i orion för att skapa EJB:er Startas med java jar ejbmaker.jar under v:\orion Mycket primitiv och tyävrr buggig men kan användas för att komma igång Exemplet innehåller Jsp-sida Javabean Enterprise JavaBean EJB 2.0 (ej 2.1) specifikation Entitetsböna Lokalt interface CMP EJB-QL Exempel Exempel: Homeinterface(lokalt) Exempel: Remoteinterface(lokalt) public interface StudenterHome extends EJBLocalHome{ public Studenter create(long key, String enamn, String fnamn) throws CreateException; public Studenter findbyprimarykey(long key) throws FinderException; public java.util.collection findbynamn(string enamn, String fnamn) throws FinderException; public interface Studenter extends EJBLocalObject{ public long getkey(); public java.lang.string getenamn(); public void setenamn(java.lang.string value); public java.lang.string getfnamn(); public void setfnamn(java.lang.string value); 3
Exempel: EJB-klassen 1/2 public abstract class StudenterEJB implements EntityBean{ protected EntityContext context; public StudenterEJB(){ public abstract long getkey(); public abstract void setkey(long value); public abstract java.lang.string getenamn(); public abstract void setenamn(java.lang.string value); public abstract java.lang.string getfnamn(); public abstract void setfnamn(java.lang.string value); public void ejbload(){ public void ejbstore(){ Exempel: EJB-klassen 2/2 public void ejbactivate(){ public void ejbpassivate(){ public void ejbremove(){ public void setentitycontext(entitycontext context){ this.context = context; public void unsetentitycontext(){ this.context = null; public Long ejbcreate(long key, String enamn, String fnamn) throws CreateException{ setkey(key); setenamn(enamn); setfnamn(fnamn); return null; // Return null when using CMP public void ejbpostcreate(long key, String enamn, String fnamn){ ejb-jar.xml 1/2 <ejb-jar> <enterprise-beans> <entity> <description>local entitybean CMP 2.0</description> <local-home>studenterhome</local-home> <local>studenter</local> <ejb-name>studenter</ejb-name> <ejb-class>studenterejb</ejb-class> <abstract-schema-name>studenter</abstract-schema-name> <persistence-type>container</persistence-type> <cmp-version>2.x</cmp-version> <reentrant>false</reentrant> <cmp-field><field-name>key</field-name></cmp-field> <cmp-field><field-name>enamn</field-name></cmp-field> <cmp-field><field-name>fnamn</field-name></cmp-field> <primkey-field>key</primkey-field> <prim-key-class>java.lang.long</prim-key-class> ejb-jar.xml 2/2 <query> <query-method> <method-name>findbynamn</method-name> <method-params> <method-param>java.lang.string</method-param> <method-param>java.lang.string</method-param> </method-params> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(o) FROM Studenter AS o WHERE o.enamn =?1 AND o.fnamn=?2]]> </ejb-ql> </query> </entity> </enterprise-beans> </ejb-jar> web.xml <web-app> <display-name>web</display-name> <taglib> <taglib-uri>util</taglib-uri> <taglib-location>/web-inf/taglib.tld</taglib-location> </taglib> <ejb-local-ref> <ejb-ref-name>studenter</ejb-ref-name> <ejb-ref-type>entity</ejb-ref-type>11 <local-home>studenterhome</local-home> <local>studenter</local> </ejb-local-ref> </web-app> Adminbönan 1:2 import javax.naming.*; import java.util.collection; import java.util.iterator; public class AdminBean{ private String fnamn; private String enamn; private String action; private StudenterHome home = null; public AdminBean(){ InitialContext env = null; env = new InitialContext(); home = (StudenterHome)env.lookup("java:comp/env/Studenter"); catch(namingexception e){ System.out.println("NamingException:"+e.getMessage()); public void setfnamn(string fnamn){ this.fnamn = fnamn; public void setenamn(string enamn){ this.enamn = enamn; public void setaction(string action){ this.action = action; 4
Adminbönan 2:2 public String execute(){ Studenter s; if("addera".equals(action)){ int key = (int)(1000*math.random()); s = home.create(key, enamn, fnamn); catch(createexception e){ System.out.println("CreateException:"+e.getMessage()); if("hitta".equals(action)){ Collection c = home.findbynamn(enamn,fnamn); Iterator i = c.iterator(); String str = ""; while(i.hasnext()){ s = (Studenter)i.next(); str = str + s.getenamn() + " " + s.getfnamn() + "<br>"; return str; catch(finderexception e){ System.out.println("FinderException:"+e.getMessage()); return ""; jsp-sidan <jsp:usebean id="ab" class="adminbean" scope="session"/> <jsp:setproperty name="ab" property="*"/> <html><body><center> <h2>sökresultat:</h2><br> <%= ab.execute() %> <h2>addera student</h2> <form> Efternamn <input type=text name="enamn"> Förnamn <input type=text name="fnamn"> <input type=hidden name="action" value="addera"> <input type=submit value=" Addera "> </form> <h2>sök efter student</h2> <form> Efternamn <input type=text name="enamn"> Förnamn <input type=text name="fnamn"> <input type=hidden name="action" value="hitta"> <input type=submit value=" Hitta "> </form> </center></body></html> 5