1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: PersonExample.java,v 1.1 2008/02/07 17:12:24 mark Exp $
7 */
8
9package persist;
10
11import java.io.File;
12import java.io.FileNotFoundException;
13import java.util.HashSet;
14import java.util.Set;
15
16import com.sleepycat.db.DatabaseException;
17import com.sleepycat.db.Environment;
18import com.sleepycat.db.EnvironmentConfig;
19import com.sleepycat.persist.EntityCursor;
20import com.sleepycat.persist.EntityIndex;
21import com.sleepycat.persist.EntityStore;
22import com.sleepycat.persist.PrimaryIndex;
23import com.sleepycat.persist.SecondaryIndex;
24import com.sleepycat.persist.StoreConfig;
25import com.sleepycat.persist.model.Entity;
26import com.sleepycat.persist.model.Persistent;
27import com.sleepycat.persist.model.PrimaryKey;
28import com.sleepycat.persist.model.SecondaryKey;
29import static com.sleepycat.persist.model.DeleteAction.NULLIFY;
30import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
31import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY;
32import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
33import static com.sleepycat.persist.model.Relationship.MANY_TO_MANY;
34
35public class PersonExample {
36
37    /* An entity class. */
38    @Entity
39    static class Person {
40
41        @PrimaryKey
42        String ssn;
43
44        String name;
45        Address address;
46
47        @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Person.class)
48        String parentSsn;
49
50        @SecondaryKey(relate=ONE_TO_MANY)
51        Set<String> emailAddresses = new HashSet<String>();
52
53        @SecondaryKey(relate=MANY_TO_MANY,
54                      relatedEntity=Employer.class,
55                      onRelatedEntityDelete=NULLIFY)
56        Set<Long> employerIds = new HashSet<Long>();
57
58        Person(String name, String ssn, String parentSsn) {
59            this.name = name;
60            this.ssn = ssn;
61            this.parentSsn = parentSsn;
62        }
63
64        private Person() {} // For deserialization
65    }
66
67    /* Another entity class. */
68    @Entity
69    static class Employer {
70
71        @PrimaryKey(sequence="ID")
72        long id;
73
74        @SecondaryKey(relate=ONE_TO_ONE)
75        String name;
76
77        Address address;
78
79        Employer(String name) {
80            this.name = name;
81        }
82
83        private Employer() {} // For deserialization
84    }
85
86    /* A persistent class used in other classes. */
87    @Persistent
88    static class Address {
89        String street;
90        String city;
91        String state;
92        int zipCode;
93        private Address() {} // For deserialization
94    }
95
96    /* The data accessor class for the entity model. */
97    static class PersonAccessor {
98
99        /* Person accessors */
100        PrimaryIndex<String,Person> personBySsn;
101        SecondaryIndex<String,String,Person> personByParentSsn;
102        SecondaryIndex<String,String,Person> personByEmailAddresses;
103        SecondaryIndex<Long,String,Person> personByEmployerIds;
104
105        /* Employer accessors */
106        PrimaryIndex<Long,Employer> employerById;
107        SecondaryIndex<String,Long,Employer> employerByName;
108
109        /* Opens all primary and secondary indices. */
110        public PersonAccessor(EntityStore store)
111            throws DatabaseException {
112
113            personBySsn = store.getPrimaryIndex(
114                String.class, Person.class);
115
116            personByParentSsn = store.getSecondaryIndex(
117                personBySsn, String.class, "parentSsn");
118
119            personByEmailAddresses = store.getSecondaryIndex(
120                personBySsn, String.class, "emailAddresses");
121
122            personByEmployerIds = store.getSecondaryIndex(
123                personBySsn, Long.class, "employerIds");
124
125            employerById = store.getPrimaryIndex(
126                Long.class, Employer.class);
127
128            employerByName = store.getSecondaryIndex(
129                employerById, String.class, "name");
130        }
131    }
132
133    public static void main(String[] args)
134        throws DatabaseException, FileNotFoundException {
135
136        if (args.length != 2 || !"-h".equals(args[0])) {
137            System.err.println
138                ("Usage: java " + PersonExample.class.getName() +
139                 " -h <envHome>");
140            System.exit(2);
141        }
142        PersonExample example = new PersonExample(new File(args[1]));
143        example.run();
144        example.close();
145    }
146
147    private Environment env;
148    private EntityStore store;
149    private PersonAccessor dao;
150
151    private PersonExample(File envHome)
152        throws DatabaseException, FileNotFoundException {
153
154        /* Open a transactional Berkeley DB engine environment. */
155        EnvironmentConfig envConfig = new EnvironmentConfig();
156        envConfig.setAllowCreate(true);
157        envConfig.setTransactional(true);
158        envConfig.setInitializeCache(true);
159        envConfig.setInitializeLocking(true);
160        env = new Environment(envHome, envConfig);
161
162        /* Open a transactional entity store. */
163        StoreConfig storeConfig = new StoreConfig();
164        storeConfig.setAllowCreate(true);
165        storeConfig.setTransactional(true);
166        store = new EntityStore(env, "PersonStore", storeConfig);
167
168        /* Initialize the data access object. */
169        dao = new PersonAccessor(store);
170    }
171
172    private void run()
173        throws DatabaseException {
174
175        /*
176         * Add a parent and two children using the Person primary index.
177         * Specifying a non-null parentSsn adds the child Person to the
178         * sub-index of children for that parent key.
179         */
180        dao.personBySsn.put
181            (new Person("Bob Smith", "111-11-1111", null));
182        dao.personBySsn.put
183            (new Person("Mary Smith", "333-33-3333", "111-11-1111"));
184        dao.personBySsn.put
185            (new Person("Jack Smith", "222-22-2222", "111-11-1111"));
186
187        /* Print the children of a parent using a sub-index and a cursor. */
188        EntityCursor<Person> children =
189            dao.personByParentSsn.subIndex("111-11-1111").entities();
190        try {
191            for (Person child : children) {
192                System.out.println(child.ssn + ' ' + child.name);
193            }
194        } finally {
195            children.close();
196        }
197
198        /* Get Bob by primary key using the primary index. */
199        Person bob = dao.personBySsn.get("111-11-1111");
200        assert bob != null;
201
202        /*
203         * Create two employers if they do not already exist.  Their primary
204         * keys are assigned from a sequence.
205         */
206        Employer gizmoInc = dao.employerByName.get("Gizmo Inc");
207        if (gizmoInc == null) {
208            gizmoInc = new Employer("Gizmo Inc");
209            dao.employerById.put(gizmoInc);
210        }
211        Employer gadgetInc = dao.employerByName.get("Gadget Inc");
212        if (gadgetInc == null) {
213            gadgetInc = new Employer("Gadget Inc");
214            dao.employerById.put(gadgetInc);
215        }
216
217        /* Bob has two jobs and two email addresses. */
218        bob.employerIds.add(gizmoInc.id);
219        bob.employerIds.add(gadgetInc.id);
220        bob.emailAddresses.add("bob@bob.com");
221        bob.emailAddresses.add("bob@gmail.com");
222
223        /* Update Bob's record. */
224        dao.personBySsn.put(bob);
225
226        /* Bob can now be found by both email addresses. */
227        bob = dao.personByEmailAddresses.get("bob@bob.com");
228        assert bob != null;
229        bob = dao.personByEmailAddresses.get("bob@gmail.com");
230        assert bob != null;
231
232        /* Bob can also be found as an employee of both employers. */
233        EntityIndex<String,Person> employees;
234        employees = dao.personByEmployerIds.subIndex(gizmoInc.id);
235        assert employees.contains("111-11-1111");
236        employees = dao.personByEmployerIds.subIndex(gadgetInc.id);
237        assert employees.contains("111-11-1111");
238
239        /*
240         * When an employer is deleted, the onRelatedEntityDelete=NULLIFY for
241         * the employerIds key causes the deleted ID to be removed from Bob's
242         * employerIds.
243         */
244        dao.employerById.delete(gizmoInc.id);
245        bob = dao.personBySsn.get("111-11-1111");
246        assert bob != null;
247        assert !bob.employerIds.contains(gizmoInc.id);
248    }
249
250    private void close()
251        throws DatabaseException {
252
253        store.close();
254        env.close();
255    }
256}
257