001    package com.sptci.prevayler;
002    
003    import static com.sptci.prevayler.PrevalentSystemFactory.getPrevayler;
004    import com.sptci.prevayler.query.Count;
005    import com.sptci.prevayler.query.Fetch;
006    import com.sptci.prevayler.query.FetchByIndex;
007    import com.sptci.prevayler.query.FetchByIndices;
008    import com.sptci.prevayler.query.FetchRange;
009    import com.sptci.prevayler.query.Search;
010    import com.sptci.prevayler.transaction.Delete;
011    import com.sptci.prevayler.transaction.Save;
012    import org.apache.lucene.search.Filter;
013    import org.apache.lucene.search.Query;
014    import org.apache.lucene.search.Sort;
015    
016    import java.util.Collection;
017    import java.util.Map;
018    
019    /**
020     * A facade around the prevalent system used to present a more natural
021     * programming interface than that provided by prevayler.
022     *
023     * <p>The following shows sample use of this class:</p>
024     * <pre>
025     *   import com.sptci.prevayler.PrevalentException;
026     *   import com.sptci.prevayler.PrevalentManager;
027     *
028     *     ...
029     *     MyPrevalentObject po = new MyPrevalentObject( ... );
030     *     po.setXxx( ... );
031     *
032     *     final PrevalentManager<MyPrevalentObject> pm = new PrevalentManager<MyPrevalentObject>();
033     *     try
034     *     {
035     *       po = pm.save( po );
036     *       System.out.format( "Total MyPrevalentObjects in system: %d%n",
037     *           po.count( MyPrevalentObject.class ) );
038     *     }
039     *     catch ( PrevalentException pex )
040     *     {
041     *       // handle error
042     *     }
043     * </pre>
044     *
045     * <p>&copy; Copyright 2008 <a href='http://sptci.com/' target='_top'>Sans
046     * Pareil Technologies, Inc.</a></p>
047     *
048     * @see PrevalentSystemFactory
049     * @author Rakesh Vidyadharan 2008-07-12
050     * @version $Id: PrevalentManager.java 22 2008-11-24 19:04:25Z sptrakesh $
051     */
052    public class PrevalentManager<P extends PrevalentObject> implements Database<P>
053    {
054      private static final long serialVersionUID = 1l;
055    
056      /**
057       * Save the specified prevalent object to the prevalent system.  If the
058       * object does not exist, it is created.  It it exists, the persisted
059       * object is updated.
060       *
061       * @param object The prevalent object to save to the prevalent system.
062       * @return The updated prevalent object instance.
063       * @throws PrevalentException If errors are encountered while saving the
064       *   prevalent object.
065       */
066      @SuppressWarnings( {"unchecked"} )
067      public P save( final P object ) throws PrevalentException
068      {
069        try
070        {
071          final Save<P> save = new Save<P>( object );
072          return (P) getPrevayler().execute( save );
073        }
074        catch ( PrevalentException pex )
075        {
076          throw pex;
077        }
078        catch ( Throwable t )
079        {
080          throw new PrevalentException( "Error saving object of type: " +
081              object.getClass().getName(), t );
082        }
083      }
084    
085      /**
086       * Delete the specified prevalent object from the prevalent system.  Note
087       * that constraint rules may cause an exception to be raised leaving the
088       * object still persisted.
089       *
090       * @param object The prevalent object to delete from the prevalent system.
091       * @return The modified prevalent object.  In particular the {@link
092       *   com.sptci.prevayler.PrevalentObject#getObjectId()} will return
093       *   <code>null</code> if the object is deleted.
094       * @throws PrevalentException If errors are encountered while deleting the
095       *   object.  More specific sub-classes such as {@link DeleteException}
096       *   are thrown when configured rules are violated.
097       */
098      @SuppressWarnings( {"unchecked"} )
099      public P delete( final P object ) throws PrevalentException
100      {
101        try
102        {
103          final Delete<P> delete = new Delete<P>( object );
104          return (P) getPrevayler().execute( delete );
105        }
106        catch ( PrevalentException pex )
107        {
108          throw pex;
109        }
110        catch ( Throwable t )
111        {
112          throw new PrevalentException( "Error deleting object with oid: " +
113              object.getObjectId() + " and type: " +
114              object.getClass().getName(), t );
115        }
116      }
117    
118      /**
119       * Return the total number of persistent instance of the specified type
120       * in the prevalent system.  This method is typically used to implement
121       * paginated views of the persistent data.
122       *
123       * @param type The type of object whose persistent instance count is to
124       *   be retrieved.
125       * @return The total number of persistent instances of the specified type.
126       * @throws PrevalentException If errors are encountered while fetching the
127       *   object count.
128       */
129      @SuppressWarnings( {"unchecked"} )
130      public int count( final Class type ) throws PrevalentException
131      {
132        try
133        {
134          return (Integer) getPrevayler().execute( new Count( type ) );
135        }
136        catch ( PrevalentException pex )
137        {
138          throw pex;
139        }
140        catch ( Throwable t )
141        {
142          throw new PrevalentException(
143              "Error retrieving object count for type: " + type, t );
144        }
145      }
146    
147      /**
148       * Return the prevalent object identified by the object id specified.
149       *
150       * @param type The type of the persisted object which has the specified
151       *   object id.
152       * @param objectId The object id of the prevalent object.
153       * @return The prevalent object if found or <code>null</code>.
154       * @throws PrevalentException If errors are encountered while fetching the
155       *   persistent object.
156       */
157      @SuppressWarnings( {"unchecked"} )
158      public P fetch( final Class type, final Object objectId )
159          throws PrevalentException
160      {
161        try
162        {
163          final Fetch fetch = new Fetch( type, objectId );
164          return (P) getPrevayler().execute( fetch );
165        }
166        catch ( PrevalentException pex )
167        {
168          throw pex;
169        }
170        catch ( Throwable t )
171        {
172          throw new PrevalentException(
173              "Error fetching prevalent object with objectId: " +
174              objectId + " and type: " + type.getName(), t );
175        }
176      }
177    
178      /**
179       * Return the collection of prevalent objects in the specified range.
180       * Objects are returned in insertion order.
181       *
182       * @param type The type of the persisted objects which are to be fetched.
183       * @param start The starting index (inclusive) of the range of objects
184       *   to fetch.
185       * @param end The ending index (exclusive) of the range of objects to
186       *   fetch.
187       * @return The collection of persistent objects.  Returns an empty
188       *   collection if no objects are found in the specified range.
189       * @throws PrevalentException If errors are encountered while retrieving
190       *   the persisted objects.
191       */
192      @SuppressWarnings( {"unchecked"} )
193      public Collection<P> fetch( final Class type, final long start,
194          final long end ) throws PrevalentException
195      {
196        try
197        {
198          final FetchRange range = new FetchRange( type, start, end );
199          return (Collection<P>) getPrevayler().execute( range );
200        }
201        catch ( PrevalentException pex )
202        {
203          throw pex;
204        }
205        catch ( Throwable t )
206        {
207          throw new PrevalentException(
208              "Error fetching prevalent objects in range: " +
209                  start + "-" + end + " and type: " + type.getName(), t );
210        }
211      }
212    
213      /**
214       * Retrieve the collection of prevelant objects of the specified type
215       * that are indexed by the specified field and value.
216       *
217       * @param type The type of the persisted objects which are to be fetched.
218       * @param field The name of the indexed field in the prevalent class.
219       * @param value The value of the indexed field in the prevalent class.
220       * @return The collection of persistent objects.  Returns an empty
221       *   collection if no objects are found with the specified indexed value.
222       * @throws PrevalentException If errors are encountered while retrieving
223       *   the persisted objects.
224       */
225      @SuppressWarnings( {"unchecked"} )
226      public Collection<P> fetch( final Class type, final String field,
227          final Object value ) throws PrevalentException
228      {
229        try
230        {
231          final FetchByIndex index = new FetchByIndex( type, field, value );
232          return (Collection<P>) getPrevayler().execute( index );
233        }
234        catch ( PrevalentException pex )
235        {
236          throw pex;
237        }
238        catch ( Throwable t )
239        {
240          throw new PrevalentException(
241              "Error fetching prevalent objects for indexed field: " + field +
242                  " with value: " + value + " and type: " + type.getName(), t );
243        }
244      }
245    
246      /**
247       * Retrieve the collection of prevelant objects of the specified type
248       * that are indexed by the specified fields and values.  The results
249       * represent a <code>union</code> of the prevalent objects matching each
250       * parameter in the collection of parameters (an <code>or</code> query).
251       *
252       * @see #fetchByIndices
253       * @param type The type of the persisted objects which are to be fetched.
254       * @param parameters The map of field-name to value mappings to use
255       *   to fetch instances.
256       * @return The collection of persistent objects.  Returns an empty
257       *   collection if no objects are found with the specified indexed value.
258       * @throws PrevalentException If errors are encountered while retrieving
259       *   the persisted objects.
260       */
261      public Collection<P> fetchUnion( final Class type,
262          final Map<String,?> parameters ) throws PrevalentException
263      {
264        return fetchByIndices( type, parameters,
265            FetchByIndices.AggregationType.UNION );
266      }
267    
268      /**
269       * Retrieve the collection of prevelant objects of the specified type
270       * that are indexed by the specified fields and values.  The results
271       * represent an <code>intersection</code> of the prevalent objects matching
272       * each parameter in the collection of parameters (an <code>or</code> query).
273       *
274       * @see #fetchByIndices
275       * @param type The type of the persisted objects which are to be fetched.
276       * @param parameters The map of field-name to value mappings to use
277       *   to fetch instances.
278       * @return The collection of persistent objects.  Returns an empty
279       *   collection if no objects are found with the specified indexed value.
280       * @throws PrevalentException If errors are encountered while retrieving
281       *   the persisted objects.
282       */
283      public Collection<P> fetchIntersection( final Class type,
284          final Map<String,?> parameters ) throws PrevalentException
285      {
286        return fetchByIndices( type, parameters,
287            FetchByIndices.AggregationType.INTERSECTION );
288      }
289    
290      /** {@inheritDoc} */
291      @SuppressWarnings( {"unchecked"} )
292      public Collection<P> search( final Query query, final int count ) throws PrevalentException
293      {
294        try
295        {
296          final Search search = new Search( query, count );
297          return (Collection<P>) getPrevayler().execute( search );
298        }
299        catch ( PrevalentException pex )
300        {
301          throw pex;
302        }
303        catch ( Throwable t )
304        {
305          throw new PrevalentException( "Error executing query: " + query, t );
306        }
307      }
308    
309      /** {@inheritDoc} */
310      @SuppressWarnings( {"unchecked"} )
311      public Collection<P> search( final Query query, final Filter filter,
312          final int count ) throws PrevalentException
313      {
314        try
315        {
316          final Search search = new Search( query, filter, count );
317          return (Collection<P>) getPrevayler().execute( search );
318        }
319        catch ( PrevalentException pex )
320        {
321          throw pex;
322        }
323        catch ( Throwable t )
324        {
325          throw new PrevalentException( "Error executing query: " + query +
326              " with filter: " + filter, t );
327        }
328      }
329    
330      /** {@inheritDoc} */
331      @SuppressWarnings( {"unchecked"} )
332      public Collection<P> search( final Query query, final Filter filter,
333          final int count, final Sort sort ) throws PrevalentException
334      {
335        try
336        {
337          final Search search = new Search( query, filter, count, sort );
338          return (Collection<P>) getPrevayler().execute( search );
339        }
340        catch ( PrevalentException pex )
341        {
342          throw pex;
343        }
344        catch ( Throwable t )
345        {
346          throw new PrevalentException( "Error executing query: " + query +
347              " with filter: " + filter + " and sort: " + sort, t );
348        }
349      }
350    
351    
352      /**
353       * Retrieve the collection of prevelant objects of the specified type
354       * that are indexed by the specified fields and values.
355       *
356       * @param type The type of the persisted objects which are to be fetched.
357       * @param parameters The map of field-name to value mappings to use
358       *   to fetch instances.
359       * @param resultType The type of aggregation to be used for the result set.
360       * @return The collection of persistent objects.  Returns an empty
361       *   collection if no objects are found with the specified indexed value.
362       * @throws PrevalentException If errors are encountered while retrieving
363       *   the persisted objects.
364       */
365      @SuppressWarnings( {"unchecked"} )
366      protected Collection<P> fetchByIndices( final Class type,
367          final Map<String,?> parameters,
368          final FetchByIndices.AggregationType resultType )
369        throws PrevalentException
370      {
371        try
372        {
373          final FetchByIndices indices =
374              new FetchByIndices( type, parameters, resultType );
375          return (Collection<P>) getPrevayler().execute( indices );
376        }
377        catch ( PrevalentException pex )
378        {
379          throw pex;
380        }
381        catch ( Throwable t )
382        {
383          throw new PrevalentException(
384              "Error fetching prevalent objects of type: " + type.getName(), t );
385        }
386      }
387    }