KickJava   Java API By Example, From Geeks To Geeks.

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


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 import java.lang.reflect.Field JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collection JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.List JavaDoc;
31
32 import javax.ejb.EJBException JavaDoc;
33
34 import org.jboss.ejb.EntityEnterpriseContext;
35 import org.jboss.ejb.GenericEntityObjectFactory;
36 import org.jboss.ha.framework.interfaces.DistributedState;
37 import org.jboss.metadata.BeanMetaData;
38 import org.jboss.metadata.ClusterConfigMetaData;
39 import org.jboss.metadata.EntityMetaData;
40
41 /**
42  * EntityPersistenceStore implementation storing values in-memory
43  * and shared accross the cluster through the DistributedState service
44  * from the clustering framework. It always uses the DefaultPartition.
45  *
46  * @see org.jboss.ejb.EntityPersistenceStore
47  * @see org.jboss.ejb.plugins.CMPInMemoryPersistenceManager
48  * @see org.jboss.ha.framework.interfaces.DistributedState
49  *
50  * @author <a HREF="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>.
51  * @version $Revision: 37459 $
52  */

53 public class CMPClusteredInMemoryPersistenceManager implements org.jboss.ejb.EntityPersistenceStore
54 {
55    // Constants -----------------------------------------------------
56

57    // Attributes ----------------------------------------------------
58

59    protected org.jboss.ejb.EntityContainer con = null;
60    protected Field JavaDoc idField = null;
61
62    protected DistributedState ds = null;
63
64    protected String JavaDoc DS_CATEGORY = null;
65
66    /**
67     * Optional isModified method used by storeEntity
68     */

69    protected Method JavaDoc isModified = null;
70
71    // Static --------------------------------------------------------
72

73    // Constructors --------------------------------------------------
74

75    public CMPClusteredInMemoryPersistenceManager ()
76    {
77    }
78
79    /**
80     * This callback is set by the container so that the plugin may access it
81     *
82     * @param con The container using this plugin.
83     */

84    public void setContainer (org.jboss.ejb.Container con)
85    {
86       this.con = (org.jboss.ejb.EntityContainer)con;
87    }
88
89    /**
90     * create the service, do expensive operations etc
91     */

92    public void create () throws Exception JavaDoc
93    {
94       BeanMetaData bmd = con.getBeanMetaData();
95       ClusterConfigMetaData ccmd = bmd.getClusterConfigMetaData ();
96       String JavaDoc partitionName = ccmd.getPartitionName();
97       String JavaDoc name = "jboss:service=DistributedState,partitionName="+partitionName;
98       ds = (DistributedState)org.jboss.system.Registry.lookup (name);
99
100       String JavaDoc ejbName = bmd.getEjbName();
101       this.DS_CATEGORY = "CMPClusteredInMemoryPersistenceManager-" + ejbName;
102
103       idField = con.getBeanClass ().getField ("id");
104
105       try
106       {
107          isModified = con.getBeanClass ().getMethod ("isModified", new Class JavaDoc[0]);
108          if (!isModified.getReturnType ().equals (Boolean.TYPE))
109             isModified = null; // Has to have "boolean" as return type!
110
}
111       catch (NoSuchMethodException JavaDoc ignored)
112       {
113       }
114    }
115
116    /**
117     * start the service, create is already called
118     */

119    public void start () throws Exception JavaDoc
120    {
121    }
122
123    /**
124     * stop the service
125     */

126    public void stop ()
127    {
128    }
129
130
131    /**
132     * destroy the service, tear down
133     */

134    public void destroy ()
135    {
136    }
137
138    // Public --------------------------------------------------------
139

140    // EntityPersistenceStore implementation ----------------------------------------------
141

142    /**
143     * Returns a new instance of the bean class or a subclass of the bean class.
144     *
145     * @return the new instance
146     *
147     * @throws Exception
148     */

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

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

247    public Object JavaDoc createEntity (Method JavaDoc m, Object JavaDoc[] args,
248       EntityEnterpriseContext ctx) throws Exception JavaDoc
249    {
250       try
251       {
252
253          Object JavaDoc id = idField.get (ctx.getInstance ());
254
255          // Check exist
256
if (this.ds.get (DS_CATEGORY, id.toString ()) != null)
257             throw new javax.ejb.DuplicateKeyException JavaDoc ("Already exists:"+id);
258
259          // Store to file
260
storeEntity (id, ctx.getInstance ());
261
262          return id;
263       }
264       catch (IllegalAccessException JavaDoc e)
265       {
266          throw new javax.ejb.CreateException JavaDoc ("Could not create entity:"+e);
267       }
268    }
269
270    /**
271     * This method is called after the ejbCreate.
272     * The persistence manager is responsible for handling the results properly
273     * wrt the persistent store.
274     *
275     * @param m the ejbPostCreate method in the bean class that was
276     * called
277     * @param args any create parameters
278     * @param ctx the instance being used for this create call
279     * @return The primary key computed by CMP PM or null for BMP
280     *
281     * @throws Exception
282     */

283    public Object JavaDoc postCreateEntity (Method JavaDoc m, Object JavaDoc[] args,
284       EntityEnterpriseContext ctx) throws Exception JavaDoc
285    {
286       return null;
287    }
288
289    /**
290     * This method is called when single entities are to be found. The
291     * persistence manager must find out whether the wanted instance is
292     * available in the persistence store, if so it returns the primary key of
293     * the object.
294     *
295     * @param finderMethod the find method in the home interface that was
296     * called
297     * @param args any finder parameters
298     * @param instance the instance to use for the finder call
299     * @return a primary key representing the found entity
300     *
301     * @throws java.rmi.RemoteException thrown if some system exception occurs
302     * @throws javax.ejb.FinderException thrown if some heuristic problem occurs
303     */

304    public Object JavaDoc findEntity (Method JavaDoc finderMethod, Object JavaDoc[] args,
305                              EntityEnterpriseContext instance,
306                              GenericEntityObjectFactory factory) throws Exception JavaDoc
307    {
308       if (finderMethod.getName ().equals ("findByPrimaryKey"))
309       {
310          if (this.ds.get (DS_CATEGORY, args[0].toString ()) == null)
311             throw new javax.ejb.FinderException JavaDoc (args[0]+" does not exist");
312
313          return factory.getEntityEJBObject(args[0]);
314       }
315       else
316          return null;
317    }
318
319    /**
320     * This method is called when collections of entities are to be found. The
321     * persistence manager must find out whether the wanted instances are
322     * available in the persistence store, and if so it must return a
323     * collection of primaryKeys.
324     *
325     * @param finderMethod the find method in the home interface that was
326     * called
327     * @param args any finder parameters
328     * @param instance the instance to use for the finder call
329     * @return an primary key collection representing the found
330     * entities
331     *
332     * @throws java.rmi.RemoteException thrown if some system exception occurs
333     * @throws javax.ejb.FinderException thrown if some heuristic problem occurs
334     */

335    public Collection JavaDoc findEntities (Method JavaDoc finderMethod, Object JavaDoc[] args,
336       EntityEnterpriseContext instance, GenericEntityObjectFactory factory) throws Exception JavaDoc
337    {
338       Collection JavaDoc results = Collections.EMPTY_LIST;
339       if (finderMethod.getName ().equals ("findAll"))
340       {
341          Collection JavaDoc tmpColl = this.ds.getAllKeys (DS_CATEGORY);
342          if (tmpColl != null)
343             results = GenericEntityObjectFactory.UTIL.getEntityCollection(factory, tmpColl);
344       }
345       return results;
346    }
347
348    /**
349     * This method is called when an entity shall be activated.
350     *
351     * <p>With the PersistenceManager factorization most EJB calls should not
352     * exists However this calls permits us to introduce optimizations in
353     * the persistence store. Particularly the context has a
354     * "PersistenceContext" that a PersistenceStore can use (JAWS does for
355     * smart updates) and this is as good a callback as any other to set it
356     * up.
357     *
358     * @param instance the instance to use for the activation
359     *
360     * @throws java.rmi.RemoteException thrown if some system exception occurs
361     */

362    public void activateEntity (EntityEnterpriseContext instance) { }
363
364    /**
365     * This method is called whenever an entity shall be load from the
366     * underlying storage. The persistence manager must load the state from
367     * the underlying storage and then call ejbLoad on the supplied instance.
368     *
369     * @param ctx the instance to synchronize
370     *
371     * @throws java.rmi.RemoteException thrown if some system exception occurs
372     */

373    public void loadEntity (EntityEnterpriseContext ctx)
374    {
375       try
376       {
377          // Read fields
378
byte[] content = (byte[])this.ds.get (this.DS_CATEGORY, ctx.getId ().toString ());
379
380          if (content == null)
381             throw new javax.ejb.EJBException JavaDoc ("No entry exists (any more?) with this id: " + ctx.getId ());
382          
383          java.io.ObjectInputStream JavaDoc in = new org.jboss.ejb.plugins.CMPClusteredInMemoryPersistenceManager.CMPObjectInputStream (
384          new java.io.ByteArrayInputStream JavaDoc (content));
385
386          Object JavaDoc obj = ctx.getInstance ();
387
388          Field JavaDoc[] f = obj.getClass ().getFields ();
389          for (int i = 0; i < f.length; i++)
390          {
391             f[i].set (obj, in.readObject ());
392          }
393
394          in.close ();
395
396       }
397       catch (javax.ejb.EJBException JavaDoc e)
398       {
399          throw e;
400       }
401       catch (Exception JavaDoc e)
402       {
403          throw new EJBException JavaDoc ("Load failed", e);
404       }
405    }
406
407    /**
408     * This method is used to determine if an entity should be stored.
409     *
410     * @param ctx the instance to check
411     * @return true, if the entity has been modified
412     * @throws Exception thrown if some system exception occurs
413     */

414    public boolean isStoreRequired (EntityEnterpriseContext ctx) throws Exception JavaDoc
415    {
416       if(isModified == null)
417       {
418          return true;
419       }
420
421       Object JavaDoc[] args =
422       {};
423       Boolean JavaDoc modified = (Boolean JavaDoc) isModified.invoke (ctx.getInstance (), args);
424       return modified.booleanValue ();
425    }
426
427    public boolean isModified (EntityEnterpriseContext ctx) throws Exception JavaDoc
428    {
429       return isStoreRequired(ctx);
430    }
431
432    /**
433     * This method is called whenever an entity shall be stored to the
434     * underlying storage. The persistence manager must call ejbStore on the
435     * supplied instance and then store the state to the underlying storage.
436     *B
437     * @param ctx the instance to synchronize
438     *
439     * @throws java.rmi.RemoteException thrown if some system exception occurs
440     */

441    public void storeEntity (EntityEnterpriseContext ctx) throws java.rmi.RemoteException JavaDoc
442    {
443       try
444       {
445          storeEntity (ctx.getId (), ctx.getInstance ());
446       }
447       catch (Exception JavaDoc e)
448       {
449          throw new java.rmi.RemoteException JavaDoc (e.toString ());
450       }
451    }
452
453    /**
454     * This method is called when an entity shall be passivate. The persistence
455     * manager must call the ejbPassivate method on the instance.
456     *
457     * <p>See the activate discussion for the reason for exposing EJB callback
458     * calls to the store.
459     *
460     * @param instance the instance to passivate
461     *
462     * @throws java.rmi.RemoteException thrown if some system exception occurs
463     */

464    public void passivateEntity (EntityEnterpriseContext instance)
465    {
466       // This plugin doesn't do anything specific
467
}
468
469    /**
470     * This method is called when an entity shall be removed from the
471     * underlying storage. The persistence manager must call ejbRemove on the
472     * instance and then remove its state from the underlying storage.
473     *
474     * @param ctx the instance to remove
475     *
476     * @throws java.rmi.RemoteException thrown if some system exception occurs
477     * @throws javax.ejb.RemoveException thrown if the instance could not be removed
478     */

479    public void removeEntity (EntityEnterpriseContext ctx) throws javax.ejb.RemoveException JavaDoc
480    {
481       try
482       {
483       if (this.ds.remove (this.DS_CATEGORY, ctx.getId ().toString (), false) == null)
484          throw new javax.ejb.RemoveException JavaDoc ("Could not remove bean:" +
485          ctx.getId ());
486       }
487       catch (Exception JavaDoc e)
488       {
489          throw new javax.ejb.RemoveException JavaDoc (e.toString ());
490       }
491    }
492
493    // Y overrides ---------------------------------------------------
494

495    // Package protected ---------------------------------------------
496

497    // Protected -----------------------------------------------------
498

499    protected void storeEntity (Object JavaDoc id, Object JavaDoc obj) throws Exception JavaDoc
500    {
501       try
502       {
503          // Store fields
504
java.io.ByteArrayOutputStream JavaDoc baos = new java.io.ByteArrayOutputStream JavaDoc ();
505          java.io.ObjectOutputStream JavaDoc out = new org.jboss.ejb.plugins.CMPClusteredInMemoryPersistenceManager.CMPObjectOutputStream (baos);
506
507          Field JavaDoc[] f = obj.getClass ().getFields ();
508          for (int i = 0; i < f.length; i++)
509          {
510             out.writeObject (f[i].get (obj));
511          }
512
513          out.close ();
514
515          this.ds.set (this.DS_CATEGORY, id.toString (), baos.toByteArray (), false);
516
517       } catch (Exception JavaDoc e)
518       {
519          throw new EJBException JavaDoc ("Store failed", e);
520       }
521    }
522
523    // Private -------------------------------------------------------
524

525    // Inner classes -------------------------------------------------
526

527    static class CMPObjectOutputStream extends java.io.ObjectOutputStream JavaDoc
528    {
529       public CMPObjectOutputStream (java.io.OutputStream JavaDoc out) throws IOException JavaDoc
530       {
531          super (out);
532          enableReplaceObject (true);
533       }
534
535       protected Object JavaDoc replaceObject (Object JavaDoc obj)
536       throws IOException JavaDoc
537       {
538          if (obj instanceof javax.ejb.EJBObject JavaDoc)
539             return ((javax.ejb.EJBObject JavaDoc)obj).getHandle ();
540
541          return obj;
542       }
543    }
544
545    static class CMPObjectInputStream extends java.io.ObjectInputStream JavaDoc
546    {
547       public CMPObjectInputStream (java.io.InputStream JavaDoc in) throws IOException JavaDoc
548       {
549          super (in);
550          enableResolveObject (true);
551       }
552
553       protected Object JavaDoc resolveObject (Object JavaDoc obj)
554       throws IOException JavaDoc
555       {
556          if (obj instanceof javax.ejb.Handle JavaDoc)
557             return ((javax.ejb.Handle JavaDoc)obj).getEJBObject ();
558
559          return obj;
560       }
561    }
562
563 }
564
Popular Tags