KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > CMPInMemoryPersistenceManager


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.ejb.plugins;
23
24
25 import java.lang.reflect.Field JavaDoc;
26 import java.lang.reflect.Method JavaDoc;
27
28 import java.io.IOException JavaDoc;
29
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.Collections JavaDoc;
34
35 import javax.ejb.EJBException JavaDoc;
36
37 import org.jboss.ejb.Container;
38 import org.jboss.ejb.EntityEnterpriseContext;
39 import org.jboss.ejb.EntityPersistenceStore;
40 import org.jboss.ejb.EntityContainer;
41 import org.jboss.ejb.GenericEntityObjectFactory;
42
43 import org.jboss.metadata.EntityMetaData;
44
45 import org.jboss.system.ServiceMBeanSupport;
46
47 /**
48  * EntityPersistenceStore implementation storing values in-memory
49  * for very efficient access.
50  *
51  * @see org.jboss.ejb.EntityPersistenceStore
52  * @see org.jboss.ejb.plugins.CMPFilePersistenceManager
53  *
54  * @version <tt>$Revision: 37459 $</tt>
55  * @author <a HREF="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>.
56  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
57  *
58  * <p><b>Revisions:</b>
59  *
60  * <p><b>28.12.2001 - Sacha Labourey:</b>
61  * <ul>
62  * <li> First implementation highly based on CMPFilePersistenceManager</li>
63  * </ul>
64  * <p><b>25.05.2002 - Dain Sundstrom:</b>
65  * <ul>
66  * <li> Replaced FinderResults with Collection</li>
67  * </ul>
68  */

69 public class CMPInMemoryPersistenceManager
70    extends ServiceMBeanSupport
71    implements EntityPersistenceStore
72 {
73    // Attributes ----------------------------------------------------
74

75    protected EntityContainer con;
76    protected HashMap JavaDoc beans;
77    protected Field JavaDoc idField;
78    
79    /**
80     * Optional isModified method used by storeEntity.
81     */

82    protected Method JavaDoc isModified;
83    
84    // Constructors --------------------------------------------------
85

86    public CMPInMemoryPersistenceManager ()
87    {
88    }
89    
90    /**
91     * This callback is set by the container so that the plugin may access it
92     *
93     * @param con The container using this plugin.
94     *
95     * @throws ClassCastException Container is not a EntityContainer.
96     */

97    public void setContainer (final Container con)
98    {
99       this.con = (EntityContainer)con;
100    }
101    
102    /**
103     * create the service, do expensive operations etc
104     */

105    protected void createService() throws Exception JavaDoc
106    {
107       this.beans = new HashMap JavaDoc(1000);
108       
109       String JavaDoc ejbName = con.getBeanMetaData ().getEjbName ();
110       
111       idField = con.getBeanClass ().getField ("id");
112       log.debug("Using id field: " + idField);
113
114       // Lookup the isModified method if it exists
115
try
116       {
117          isModified = con.getBeanClass().getMethod("isModified", new Class JavaDoc[0]);
118          if (!isModified.getReturnType().equals(Boolean.TYPE)) {
119             isModified = null; // Has to have "boolean" as return type!
120
log.warn("Found isModified method, but return type is not boolean; ignoring");
121          }
122          else {
123             log.debug("Using isModified method: " + isModified);
124          }
125       }
126       catch (NoSuchMethodException JavaDoc ignored) {}
127    }
128
129    protected void stopService() throws Exception JavaDoc
130    {
131       this.beans.clear();
132    }
133    
134    // EntityPersistenceStore implementation ----------------------------------------------
135

136    /**
137     * Returns a new instance of the bean class or a subclass of the bean class.
138     *
139     * @return the new instance
140     *
141     * @throws Exception
142     */

143    public Object JavaDoc createBeanClassInstance () throws Exception JavaDoc
144    {
145       return con.getBeanClass ().newInstance ();
146    }
147    
148    /**
149     * Initializes the instance context.
150     *
151     * <p>This method is called before createEntity, and should
152     * reset the value of all cmpFields to 0 or null.
153     *
154     * @param ctx
155     */

156    public void initEntity (EntityEnterpriseContext ctx)
157    {
158       // first get cmp metadata of this entity
159
Object JavaDoc instance = ctx.getInstance ();
160       Class JavaDoc ejbClass = instance.getClass ();
161       Field JavaDoc cmpField;
162       Class JavaDoc cmpFieldType;
163       
164       EntityMetaData metaData = (EntityMetaData)con.getBeanMetaData ();
165       Iterator JavaDoc i= metaData.getCMPFields ();
166       
167       while(i.hasNext ())
168       {
169          // get the field declaration
170
try
171          {
172             cmpField = ejbClass.getField ((String JavaDoc)i.next ());
173             cmpFieldType = cmpField.getType ();
174             
175             // find the type of the field and resets it
176
// to the default value
177
if (cmpFieldType.equals (boolean.class))
178             {
179                cmpField.setBoolean (instance,false);
180             }
181             else if (cmpFieldType.equals (byte.class))
182             {
183                cmpField.setByte (instance,(byte)0);
184             }
185             else if (cmpFieldType.equals (int.class))
186             {
187                cmpField.setInt (instance,0);
188             }
189             else if (cmpFieldType.equals (long.class))
190             {
191                cmpField.setLong (instance,0L);
192             }
193             else if (cmpFieldType.equals (short.class))
194             {
195                cmpField.setShort (instance,(short)0);
196             }
197             else if (cmpFieldType.equals (char.class))
198             {
199                cmpField.setChar (instance,'\u0000');
200             }
201             else if (cmpFieldType.equals (double.class))
202             {
203                cmpField.setDouble (instance,0d);
204             }
205             else if (cmpFieldType.equals (float.class))
206             {
207                cmpField.setFloat (instance,0f);
208             }
209             else
210             {
211                cmpField.set (instance,null);
212             }
213          }
214          catch (NoSuchFieldException JavaDoc e)
215          {
216             // will be here with dependant value object's private attributes
217
// should not be a problem
218
}
219          catch (Exception JavaDoc e)
220          {
221             throw new EJBException JavaDoc (e);
222          }
223       }
224    }
225    
226    /**
227     * This method is called whenever an entity is to be created.
228     * The persistence manager is responsible for handling the results properly
229     * wrt the persistent store.
230     *
231     * @param m the create method in the home interface that was
232     * called
233     * @param args any create parameters
234     * @param ctx the instance being used for this create call
235     * @return The primary key computed by CMP PM or null for BMP
236     *
237     * @throws Exception
238     */

239    public Object JavaDoc createEntity (Method JavaDoc m, Object JavaDoc[] args, EntityEnterpriseContext ctx) throws Exception JavaDoc
240    {
241       try
242       {
243          Object JavaDoc id = idField.get (ctx.getInstance ());
244          
245          // Check exist
246
if (this.beans.containsKey (id))
247             throw new javax.ejb.DuplicateKeyException JavaDoc ("Already exists: "+id);
248          
249          // Store to file
250
storeEntity (id, ctx.getInstance ());
251          
252          return id;
253       }
254       catch (IllegalAccessException JavaDoc e)
255       {
256          throw new javax.ejb.CreateException JavaDoc ("Could not create entity: "+e);
257       }
258    }
259
260    /**
261     * This method is called after the createEntity.
262     * The persistence manager is responsible for handling the results properly
263     * wrt the persistent store.
264     *
265     * @param m the ejbPostCreate method in the bean class that was
266     * called
267     * @param args any create parameters
268     * @param ctx the instance being used for this create call
269     * @return null
270     *
271     * @throws Exception
272     */

273    public Object JavaDoc postCreateEntity(final Method JavaDoc m,
274                                   final Object JavaDoc[] args,
275                                   final EntityEnterpriseContext ctx)
276       throws Exception JavaDoc
277    {
278       return null;
279    }
280    
281    /**
282     * This method is called when single entities are to be found. The
283     * persistence manager must find out whether the wanted instance is
284     * available in the persistence store, if so it returns the primary key of
285     * the object.
286     *
287     * @param finderMethod the find method in the home interface that was
288     * called
289     * @param args any finder parameters
290     * @param instance the instance to use for the finder call
291     * @return a primary key representing the found entity
292     *
293     * @throws Exception thrown if some heuristic problem occurs
294     */

295    public Object JavaDoc findEntity (Method JavaDoc finderMethod, Object JavaDoc[] args, EntityEnterpriseContext instance, GenericEntityObjectFactory factory)
296       throws Exception JavaDoc
297    {
298       if (finderMethod.getName ().equals ("findByPrimaryKey"))
299       {
300          if (!this.beans.containsKey (args[0]))
301             throw new javax.ejb.FinderException JavaDoc (args[0]+" does not exist");
302          
303          return factory.getEntityEJBObject(args[0]);
304       }
305
306       return null;
307    }
308    
309    /**
310     * This method is called when collections of entities are to be found. The
311     * persistence manager must find out whether the wanted instances are
312     * available in the persistence store, and if so it must return a
313     * collection of primaryKeys.
314     *
315     * @param finderMethod the find method in the home interface that was
316     * called
317     * @param args any finder parameters
318     * @param instance the instance to use for the finder call
319     * @return an primary key collection representing the found
320     * entities
321     *
322     * @throws Exception thrown if some heuristic problem occurs
323     */

324    public Collection JavaDoc findEntities(final Method JavaDoc finderMethod,
325                                   final Object JavaDoc[] args,
326                                   final EntityEnterpriseContext instance,
327                                   GenericEntityObjectFactory factory)
328       throws Exception JavaDoc
329    {
330       if (finderMethod.getName ().equals ("findAll"))
331       {
332          return GenericEntityObjectFactory.UTIL.getEntityCollection(factory, this.beans.keySet());
333       }
334       else
335       {
336          // we only support find all
337
return Collections.EMPTY_LIST;
338       }
339    }
340    
341    /**
342     * Non-operation.
343     */

344    public void activateEntity (EntityEnterpriseContext instance)
345    {
346       // nothing to do
347
}
348    
349    /**
350     * This method is called whenever an entity shall be load from the
351     * underlying storage. The persistence manager must load the state from
352     * the underlying storage and then call ejbLoad on the supplied instance.
353     *
354     * @param ctx the instance to synchronize
355     */

356    public void loadEntity (EntityEnterpriseContext ctx)
357    {
358       try
359       {
360          // Read fields
361

362          java.io.ObjectInputStream JavaDoc in = new CMPObjectInputStream
363             (new java.io.ByteArrayInputStream JavaDoc ((byte[])this.beans.get (ctx.getId ())));
364          
365          Object JavaDoc obj = ctx.getInstance ();
366          
367          Field JavaDoc[] f = obj.getClass ().getFields ();
368          for (int i = 0; i < f.length; i++)
369          {
370             f[i].set (obj, in.readObject ());
371          }
372          
373          in.close ();
374       }
375       catch (Exception JavaDoc e)
376       {
377          throw new EJBException JavaDoc ("Load failed", e);
378       }
379    }
380    
381    /**
382     * This method is used to determine if an entity should be stored.
383     *
384     * @param ctx the instance to check
385     * @return true, if the entity has been modified
386     * @throws Exception thrown if some system exception occurs
387     */

388    public boolean isStoreRequired (EntityEnterpriseContext ctx) throws Exception JavaDoc
389    {
390       if(isModified == null)
391       {
392          return true;
393       }
394       
395       Boolean JavaDoc modified = (Boolean JavaDoc) isModified.invoke (ctx.getInstance (), new Object JavaDoc[0]);
396       return modified.booleanValue ();
397    }
398
399    public boolean isModified(EntityEnterpriseContext ctx) throws Exception JavaDoc
400    {
401       return isStoreRequired(ctx);
402    }
403
404    /**
405     * This method is called whenever an entity shall be stored to the
406     * underlying storage. The persistence manager must call ejbStore on the
407     * supplied instance and then store the state to the underlying storage.
408     *
409     * @param ctx the instance to synchronize
410     */

411    public void storeEntity (EntityEnterpriseContext ctx)
412    {
413       storeEntity (ctx.getId (), ctx.getInstance ());
414    }
415    
416    /**
417     * Non-operation.
418     */

419    public void passivateEntity (EntityEnterpriseContext instance)
420    {
421       // This plugin doesn't do anything specific
422
}
423    
424    /**
425     * This method is called when an entity shall be removed from the
426     * underlying storage. The persistence manager must call ejbRemove on the
427     * instance and then remove its state from the underlying storage.
428     *
429     * @param ctx the instance to remove
430     *
431     * @throws javax.ejb.RemoveException thrown if the instance could not be removed
432     */

433    public void removeEntity (EntityEnterpriseContext ctx) throws javax.ejb.RemoveException JavaDoc
434    {
435       if (this.beans.remove (ctx.getId ()) == null)
436          throw new javax.ejb.RemoveException JavaDoc ("Could not remove bean:" + ctx.getId ());
437    }
438    
439    // Protected -----------------------------------------------------
440

441    protected void storeEntity (Object JavaDoc id, Object JavaDoc obj)
442    {
443       try
444       {
445          // Store fields
446
java.io.ByteArrayOutputStream JavaDoc baos = new java.io.ByteArrayOutputStream JavaDoc ();
447          java.io.ObjectOutputStream JavaDoc out = new CMPObjectOutputStream (baos);
448
449          try {
450             Field JavaDoc[] f = obj.getClass ().getFields ();
451             for (int i = 0; i < f.length; i++)
452             {
453                out.writeObject (f[i].get (obj));
454             }
455          }
456          finally {
457             out.close();
458          }
459          
460          this.beans.put (id, baos.toByteArray ());
461       }
462       catch (Exception JavaDoc e)
463       {
464          throw new EJBException JavaDoc ("Store failed", e);
465       }
466    }
467    
468    // Inner classes -------------------------------------------------
469

470    static class CMPObjectOutputStream extends java.io.ObjectOutputStream JavaDoc
471    {
472       public CMPObjectOutputStream (java.io.OutputStream JavaDoc out) throws IOException JavaDoc
473       {
474          super (out);
475          enableReplaceObject (true);
476       }
477       
478       protected Object JavaDoc replaceObject (Object JavaDoc obj)
479          throws IOException JavaDoc
480       {
481          if (obj instanceof javax.ejb.EJBObject JavaDoc)
482             return ((javax.ejb.EJBObject JavaDoc)obj).getHandle ();
483          
484          return obj;
485       }
486    }
487    
488    static class CMPObjectInputStream extends java.io.ObjectInputStream JavaDoc
489    {
490       public CMPObjectInputStream (java.io.InputStream JavaDoc in) throws IOException JavaDoc
491       {
492          super (in);
493          enableResolveObject (true);
494       }
495       
496       protected Object JavaDoc resolveObject (Object JavaDoc obj)
497          throws IOException JavaDoc
498       {
499          if (obj instanceof javax.ejb.Handle JavaDoc)
500             return ((javax.ejb.Handle JavaDoc)obj).getEJBObject ();
501          
502          return obj;
503       }
504    }
505    
506 }
507
Popular Tags