• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/timemachine/db-4.7.25.NC/java/src/com/sleepycat/persist/
1<!-- $Id: package.html,v 1.1 2008/02/07 17:12:26 mark Exp $ -->
2<html>
3<body>
4The Direct Persistence Layer (DPL) adds a persistent object model to the
5Berkeley DB transactional engine.
6
7<h1>Package Specification</h1>
8
9<ul>
10<li><a href="#intro">Introduction</a></li>
11<li><a href="#model">The Entity Model</a></li>
12<li><a href="#example">A brief example</a></li>
13<li><a href="#whichAPI">Which API to use?</a></li>
14<li><a href="#java14and15">Java 1.5 dependencies</a>
15    <ul>
16    <li><a href="#genericTypes">Generic Types</a></li>
17    <li><a href="#annotations">Annotations</a></li>
18    </ul>
19</li>
20<li><a href="#bytecode">Bytecode Enhancement</a></li>
21</ul>
22
23<a name="intro"><h2>Introduction</h2></a>
24
25<p>The Direct Persistence Layer (DPL) was designed to meet the following
26requirements.</p>
27<ul>
28<li>A type safe and convenient API is provided for accessing persistent
29objects.  The use of Java generic types, although optional, is fully exploited
30to provide type safety.  For example:
31<pre class="code">
32{@literal PrimaryIndex<Long,Employer> employerById = ...;}
33long employerId = ...;
34Employer employer = employerById.get(employerId);</pre>
35</li>
36<li>All Java types are allowed to be persistent without requiring that they
37implement special interfaces.  Persistent fields may be {@code private},
38package-private (default access), {@code protected}, or {@code public}.  No
39hand-coding of bindings is required.  However, each persistent class must have
40a default constructor.  For example:
41<pre class="code">
42{@literal @Persistent}
43class Address {
44    String street;
45    String city;
46    String state;
47    int zipCode;
48    private Address() {}
49}</pre>
50</li>
51<li>Bytecode enhancement provides fully optimized bindings that do not use Java
52reflection.</li>
53<li>It is easy to define primary and secondary keys.  No external schema is
54required and Java annotations may be used for defining all metadata.
55Extensions may derive metadata from other sources.  For example, the following
56Employer class is defined as a persistent entity with a primary key field
57{@code id} and the secondary key field {@code name}:</li>
58<pre class="code">
59{@literal @Entity}
60class Employer {
61
62    {@literal @PrimaryKey(sequence="ID")}
63    long id;
64
65    {@literal @SecondaryKey(relate=ONE_TO_ONE)}
66    String name;
67
68    Address address;
69
70    private Employer() {}
71}</pre>
72<li>Interoperability with external components is supported via the Java
73collections framework.  Any primary or secondary index can be accessed using a
74standard <code>java.util</code> collection.  For example:
75<pre class="code">{@literal java.util.SortedMap<String,Employer> map = employerByName.sortedMap();}</pre>
76</li>
77<li>Class evolution is explicitly supported.  Compatible changes (adding fields
78and type widening) are performed automatically and transparently.  For example,
79without any special configuration a {@code street2} field may be added to the
80{@code Address} class and the type of the {@code zipCode} field may be changed
81from {@code int} to {@code long}:
82<pre class="code">
83{@literal @Persistent}
84class Address {
85    String street;
86    String street2;
87    String city;
88    String state;
89    long zipCode;
90    private Address() {}
91}</pre>
92Many incompatible class changes, such as renaming fields or refactoring a
93single class, can be performed using {@link
94com.sleepycat.persist.evolve.Mutations Mutations}.  Mutations are automatically
95applied lazily as data is accessed, avoiding downtime to convert large
96databases during a software upgrade.
97<p>Complex refactoring involving multiple classes may be performed using the a
98<a href="package-summary.html#storeConversion">store conversion</a>.  The DPL
99always provides access to your data via a {@code RawStore}, no matter what
100changes have been made to persistent classes.</p>
101</li>
102<br>
103<li>The performance of the Berkeley DB transactional engine is not compromised.
104Operations are internally mapped directly to the engine API, object bindings
105are lightweight, and all engine tuning parameters are available.  For example,
106a "dirty read" may be performed using an optional {@link
107com.sleepycat.db.LockMode LockMode} parameter:
108<pre class="code">Employer employer = employerByName.get(null, "Gizmo Inc", LockMode.READ_UNCOMMITTED);</pre>
109For high performance applications, {@link com.sleepycat.db.DatabaseConfig
110DatabaseConfig} parameters may be used to tune the performance of the Berkeley
111DB engine.  For example, the size of an internal Btree node can be specified
112as follows:
113<pre class="code">
114DatabaseConfig config = store.getPrimaryConfig(Employer.class);
115config.setNodeMaxEntries(64);
116store.setPrimaryConfig(config);</pre>
117</li>
118</ul>
119
120<a name="model"><h2>The Entity Model</h2></a>
121
122<p>The DPL is intended for applications that represent persistent domain
123objects using Java classes.  An <em>entity class</em> is an ordinary Java class
124that has a primary key and is stored and accessed using a primary index.  It
125may also have any number of secondary keys, and entities may be accessed by
126secondary key using a secondary index.</p>
127
128<p>An entity class may be defined with the {@link
129com.sleepycat.persist.model.Entity Entity} annotation.  For each entity class,
130its primary key may be defined using the {@link
131com.sleepycat.persist.model.PrimaryKey PrimaryKey} annotation and any number of
132secondary keys may be defined using the {@link
133com.sleepycat.persist.model.SecondaryKey SecondaryKey} annotation.</p>
134
135<p>In the following example, the {@code Person.ssn} (social security number)
136field is the primary key and the {@code Person.employerIds} field is a
137many-to-many secondary key.</p>
138<pre class="code">
139{@literal @Entity}
140class Person {
141
142    {@literal @PrimaryKey}
143    String ssn;
144
145    String name;
146    Address address;
147
148    {@literal @SecondaryKey(relate=MANY_TO_MANY, relatedEntity=Employer.class)}
149    {@literal Set<Long> employerIds = new HashSet<Long>();}
150
151    private Person() {} // For bindings
152}</pre>
153
154<p>A set of entity classes constitutes an <em>entity model</em>.  In addition
155to isolated entity classes, an entity model may contain relationships between
156entities.  Relationships may be defined using the {@link
157com.sleepycat.persist.model.SecondaryKey SecondaryKey} annotation.
158Many-to-one, one-to-many, many-to-many and one-to-one relationships are
159supported, as well as foreign key constraints.</p>
160
161<p>In the example above, a relationship between the {@code Person} and {@code
162Employer} entities is defined via the {@code Person.employerIds} field.  The
163{@code relatedEntity=Employer.class} annotation property establishes foreign
164key constraints to guarantee that every element of the {@code employerIds} set
165is a valid {@code Employer} primary key.</p>
166
167<p>For more information on the entity model, see the {@link
168com.sleepycat.persist.model.AnnotationModel AnnotationModel} and the {@link
169com.sleepycat.persist.model.Entity Entity} annotation.</p>
170
171<p>The root object in the DPL is the {@link com.sleepycat.persist.EntityStore
172EntityStore}.  An entity store manages any number of objects for each entity
173class defined in the model.  The store provides access to the primary and
174secondary indices for each entity class, for example:</p>
175
176<pre class="code">
177EntityStore store = new EntityStore(...);
178
179{@literal PrimaryIndex<String,Person> personBySsn} =
180    store.getPrimaryIndex(String.class, Person.class);</pre>
181
182<a name="example"><h2>A brief example</h2></a>
183
184<p>The following example shows how to define an entity model and how to store
185and access persistent objects.  Exception handling is omitted for brevity.</p>
186
187<pre class="code">
188import java.io.File;
189import java.util.HashSet;
190import java.util.Set;
191
192import com.sleepycat.db.DatabaseException;
193import com.sleepycat.db.Environment;
194import com.sleepycat.db.EnvironmentConfig;
195import com.sleepycat.persist.EntityCursor;
196import com.sleepycat.persist.EntityIndex;
197import com.sleepycat.persist.EntityStore;
198import com.sleepycat.persist.PrimaryIndex;
199import com.sleepycat.persist.SecondaryIndex;
200import com.sleepycat.persist.StoreConfig;
201import com.sleepycat.persist.model.Entity;
202import com.sleepycat.persist.model.Persistent;
203import com.sleepycat.persist.model.PrimaryKey;
204import com.sleepycat.persist.model.SecondaryKey;
205import static com.sleepycat.persist.model.DeleteAction.NULLIFY;
206import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
207import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY;
208import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
209import static com.sleepycat.persist.model.Relationship.MANY_TO_MANY;
210
211// An entity class.
212//
213{@literal @Entity}
214class Person {
215
216    {@literal @PrimaryKey}
217    String ssn;
218
219    String name;
220    Address address;
221
222    {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Person.class)}
223    String parentSsn;
224
225    {@literal @SecondaryKey(relate=ONE_TO_MANY)}
226    {@literal Set<String> emailAddresses = new HashSet<String>();}
227
228    {@code @SecondaryKey(relate=MANY_TO_MANY, relatedEntity=Employer.class,
229                                       onRelatedEntityDelete=NULLIFY)}
230    {@code Set<Long> employerIds = new HashSet<Long>();}
231
232    Person(String name, String ssn, String parentSsn) {
233        this.name = name;
234        this.ssn = ssn;
235        this.parentSsn = parentSsn;
236    }
237
238    private Person() {} // For bindings
239}
240
241// Another entity class.
242//
243{@literal @Entity}
244class Employer {
245
246    {@literal @PrimaryKey(sequence="ID")}
247    long id;
248
249    {@literal @SecondaryKey(relate=ONE_TO_ONE)}
250    String name;
251
252    Address address;
253
254    Employer(String name) {
255        this.name = name;
256    }
257
258    private Employer() {} // For bindings
259}
260
261// A persistent class used in other classes.
262//
263{@literal @Persistent}
264class Address {
265    String street;
266    String city;
267    String state;
268    int zipCode;
269    private Address() {} // For bindings
270}
271
272// The data accessor class for the entity model.
273//
274class PersonAccessor {
275
276    // Person accessors
277    //
278    {@literal PrimaryIndex<String,Person> personBySsn;}
279    {@literal SecondaryIndex<String,String,Person> personByParentSsn;}
280    {@literal SecondaryIndex<String,String,Person> personByEmailAddresses;}
281    {@literal SecondaryIndex<Long,String,Person> personByEmployerIds;}
282
283    // Employer accessors
284    //
285    {@literal PrimaryIndex<Long,Employer> employerById;}
286    {@literal SecondaryIndex<String,Long,Employer> employerByName;}
287
288    // Opens all primary and secondary indices.
289    //
290    public PersonAccessor(EntityStore store)
291        throws DatabaseException {
292
293        personBySsn = store.getPrimaryIndex(
294            String.class, Person.class);
295
296        personByParentSsn = store.getSecondaryIndex(
297            personBySsn, String.class, "parentSsn");
298
299        personByEmailAddresses = store.getSecondaryIndex(
300            personBySsn, String.class, "emailAddresses");
301
302        personByEmployerIds = store.getSecondaryIndex(
303            personBySsn, Long.class, "employerIds");
304
305        employerById = store.getPrimaryIndex(
306            Long.class, Employer.class);
307
308        employerByName = store.getSecondaryIndex(
309            employerById, String.class, "name"); 
310    }
311}
312
313// Open a transactional Berkeley DB engine environment.
314//
315EnvironmentConfig envConfig = new EnvironmentConfig();
316envConfig.setAllowCreate(true);
317envConfig.setTransactional(true);
318Environment env = new Environment(new File("/my/data"), envConfig);
319
320// Open a transactional entity store.
321//
322StoreConfig storeConfig = new StoreConfig();
323storeConfig.setAllowCreate(true);
324storeConfig.setTransactional(true);
325EntityStore store = new EntityStore(env, "PersonStore", storeConfig);
326
327// Initialize the data access object.
328//
329PersonAccessor dao = new PersonAccessor(store);
330
331// Add a parent and two children using the Person primary index.  Specifying a
332// non-null parentSsn adds the child Person to the sub-index of children for
333// that parent key.
334//
335dao.personBySsn.put(new Person("Bob Smith", "111-11-1111", null));
336dao.personBySsn.put(new Person("Mary Smith", "333-33-3333", "111-11-1111"));
337dao.personBySsn.put(new Person("Jack Smith", "222-22-2222", "111-11-1111"));
338
339// Print the children of a parent using a sub-index and a cursor.
340//
341{@literal EntityCursor<Person> children =}
342    dao.personByParentSsn.subIndex("111-11-1111").entities();
343try {
344    for (Person child : children) {
345        System.out.println(child.ssn + ' ' + child.name);
346    }
347} finally {
348    children.close();
349}
350
351// Get Bob by primary key using the primary index.
352//
353Person bob = dao.personBySsn.get("111-11-1111");
354assert bob != null;
355
356// Create two employers.  Their primary keys are assigned from a sequence.
357//
358Employer gizmoInc = new Employer("Gizmo Inc");
359Employer gadgetInc = new Employer("Gadget Inc");
360dao.employerById.put(gizmoInc);
361dao.employerById.put(gadgetInc);
362
363// Bob has two jobs and two email addresses.
364//
365bob.employerIds.add(gizmoInc.id);
366bob.employerIds.add(gadgetInc.id);
367bob.emailAddresses.add("bob@bob.com");
368bob.emailAddresses.add("bob@gmail.com");
369
370// Update Bob's record.
371//
372dao.personBySsn.put(bob);
373
374// Bob can now be found by both email addresses.
375//
376bob = dao.personByEmailAddresses.get("bob@bob.com");
377assert bob != null;
378bob = dao.personByEmailAddresses.get("bob@gmail.com");
379assert bob != null;
380
381// Bob can also be found as an employee of both employers.
382//
383{@literal EntityIndex<String,Person> employees;}
384employees = dao.personByEmployerIds.subIndex(gizmoInc.id);
385assert employees.contains("111-11-1111");
386employees = dao.personByEmployerIds.subIndex(gadgetInc.id);
387assert employees.contains("111-11-1111");
388
389// When an employer is deleted, the onRelatedEntityDelete=NULLIFY for the
390// employerIds key causes the deleted ID to be removed from Bob's employerIds.
391//
392dao.employerById.delete(gizmoInc.id);
393bob = dao.personBySsn.get("111-11-1111");
394assert !bob.employerIds.contains(gizmoInc.id);
395
396store.close();
397env.close();
398</pre>
399<p>The example illustrates several characteristics of the DPL:</p>
400<ul>
401<li>Persistent data and keys are defined in terms of instance fields.  For
402brevity the example does not show getter and setter methods, although these
403would normally exist to provide encapsulation.  The DPL accesses fields during
404object serialization and deserialization, rather than calling getter/setter
405methods, leaving business methods free to enforce arbitrary validation rules.
406For example: 
407<pre class="code">
408{@literal @Persistent}
409public class ConstrainedValue {
410
411    private int min;
412    private int max;
413    private int value;
414
415    private ConstrainedValue() {} // For bindings
416
417    public ConstrainedValue(int min, int max) {
418        this.min = min;
419        this.max = max;
420        value = min;
421    }
422
423    public setValue(int value) {
424        if (value &lt; min || value &gt; max) {
425            throw new IllegalArgumentException("out of range");
426        }
427        this.value = value;
428    }
429}
430</pre>
431The above {@code setValue} method would not work if it were called during
432object deserialization, since the order of setting fields is arbitrary.  The
433{@code min} and {@code max} fields may not be set before the {@code value} is
434set.
435</li>
436<br>
437<li>The example creates a transactional store and therefore all operations are
438transaction protected.  Because no explicit transactions are used, auto-commit
439is used implicitly.
440
441<p>Explicit transactions may also be used to group multiple operations in a
442single transaction, and all access methods have optional transaction
443parameters.  For example, the following two operations are performed atomically
444in a transaction:
445<pre class="code">
446Transaction txn = env.beginTransaction(null, null);
447dao.employerById.put(txn, gizmoInc);
448dao.employerById.put(txn, gadgetInc);
449txn.commit();
450</pre>
451</li>
452<li>To provide maximum performance, the DPL operations map directly to the
453Btree operations of the Berkeley DB engine.  Unlike other persistence
454approaches, keys and indices are exposed for direct access and performance
455tuning.
456<p>Queries are implemented by calling methods of the primary and secondary
457indices.  An {@link com.sleepycat.persist.EntityJoin EntityJoin} class is also
458available for performing equality joins.  For example, the following code
459queries all of Bob's children that work for Gizmo Inc:
460<pre class="code">
461{@literal EntityJoin<String,Person> join = new EntityJoin(dao.personBySsn);}
462
463join.addCondition(dao.personByParentSsn, "111-11-1111");
464join.addCondition(dao.personByEmployerIds, gizmoInc.id);
465
466{@literal ForwardCursor<Person> results = join.entities();}
467try {
468    for (Person person : results) {
469        System.out.println(person.ssn + ' ' + person.name);
470    }
471} finally {
472    results.close();
473}
474</li>
475<li>Object relationships are based on keys.  When a {@code Person} with a given
476employer ID in its {@code employerIds} set is stored, the {@code Person} object
477becomes part of the collection of employees for that employer.  This collection
478of employees is accessed using a {@link
479com.sleepycat.persist.SecondaryIndex#subIndex SecondaryIndex.subIndex} for the
480employer ID, as shown below:
481<pre class="code">
482{@literal EntityCursor<Person> employees =}
483    dao.personByEmployerIds.subIndex(gizmoInc.id).entities();
484try {
485    for (Person employee : employees) {
486        System.out.println(employee.ssn + ' ' + employee.name);
487    }
488} finally {
489    employees.close();
490}
491</pre></li>
492<li>Note that when Bob's employer is deleted in the example, the {@code Person}
493object for Bob is refetched to see the change to its {@code employerIds}.  This
494is because objects are accessed by value, not by reference.  In other words, no
495object cache or "persistence context" is maintained by the DPL.  The low level
496caching of the embedded Berkeley DB engine, combined with lightweight object
497bindings, provides maximum performance.</li>
498</ul>
499
500<a name="whichAPI"><h2>Which API to use?</h2></a>
501
502<p>The Berkeley DB engine has a {@link com.sleepycat.db Base API}, a {@link
503com.sleepycat.collections Collections API} and a {@link com.sleepycat.persist
504Direct Persistence Layer (DPL)}.  Follow these guidelines if you are not sure
505which API to use:</p>
506<ul>
507<li>When Java classes are used to represent domain objects in an application,
508the DPL is recommended.  The more domain classes, the more value there is in
509using annotations to define your schema.</li>
510<br>
511<li>When porting an application between Berkeley DB and Berkeley DB Java
512Edition, or when you've chosen not to use Java classes to represent domain
513objects, then the Base API is recommended.  You may also prefer to use this API
514if you have very few domain classes.</li>
515<br>
516<li>The Collections API is useful for interoperating with external components
517because it conforms to the standard Java Collections Framework.  It is
518therefore useful in combination with both the Base API and the DPL.  You may
519prefer this API because it provides the familiar Java Collections
520interface.</li>
521</ul>
522
523<a name="java14and15"><h2>Java 1.5 dependencies</h2></a>
524
525<p><em>NOTE:</em> The current release of the DPL requires compiling and
526deploying with Java 1.5 or greater.  Support for Java 1.4 may be added in a
527future release, based on user demand.</p>
528
529<p>The DPL uses two features of Java 1.5: generic types and annotations.  If
530you wish to avoid using these two Java 1.5 features, the DPL provides options
531for doing so.</p>
532
533<a name="genericTypes"><h3>Generic Types</h3></a>
534
535<p>Generic types are used to provide type safety, especially for the {@link
536com.sleepycat.persist.PrimaryIndex PrimaryIndex}, {@link
537com.sleepycat.persist.SecondaryIndex SecondaryIndex}, and {@link
538com.sleepycat.persist.EntityCursor EntityCursor} classes.  If you don't wish to
539use generic types, you can simply not declare your index and cursor objects
540using generic type parameters.  This is the same as using the Java 1.5
541Collections Framework without using generic types.</p>
542
543<a name="annotations"><h3>Annotations</h3></a>
544
545<p>If you don't wish to use annotations, you can provide another source of
546metadata by implementing an {@link com.sleepycat.persist.model.EntityModel
547EntityModel} class.  For example, naming conventions, static members, or an XML
548configuration file might be used as a source of metadata.  However, if you
549don't use annotations then you won't be able to use bytecode enhancement, which
550is described next.</p>
551
552<a name="bytecode"><h2>Bytecode Enhancement</h2></a>
553
554<p>The persistent fields of a class may be private, package-private, protected
555or public.  The DPL can access persistent fields either by bytecode enhancement
556or by reflection.</p>
557
558<p>Bytecode enhancement may be used to fully optimize binding performance and
559to avoid the use of Java reflection.  In applications that are CPU bound,
560avoiding Java reflection can have a significant performance impact.</p>
561
562<p>Bytecode enhancement may be performed either at runtime or at build time
563(offline).  When enhancement is performed at runtime, persistent classes are
564enhanced as they are loaded.  When enhancement is performed offline, class
565files are enhanced during a post-compilation step.
566Enhanced classes are used to efficiently access all fields and default
567constructors, including non-public members.</p>
568
569<p>See {@link com.sleepycat.persist.model.ClassEnhancer ClassEnhancer} for
570bytecode enhancement configuration details.</p>
571
572<p>If bytecode enhancement is not used as described above, the DPL will use
573reflection for accessing persistent fields and the default constructor.  The
574{@link java.lang.reflect.AccessibleObject#setAccessible
575AccessibleObject.setAccessible} method is called by the DPL to enable access to
576non-public fields and constructors.  If you are running under a Java security
577manager you must configure your security policy to allow the following
578permission:</p>
579
580<p>{@code permission java.lang.reflect.ReflectPermission "suppressAccessChecks";}
581
582<p>There are three cases where setting the above permission is <em>not</em>
583required:</p>
584<ol>
585<li>If you are not running under a Java Security Manager, then access to
586non-public members via reflection is not restricted.  This is the default for
587J2SE.</li>
588<br>
589<li>If all persistent fields and default constructors are {@code public} then
590they can be accessed via reflection without special permissions, even when
591running under a Java Security Manager.  However, declaring {@code public}
592instance fields is not recommended because it discourages encapsulation.</li>
593<br>
594<li>If bytecode enhancement is used as described above, then reflection will
595not be used.</li>
596</ol>
597
598<p>It is well known that executing generated code is faster than reflection.
599However, this performance difference may or may not impact a given application
600since it may be overshadowed by other factors.  Performance testing in a
601realistic usage scenario is the best way to determine the impact.  If you are
602determined to avoid the use of reflection then option 3 above is
603recommended.</p>
604
605</body>
606</html>
607