750 likes | 873 Views
Disseny de la persistència JDO i frameworks de persistència. Toni Navarrete Enginyeria del Software II – UPF 200 4. Recordatori: problemes (i aventatges) d’altres solucions. Serialitzatió Avantantges: Estàndard en qualsevol ambient Java Fàcil d’utilitzar
E N D
Disseny de la persistència JDO i frameworks de persistència Toni Navarrete Enginyeria del Software II – UPF 2004
Recordatori: problemes (i aventatges) d’altres solucions • Serialitzatió • Avantantges: • Estàndard en qualsevol ambient Java • Fàcil d’utilitzar • El model de dades és directament el de les classes (aprofita OO) • Inconvenients: • No té les característiques d’un gestor de BD robust • Per exemple, índexs, transaccions,... • No és escalable
Recordatori: problemes (i aventatges) d’altres solucions • JDBC • Dóna accés a SQL • Usa el model relacional de SQL • No el model orientat a objectes de Java • Procedimental en lloc d’OO • El processament de dades es fa mitjançant SQL i no Java • Les operacions són expressades en relació a taules, files i columnes • SQL no està realment estandaritzat, amb la qual cosa la portabilitat no sempre és real
Recordatori: problemes (i aventatges) d’altres solucions • Quan s’utilitza JDBC, el programador està obligat a treballar amb dos models de dades diferents, així com amb dos paradigmes i llenguatges d’accés a les dades distints. • El resultat sol ser que s’escriu codi Java procedural per manipular les taules. No OO
Conseqüència • Moltes organitzacions comencen a desenvolupar el seu propi framework per a persistència i O/R mapping, que permeti els seus objectes interactuar amb la BD de forma transparent • Exemples • Castor • Apache ObJectRelationalBridge (OJB) • ODMG 3.0, desenvolupat pelObject Data Management Group (ODMG). Inicalment en C++ i Smaltalk, ha estat una de les bases de JDO i n’és un subconjunt
Problemes (i avantatges) d’altres solucions • ORM propietaris (Object-Relational Mapping) • Riscos significatius a l’hora de desenvolupar un ORM propi • Limitacions d’APIs ORM propietàries. Adoptar un API propietària és sempre arriscat. A moltes implementacions: • Falta d’encapsulació causada per la necessitat de definir mètodes getter i setter públics per als atributs persistents • Extensibilitat limitada per la falta de soport de l’herència • Falta de soport de referències polimòrfiques • Dependència absoluta d’un venedor
JDO • És una nova iniciativa de la comunitat Java per crear un framework estandaritzat per a persistència (de la mateixa que Swing ho és per a interfície gràfica) • JDO és només una especificació, de la qual els fabricants de software faran implementacions (a vegades lliures, a vegades no) • Normalment parlarem de JDO per accedir a BDR, però pot ser qualsevol forma d’emmagatzemantge permanent (XML, fitxers,...) • Sun produeix el JDORI (JDO Reference Implementation) com a una implementació per demostrar que l’especificació és vàlida. Però no està pensada per explotació en entorns reals
JDO • JDO: capacitats de BD de JDBC amb la integració Java de la serialització • JDO usa el model d’objectes Java • Les instàncies tenen un identificador únic (OID únic) • Soporta transaccions • Emmagatzemar instàncies, recuperar-les i modificar-es és transparent • Resum: mínima intrusió i màxima transparència
Comparació JDO amb les altres alternatives • EJB també defineix un mecanisme de persistència transparent (Container Managed Persistence, CMP), però EJB és una arquitectura complexa i amb més overhead que JDO • Serialització també és OO però no és apte per treballar amb grans volums de dades, no és escalable, i no té suport per índexs, transaccions i demés mecanismes d’un SGBD
JDO i JDBC • JDO no substituirà JDBC • Són complementàries • Les implementacions de JDO solen utilitzar JDBC per sota per connectar-se a la BD • JDBC és útil per gestionar connexions amb la BD • JDBC és força sòlid • JDBC està soportat per la majoria de fabricants de SGBC
JDO JDOcentral.com: A comparion between Java Data Objects (JDO), Serialization and JDBC for Java Persistance
Exemple d’una classe persistent amb JDO package es2; public class Persona { String nom, cognom; int anyNaixement = 0; public Persona() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Persona(String nom, String cognom, int anyNaixement) { this.nom = nom; this.cognom = cognom; this. anyNaixement = anyNaixement; } public void setNom(String nom) { this.nom = nom; } public String getNom() { return this.nom; } public void setCognom(String cognom) { this.cognom = cognom; } public String getCognom() { return this.cognom; } public void setAnyNaixement(int anyNaixement) { this. anyNaixement = anyNaixement; } public int getAnyNaixement() { return this.anyNaixement; } }
Declaració de classes persistents • L’únic requeriment és que la classe ha de tenir un constructor sense arguments • Ara podem crear instàncies d’aquesta classe Person i guardar-las a la BDR • JDO utilitza un fitxer de metadades per dir quines classes seran persistents i reflectir tota la informació relacionada amb la persistència (ho veurem amb més detall més endavant) • Fitxer amb extensió .jdo
Exemple de fitxer de metadades (es2.jdo) <?xml version= "1.0" encoding="UTF-8"?> <!DOCTYPE jdo SYSTEM "file:/C:/.../jdori-1_0/srcjavax/jdo/jdo.dtd"> <jdo> <package name= "es2" > <class name="Persona" /> </package> </jdo> o <!DOCTYPE jdo PUBLIC “-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "http://java.sun.com/dtd/jdo_1_0.dtd"> • Restricció: • El nom del fitxer és el del paquet (al directori arrel) o també es pot fer separat per classes (Persona.jdo en el nostre cas) i van dins del directori es2
Jars necessaris • JDO es pot baixar de www.jcp.org (JSR-12) • Per treballar amb la implementació de referència: • jdo.jar • Les interfícies estàndard i les classes definides a l’especificació JDO • jdori.jar • La implementació de referència de Sun • btree.jar • Implementa un petit gestor d’emmagatzament per la JDORI de Sun • jta.tar • Java Transaction API que usa JDO per definir transaccions • antlr.jar • Serveix per parsejar el llenguatges de consultes de JDO • xerces.jar • Per parsejar XML
Enhancement • Un cop que hem compilat la(s) classe(s), hem de fer un enhancement • Això sobre-escriu els fitxers de bytecode (.class) afegint dades i mètodes que permeten les instàncies de la classe ser manegades per la implementació JDO • Ho fa a partir del fitxer de metadades • Cada fabricant de JDO pot incloure el seu enhancer, però suposadament són compatibles • JDORI porta el reference enhancer
Enhancement • java com.sun.jdori.enhancer.Main es2.jdo es2/Persona.class • Algunes opcions: • -v (verbose) • -d (a un directori distint, sense sobreescriure el .class original): • java com.sun.jdori.enhancer.Main -v -d enhanced es2.jdo es2/Persona.class • Cada fabricant d’implementacions JDO té el seu enhancer que es crida de forma diferent • Noteu que l’enhancement és independent del magatzem de dades que utilitzem després
Fent una aplicació • Ara farem una aplicació que crea instàncies de Persona i les guarda a una BD • JDORI porta un petit gestor com a referència que es diu FOStore (File Object Store)
Estructura de classes de JDO • El nucli de JDO és la interfície PersistenceManager, que és la que manega la connexió amb un magatzem de dades
Estructura de classes de JDO • Per obtenir i configurar un PersistenceManager es fa mitjançant la interfície PersistenceManagerFactory • A la vegada, el PersistenceManagerFactory s’obté a partir d’un mètode estàtic de la classe JDOHelper, segons unes propietats (url de connexió, login, password i el nom de la implementació de JDO que utilitzem)
Estructura de classes de JDO • Exemple de propietats per crear un PersistenceManagerFactory: javax.jdo.PersistenceManagerFactoryClass=com.sun.jdori.fostore.FOStorePMF javax.jdo.option.ConnectionURL =fostore:database/fostoredb javax.jdo.option.ConnectionUserName=toni javax.jdo.option.ConnectionPassword=toni • Aquestes propietats poden estar a un fitxer (típciament jdo.properties) o ser configurades des de programa
Estructura de classes de JDO • Un PersistenceManager té associat una instància de la interfície JDO Transaction, per a controlar el començament i finalització d’una transacció • Per obtenir la instància de Transaction ho fem amb el mètode currentTransaction de la instància de PersistenceManager • En JDO tota acció que hagi de modificar la BD estarà emmarcada dins d’una transacció • Usarem els mètodes begin, commit i rollback de la instància de Transaction
FOStore • JDORI porta un petit gestor com a referència que es diu FOStore (File Object Store) • Anem a crear una BD per guardar les futures instàncies de la classe Persones • jdo.properties • Directori database • CreateDatabase.java
package es2; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; import javax.jdo.PersistenceManager; import javax.jdo.Transaction; public class CreateDatabase{ public static void main(String[] args){ create(); } public static void create(){ try{ InputStream propertyStream = new FileInputStream("es2/jdo.properties"); Properties jdoproperties = new Properties(); jdoproperties.load(propertyStream); jdoproperties.put("com.sun.jdori.option.ConnectionCreate","true"); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties); PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx = pm.currentTransaction(); tx.begin(); tx.commit(); } catch (Exception e) { System.err.println("Exception creating db"); e.printStackTrace(); System.exit(-1); } } } Creació d’una BD en FOStore • Aquest codi crea un magatzem al directori database • Propietat com.sun.jdori.option.ConnectionCreate a true
Creant l’aplicació package es2; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; import java.util.Map; import java.util.HashMap; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; import javax.jdo.PersistenceManager; import javax.jdo.Transaction; public class Aplicacio1{ protected PersistenceManagerFactory pmf; protected PersistenceManager pm; protected Transaction tx; public Aplicacio1() { try{ InputStream propertyStream = new FileInputStream("es2/jdo.properties"); Properties jdoproperties = new Properties(); jdoproperties.load(propertyStream); pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties); pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); } catch (Exception e) { System.err.println("Exception creating db"); e.printStackTrace(); System.exit(-1); } } public void executeTransaction() { try{ tx.begin(); Persona p = new Persona("toni","navarrete",1973); pm.makePersistent(p); tx.commit(); } catch (Throwable exception){ exception.printStackTrace(System.err); if (tx.isActive()) tx.rollback(); } } public static void main(String[] args) { Aplicacio1 ap = new Aplicacio1(); ap.executeTransaction(); } }
Sobre les propietats • També es poden especificar les propietats dins del codi: ... Properties props = new Properties(); props.setProperty("javax.jdo.PersistenceManagerFactoryClass", "com.sun.jdori.fostore.FOStorePMF "); props.setProperty("javax.jdo.option.ConnectionURL", "fostore:database/fostoredb"); props.setProperty("javax.jdo.option.ConnectionUserName",“toni"); props.setProperty("javax.jdo.option.ConnectionPassword",“toni"); props.setProperty("javax.jdo.option.Optimistic",“false"); pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties);
Creant l’aplicació amb una millor organització package es2; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; import javax.jdo.PersistenceManager; import javax.jdo.Transaction; public abstract class Aplicacio{ protected PersistenceManagerFactory pmf; protected PersistenceManager pm; protected Transaction tx; public abstract void execute(); public Aplicacio() { try{ InputStream propertyStream = new FileInputStream("es2/jdo.properties"); Properties jdoproperties = new Properties(); jdoproperties.load(propertyStream); pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties); pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); } catch (Exception e) { System.err.println("Exception creating db"); e.printStackTrace(); System.exit(-1); } } public void executeTransaction() { try{ tx.begin(); execute(); tx.commit(); } catch (Throwable exception){ exception.printStackTrace(System.err); if (tx.isActive()) tx.rollback(); } } } package es2; public class CrearPersones extends Aplicacio{ public static void main(String[] args) { CrearPersones cp = new CrearPersones(); cp.executeTransaction(); } public void execute() { Persona p1 = new Persona("pasqual","maragall",1950); pm.makePersistent(p1); Persona p2 = new Persona("artur","mas",1955); pm.makePersistent(p2); } }
Consultes • Extent és una interfície que permet accedir a totes les instàncies d’una classe persistent • Mètode getExtent del PersistenceManager Extent extent = pm.getExtent(Persona.class,false); /* el segon paràmetre indica si també considerar les instàncies de les subclasses */
Consulta de totes les persones emmagatzemades package es2; import java.util.Iterator; import javax.jdo.Extent; public class LlistatPersones extends Aplicacio{ public static void main(String[] args) { LlistatPersones lp = new LlistatPersones(); lp.executeTransaction(); } public void execute() { Extent extent = pm.getExtent(Persona.class,false); Iterator it = extent.iterator(); while (it.hasNext()) { Persona p = (Persona)it.next(); System.out.println("Nom: " + p.getNom()); System.out.println("Cognom: " + p.getCognom()); System.out.println("Any naixement: " + p.getAnyNaixement()); System.out.println(); } extent.close(it); } }
Consulta de totes les persones emmagatzemades (sense transacció) package es2; import java.util.Iterator; import javax.jdo.Extent; public class LlistatPersones extends Aplicacio{ public static void main(String[] args) { LlistatPersones lp = new LlistatPersones(); lp.consulta(); } public void consulta() { Extent extent = pm.getExtent(Persona.class,false); Iterator it = extent.iterator(); while (it.hasNext()) { Persona p = (Persona)it.next(); System.out.println("Nom: " + p.getNom()); System.out.println("Cognom: " + p.getCognom()); System.out.println("Any naixement: " + p.getAnyNaixement()); System.out.println(); } extent.close(it); } public void execute() {} }
Consultes i filtres • La interfície Query permet definir filtres sobre un Extent, per fer consultes més específiques (i no de tots els elements) • Quan es crea una Query s’especifica l’Extent i la condició: Query q = pm.newQuery(extent,"nom == nomPersona"); q.declareParameters("String nomPersona"); • També es pot crear la Query directament sobre la classe: Query q = pm.newQuery(Persona.class,"nom==\"toni\""); • En especificar la condició podem utilitzar els operadors comparatius, aritmètics,... de Java
Consulta del cognom d’una persona concreta package es2; import java.util.Iterator; import java.util.Collection; import javax.jdo.Extent; import javax.jdo.Query; public class CognomPersona extends Aplicacio{ public static void main(String[] args) { CognomPersona cp = new CognomPersona(); cp.executeTransaction(); } public void execute() { Extent extent = pm.getExtent(Persona.class,false); String nomPersona = new String("toni"); Query q = pm.newQuery(extent,"nom == nomPersona"); q.declareParameters("String nomPersona"); Collection result = (Collection)q.execute(nomPersona); Iterator it = result.iterator(); if (it.hasNext()) { Persona p = (Persona)it.next(); System.out.println("Nom: " + p.getNom()); System.out.println("Cognom: " + p.getCognom()); System.out.println("Any naixement: " + p.getAnyNaixement()); } q.close(result); } }
Més coses • Treballar amb un gestor de veritat • Una altra implementació de JDO: JPOX • És opensource i té suport per treballar amb nombrosos SGBDs (MySQL, PostgreSQL i Oracle entre d’altres) • Associacions entre classes (relacions entre taules) i herència • Generació automàtica de l’esquema de la BD • Capacitat per configurar el mapping objecte/relacional a l’hora de crear les taules • Permet: • Insercions, eliminacions i modificacions d’objectes • Consultes • Persistència transitiva
Un exemple més complet (amb JPOX) Grup Persona 0..* 0..1 Empleat
Persona package es2; public class Persona { String nom, cognom; int anyNaixement = 0; Grup grupp; public Persona() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Persona(String nom, String cognom, int anyNaixement) { this.nom = nom; this.cognom = cognom; this. anyNaixement = anyNaixement; } public void setNom(String nom) { this.nom = nom; } public String getNom() { return this.nom; } public void setCognom(String cognom) { this.cognom = cognom; } public String getCognom() { return this.cognom; } public void setAnyNaixement(int anyNaixement) { this. anyNaixement = anyNaixement; } public int getAnyNaixement() { return this.anyNaixement; } public void setGrup(Grup g) { this.grupp = g; } public Grup getGrup() { return this.grupp; } }
Grup package es2; import java.util.*; public class Grup{ String nom; Set persones; public Grup() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Grup(String nom){ this.nom=nom; this.persones=new HashSet(); } public void setNom(String nom){ this.nom = nom; } public String getNom() { return this.nom; } public void afegeixPersona(Persona p) { this.persones.add(p); p.setGrup(this); } public Set getPersones() { return this.persones; } } Suporta diversos tipus per a les col·leccions: • Collection • Set • HashSet • Map • List • ArrayList • HashMap • Hashtable • LinkedList • TreeMap • TreeSet • Vector
Empleat package es2; public class Empleat extends Persona{ int salari; public Empleat() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Empleat(String nom, String cognom, int anyNaixement, int salari) { this.nom = nom; this.cognom = cognom; this.anyNaixement = anyNaixement; this.salari=salari; } public void setSalari(int salari) { this.salari = salari; } public int getSalari() { return this.salari; } }
Fitxer de metadades (package.jdo) <?xml version="1.0"?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "http://java.sun.com/dtd/jdo_1_0.dtd"> <jdo> <package name="es2"> <class name="Persona"> <field name="grupp" persistence-modifier="persistent" /> </class> <class name="Empleat" persistence-capable-superclass="es2.Persona"/> <class name="Grup"> <field name="persones" mapped-by="grupp"> <collection element-type="es2.Persona"/> </field> </class> </package> </jdo> • Comanda d’Enhancement: java -cp "build;lib/jpox.jar;lib/jpox-enhancer.jar;lib/bcel.jar;lib/jdo.jar; lib/log4j.jar" org.jpox.enhancer.JPOXEnhancer build/es2/package.jdo
Extensions als elements de metadades • Els fabricants d’implementacions JDO poden crear les seves extensions als elements del fitxers de metadades • Lògicament no seran portables a altres implementacions • Es poden definir paràmetres referents a com emmagatzemar les dades, com per exemple crear índexs, definir primary-keys, especificar longituds de strings,... • Exemple: <field name="name"> <extension vendor-name="jpox“key="length" value="max 100"/> </field>
Tractament de les relacions. Relacions 1 a 1 • Single-ended <package name="mydomain"> <class name="User" identity-type="datastore"> <field name="login" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 20"/> </field> </class> <class name="Account" identity-type="datastore"> <field name="firstName" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="secondName" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="user" persistence-modifier="persistent"> </field> </class> </package>
Tractament de les relacions. Relacions 1 a 1 • Double-ended <package name="mydomain"> <class name="User" identity-type="datastore"> <field name="login" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 20"/> </field> <field name="account" persistence-modifier="persistent"> </field> </class> <class name="Account" identity-type="datastore"> <field name="firstName" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="secondName" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="user" persistence-modifier="persistent"> </field> </class> </package>
Tractament de les relacions. Relacions 1 a N • Normal (amb Set): <package name="mydomain"> <class name="Address" identity-type="datastore"> <field name="city" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="street" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> </class> <class name="Account" identity-type="datastore"> <field name="firstname" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 100"/> </field> <field name="lastname" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 100"/> </field> <field name="addresses" persistence-modifier="persistent"> <collection element-type="mydomain.Address"/> </field> </class> </package>
Tractament de les relacions. Relacions 1 a N • Inverse-bidirectional (amb Set): <package name="mydomain"> <class name="Address" identity-type="datastore"> <field name="city" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="street" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="account" persistence-modifier="persistent"> <extension vendor-name="jpox" key="collection-field" value="addresses"/> </field> </class> <class name="Account" identity-type="datastore"> <field name="firstname" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 100"/> </field> <field name="lastname" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 100"/> </field> <field name="addresses" persistence-modifier="persistent"> <collection element-type="mydomain.Address"> <extension vendor-name="jpox" key="owner-field" value="account"/> <collection/> </field> </class> </package>
Tractament de les relacions. Relacions M a N • Amb dues taules de join (amb Set): <package name="mydomain"> <class name="Product" identity-type="datastore"> <field name="name" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="price" persistence-modifier="persistent"> </field> <field name="suppliers" persistence-modifier="persistent"> <collection element-type="mydomain.Supplier"> <collection/> </field> </class> <class name="Supplier" identity-type="datastore"> <field name="name" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 100"/> </field> <field name="products" persistence-modifier="persistent"> <collection element-type="mydomain.Product"> <collection/> </field> </class> </package>
Tractament de les relacions. Relacions M a N • Amb només una taula de join (amb Set): <package name="mydomain"> <class name="Product" identity-type="datastore"> <field name="name" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 50"/> </field> <field name="price" persistence-modifier="persistent"> </field> <field name="suppliers" persistence-modifier="persistent"> <collection element-type="mydomain.Supplier"> <extension vendor-name="jpox" key="table-name" value="PRODUCTS_SUPPLIERS"/> <extension vendor-name="jpox" key="owner-column-name" value="PRODUCT_ID"/> <extension vendor-name="jpox" key="element-column-name" value="SUPPLIER_ID"/> <collection/> </field> </class> <class name="Supplier" identity-type="datastore"> <field name="name" persistence-modifier="persistent"> <extension vendor-name="jpox" key="length" value="max 100"/> </field> <field name="products" persistence-modifier="persistent"> <collection element-type="mydomain.Product"> <extension vendor-name="jpox" key="table-name" value="PRODUCTS_SUPPLIERS"/> <extension vendor-name="jpox" key="owner-column-name" value="SUPPLIER_ID"/> <extension vendor-name="jpox" key="element-column-name" value="PRODUCT_ID"/> <collection/> </field> </class> </package>
Tractament de l’herència • Utilitza una taula per a cada classe de l’arbre d’herència, on cada taula contindrà només els atributs propis de la classe (no duplicació d’atributs a diferents classes) • Recordatori: solució 3 del tema “Disseny de la persistència. Introducció i mapping objecte/relacional” • S’espera que en futures versions sigui configurable. Altres implementacions de JDO ho permeten
Tractament de l’herència • Exemple: <package name="org.jpox.sample.store"> <class name="Product"> <field name="name"> <extension vendor-name="jpox" key="length" value="max 100"/> </field> <field name="description"> <extension vendor-name="jpox" key="length" value="max 255"/> </field> <field name="price"/> </class> <class name="Book" persistence-capable-superclass="org.jpox.samples.store.Product"> <field name="isbn"> <extension vendor-name="jpox" key="length" value="max 20"/> </field> <field name="author"> <extension vendor-name="jpox" key="length" value="max 40"/> </field> <field name="title"> <extension vendor-name="jpox" key="length" value="max 40"/> </field> </class> <class name="TravelGuide" persistence-capable-superclass="org.jpox.samples.store.Book"> <field name="country"> <extension vendor-name="jpox" key="length" value="max 40"/> </field> </class> <class name="CompactDisc" persistence-capable-superclass="org.jpox.samples.store.Product"> <field name="artist"> <extension vendor-name="jpox" key="length" value="max 40"/> </field> <field name="title"> <extension vendor-name="jpox" key="length" value="max 40"/> </field> </class> </package>