1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2004,2008 Oracle.  All rights reserved.
5 *
6 * $Id: EventExampleDPL.java,v 1.1 2008/02/07 17:12:24 mark Exp $
7 */
8
9package persist;
10
11import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
12
13import java.io.File;
14import java.io.FileNotFoundException;
15import java.util.Calendar;
16import java.util.Date;
17import java.util.HashSet;
18import java.util.Random;
19import java.util.Set;
20
21import com.sleepycat.db.DatabaseException;
22import com.sleepycat.db.Environment;
23import com.sleepycat.db.EnvironmentConfig;
24import com.sleepycat.db.Transaction;
25import com.sleepycat.persist.EntityCursor;
26import com.sleepycat.persist.EntityStore;
27import com.sleepycat.persist.PrimaryIndex;
28import com.sleepycat.persist.SecondaryIndex;
29import com.sleepycat.persist.StoreConfig;
30import com.sleepycat.persist.model.Entity;
31import com.sleepycat.persist.model.PrimaryKey;
32import com.sleepycat.persist.model.SecondaryKey;
33
34/**
35 * EventExampleDPL is a trivial example which stores Java objects that
36 * represent an event. Events are primarily indexed by a timestamp, but have
37 * other attributes, such as price, account reps, customer name and
38 * quantity.  Some of those other attributes are indexed.
39 * <p>
40 * The example simply shows the creation of a BDB environment and database,
41 * inserting some events, and retrieving the events using the Direct
42 * Persistence layer.
43 * <p>
44 * This example is meant to be paired with its twin, EventExample.java.
45 * EventExample.java and EventExampleDPL.java perform the same functionality,
46 * but use the Base API and the Direct Persistence Layer API, respectively.
47 * This may be a useful way to compare the two APIs.
48 * <p>
49 * To run the example:
50 * <pre>
51 * javac EventExampleDPL.java
52 * java EventExampleDPL -h <environmentDirectory>
53 * </pre>
54 */
55public class EventExampleDPL {
56
57    /*
58     * The Event class embodies our example event and is the application
59     * data. The @Entity annotation indicates that this class defines the
60     * objects stored in a BDB database.
61     */
62    @Entity
63    static class Event {
64
65        @PrimaryKey
66        private Date time;
67
68        @SecondaryKey(relate=MANY_TO_ONE)
69        private int price;
70
71        private Set<String> accountReps;
72
73        private String customerName;
74        private int quantity;
75
76        Event(Date time,
77              int price,
78              String customerName) {
79
80            this.time = time;
81            this.price = price;
82            this.customerName = customerName;
83            this.accountReps = new HashSet<String>();
84        }
85
86        private Event() {} // For deserialization
87
88        void addRep(String rep) {
89            accountReps.add(rep);
90        }
91
92        @Override
93        public String toString() {
94            StringBuilder sb = new StringBuilder();
95            sb.append("time=").append(time);
96            sb.append(" price=").append(price);
97            sb.append(" customerName=").append(customerName);
98            sb.append(" reps=");
99            if (accountReps.size() == 0) {
100                sb.append("none");
101            } else {
102                for (String rep: accountReps) {
103                    sb.append(rep).append(" ");
104                }
105            }
106            return sb.toString();
107        }
108    }
109
110    /* A BDB environment is roughly equivalent to a relational database. */
111    private Environment env;
112    private EntityStore store;
113
114    /*
115     * Event accessors let us access events by the primary index (time)
116     * as well as by the rep and price fields
117     */
118    PrimaryIndex<Date,Event> eventByTime;
119    SecondaryIndex<Integer,Date,Event> eventByPrice;
120
121    /* Used for generating example data. */
122    private Calendar cal;
123
124    /*
125     * First manually make a directory to house the BDB environment.
126     * Usage: java EventExampleDPL -h <envHome>
127     * All BDB on-disk storage is held within envHome.
128     */
129    public static void main(String[] args)
130        throws DatabaseException, FileNotFoundException {
131
132        if (args.length != 2 || !"-h".equals(args[0])) {
133            System.err.println
134                ("Usage: java " + EventExampleDPL.class.getName() +
135                 " -h <envHome>");
136            System.exit(2);
137        }
138        EventExampleDPL example = new EventExampleDPL(new File(args[1]));
139        example.run();
140        example.close();
141    }
142
143    private EventExampleDPL(File envHome)
144        throws DatabaseException, FileNotFoundException {
145
146        /* Open a transactional Berkeley DB engine environment. */
147        System.out.println("-> Creating a BDB environment");
148        EnvironmentConfig envConfig = new EnvironmentConfig();
149        envConfig.setAllowCreate(true);
150        envConfig.setTransactional(true);
151        envConfig.setInitializeCache(true);
152        envConfig.setInitializeLocking(true);
153        env = new Environment(envHome, envConfig);
154
155        /* Initialize the data access object. */
156        init();
157        cal = Calendar.getInstance();
158    }
159
160    /**
161     * Create all primary and secondary indices.
162     */
163    private void init()
164        throws DatabaseException {
165
166        /* Open a transactional entity store. */
167        System.out.println("-> Creating a BDB database");
168        StoreConfig storeConfig = new StoreConfig();
169        storeConfig.setAllowCreate(true);
170        storeConfig.setTransactional(true);
171        store = new EntityStore(env, "ExampleStore", storeConfig);
172
173        eventByTime = store.getPrimaryIndex(Date.class, Event.class);
174        eventByPrice = store.getSecondaryIndex(eventByTime,
175                                               Integer.class,
176                                               "price");
177    }
178
179    private void run()
180        throws DatabaseException {
181
182        Random rand = new Random();
183
184        /*
185         * Create a set of events. Each insertion is a separate, auto-commit
186         * transaction.
187         */
188        System.out.println("-> Inserting 4 events");
189        eventByTime.put(new Event(makeDate(1), 100, "Company_A"));
190        eventByTime.put(new Event(makeDate(2), 2, "Company_B"));
191        eventByTime.put(new Event(makeDate(3), 20, "Company_C"));
192        eventByTime.put(new Event(makeDate(4), 40, "CompanyD"));
193
194        /* Load a whole set of events transactionally. */
195        Transaction txn = env.beginTransaction(null, null);
196        int maxPrice = 50;
197        System.out.println("-> Inserting some randomly generated events");
198        for (int i = 0; i < 25; i++) {
199            Event e = new Event(makeDate(rand.nextInt(365)),
200                                rand.nextInt(maxPrice),
201                                "Company_X");
202            if ((i%2) ==0) {
203                e.addRep("Bob");
204                e.addRep("Nikunj");
205            } else {
206                e.addRep("Yongmin");
207            }
208            eventByTime.put(e);
209        }
210        txn.commitWriteNoSync();
211
212        /*
213         * Windows of events - display the events between June 1 and Aug 31
214         */
215        System.out.println("\n-> Display the events between June 1 and Aug 31");
216        Date startDate = makeDate(Calendar.JUNE, 1);
217        Date endDate = makeDate(Calendar.AUGUST, 31);
218
219        EntityCursor<Event> eventWindow =
220            eventByTime.entities(startDate, true, endDate, true);
221        printEvents(eventWindow);
222
223        /*
224         * Display all events, ordered by a secondary index on price.
225         */
226        System.out.println("\n-> Display all events, ordered by price");
227        EntityCursor<Event> byPriceEvents = eventByPrice.entities();
228        printEvents(byPriceEvents);
229    }
230
231    private void close()
232        throws DatabaseException {
233
234        store.close();
235        env.close();
236    }
237
238    /**
239     * Print all events covered by this cursor.
240     */
241    private void printEvents(EntityCursor<Event> eCursor)
242        throws DatabaseException {
243        try {
244            for (Event e: eCursor) {
245                System.out.println(e);
246            }
247        } finally {
248            /* Be sure to close the cursor. */
249            eCursor.close();
250        }
251    }
252
253    /**
254     * Little utility for making up java.util.Dates for different days, just
255     * to generate test data.
256     */
257    private Date makeDate(int day) {
258
259        cal.set((Calendar.DAY_OF_YEAR), day);
260        return cal.getTime();
261    }
262
263    /**
264     * Little utility for making up java.util.Dates for different days, just
265     * to make the test data easier to read.
266     */
267    private Date makeDate(int month, int day) {
268
269        cal.set((Calendar.MONTH), month);
270        cal.set((Calendar.DAY_OF_MONTH), day);
271        return cal.getTime();
272    }
273}
274