Yes I agree it should be replicating, the problem is that it isn't. I must be
doing something wrong, but for the life of me I can't see what it is. I've
gone through all of the tutorials and reference pages, and my configuration
seems correct. The synchronous replication of the cached objects in the
TreeCacheAop just doesn't happen as advertised. When a new object is added to
the TreeCacheAop it's correctly replicated into the other TreeCacheAops on all
nodes of the cluster, but any subsequent modifications of the cached objects
are not replicated, and everything quickly becomes out of sync.
Below is a summary of my configuration and code, hopefully someone can see
where I'm going awry:
The class which uses the TreeCacheAop is UserActivityManager, which is a Simple
MBean. This class has methods which are invoked by Servlets and other MBeans
to update UserActivity JavaBean objects which are being cached. As mentioned
in the original post these objects are being "aspectized" by virtue of the
entry in jboss-aop.xml. The jboss-service.xml included in my SAR is as follows:
<?xml version="1.0" encoding="UTF-8"?>
|
| <server>
|
| <mbean code="org.jboss.cache.aop.TreeCacheAop"
| name="jboss.cache:service=TreeCacheAop">
| <depends>jboss:service=Naming</depends>
| <depends>jboss:service=TransactionManager</depends>
| <attribute
name="TransactionManagerLookupClass">org.jboss.cache.JBossTransactionManagerLookup</attribute>
| <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
| <attribute name="CacheMode">REPL_SYNC</attribute>
| <attribute name="UseReplQueue">false</attribute>
| <attribute name="ReplQueueInterval">0</attribute>
| <attribute name="ReplQueueMaxElements">0</attribute>
| <attribute name="ClusterName">TreeCache-Cluster</attribute>
| <attribute name="ClusterConfig">
| <config>
| <UDP mcast_addr="228.1.2.83"
| mcast_port="45556"
| ip_ttl="64"
| ip_mcast="true"
| mcast_send_buf_size="150000"
| mcast_recv_buf_size="80000"
| ucast_send_buf_size="150000"
| ucast_recv_buf_size="80000"
| loopback="false"/>
| <PING timeout="2000"
| num_initial_members="3"
| up_thread="false"
| down_thread="false"/>
| <MERGE2 min_interval="10000"
| max_interval="20000"/>
| <FD_SOCK/>
| <VERIFY_SUSPECT timeout="1500"
| up_thread="false"
| down_thread="false"/>
| <pbcast.NAKACK gc_lag="50"
| retransmit_timeout="600,1200,2400,4800"
| up_thread="false"
| down_thread="false"/>
| <pbcast.STABLE desired_avg_gossip="20000"
| up_thread="false"
| down_thread="false"/>
| <UNICAST timeout="600,1200,2400"
| window_size="100"
| min_threshold="10"
| down_thread="false"/>
| <FRAG frag_size="8192"
| down_thread="false"
| up_thread="false"/>
| <pbcast.GMS join_timeout="5000"
| join_retry_timeout="2000"
| shun="true"
| print_local_addr="true"/>
| <pbcast.STATE_TRANSFER up_thread="true"
| down_thread="true"/>
| </config>
| </attribute>
| <attribute name="FetchStateOnStartup">true</attribute>
| <attribute name="InitialStateRetrievalTimeout">15000</attribute>
| <attribute name="SyncReplTimeout">10000</attribute>
| <attribute name="LockAcquisitionTimeout">30000</attribute>
| <attribute name="EvictionPolicyClass"></attribute>
| </mbean>
|
| <mbean code="com.mycom.grover.mbean.UserActivityManager"
| name="grover.management:service=UserActivityManager">
| <depends>jboss.cache:service=TreeCacheAop</depends>
| </mbean>
|
| </server>
A typical method of the UserActivityManager MBean which accesses the cached
UserActivity objects and updates a couple of Date properties:
/**
| * Updates the user activity information for the specified user to
indicate the last time
| * the user accessed the system (heartbeat) and the last time the user
sent an IOI message.
| *
| * @param userId the user's ID
| * @throws MBeanException
| */
| public void updateMessageSentTime (String userId)
| throws MBeanException
| {
| // handle a null/blank parameter
| if ((userId == null) || (userId.trim().equals("")))
| {
| // log the error and throw a new Exception
| this.logger.error("Required user ID parameter was either null
or blank");
| throw new MBeanException(new IllegalArgumentException("Required
user ID parameter was either null or blank"));
| }
|
|
| // create and begin a transaction
| UserTransaction userTransaction;
| try
| {
| userTransaction = (UserTransaction)
this.jndiContext.lookup("UserTransaction");
| userTransaction.begin();
| }
| catch (Exception e)
| {
| // log the error and throw an Exception
| this.logger.error("Unable to create and begin a
UserTransaction", e);
| throw new MBeanException(e, "Unable to create and begin a
UserTransaction");
| }
|
|
| try
| {
| // get the UserActivity for the user, creating one if one
doesn't already exist
| UserActivity userActivity = getUserActivity(userId, new
Boolean(true));
|
| // set the heartbeat and message sent times
| userActivity.setHeartbeatTime(new Date());
| userActivity.setMessageSentTime(new Date());
|
| // commit the transaction
| userTransaction.commit();
| }
| catch (Exception e)
| {
| try
| {
| // rollback the exception
| userTransaction.setRollbackOnly();
| }
| catch (SystemException e2)
| {
| // log the error
| this.logger.error("Unable to set the UserTransaction for
rollback", e2);
| }
|
| // log the error and throw an Exception
| this.logger.error("Unable to update the user activity
information for the user with ID " + userId, e);
| throw new MBeanException(e, "Unable to update the user activity
information for the user with ID " + userId);
| }
| }
|
|
| /**
| * Gets the cached UserActivity object for the specified user, or null
if a
| * corresponding UserActivity object for the specified user is not
found and
| * not requested to be created (as specified by the create parameter).
| *
| * NO TRANSACTION
| *
| * @param userId the user's ID
| * @param create whether or not we should create a new UserActivity
object for the
| * user if one doesn't already exist
| * @return a dynamic proxy for the user's cached UserActivity object,
or null if a
| * UserActivity object for the specified user is not found and
the create
| * argument is either null or false
| * @throws MBeanException
| */
| private UserActivity getUserActivity (String userId,
| Boolean create)
| throws MBeanException
| {
| // handle a null/blank parameter
| if ((userId == null) || (userId.trim().equals("")))
| {
| // log the error and throw a new Exception
| this.logger.error("Required user ID parameter was either null
or blank");
| throw new MBeanException(new IllegalArgumentException("Required
user ID parameter was either null or blank"));
| }
|
|
| // get the corresponding fully qualified name of the
UserActivity object for the user
| // (this will be null if the user's activity information
doesn't yet exist)
| String fullyQualifiedName = getFullyQualifiedName(userId);
|
|
| // get the proxy for the cached UserActivity for the user if it
already exists
| if (fullyQualifiedName != null)
| {
| try
| {
| // get the dynamic proxy for the UserActivity object which
is cached for the user
| UserActivity userActivity =
| (UserActivity)
this.mbeanServer.invoke(this.cacheServiceName,
| "getObject",
| new Object[]
{fullyQualifiedName},
| new String[]
{String.class.getName()});
|
| // return the proxy for the user's cached UserActivity
object
| return userActivity;
| }
| catch (Exception e)
| {
| // log the error and throw an Exception
| this.logger.error("Unable to get the cached UserActivity
object for the user with ID " + userId, e);
| throw new MBeanException(e, "Unable to get the cached
UserActivity object for the user with ID " + userId);
| }
| }
| else if ((create != null) && create.booleanValue())
| {
| // get the user's Preferences
| Preferences preferences = null;
| try
| {
| // get the PreferencesAccess EJB
| PreferencesAccessHome preferencesAccessHome =
| (PreferencesAccessHome)
ServiceLocator.getInstance().getRemoteHome("ejb/PreferencesAccess",
PreferencesAccessHome.class);
| PreferencesAccess preferencesAccess =
preferencesAccessHome.create();
|
| // get the user's Preferences Data Transfer Object
| preferences = preferencesAccess.getPreferences(userId);
| }
| catch (Exception e)
| {
| // log the error and throw a new Exception
| this.logger.error("Unable to get Preferences for the user
with ID " + userId, e);
| throw new MBeanException(e, "Unable to get Preferences for
the user with ID " + userId);
| }
|
|
| // get the cache node name to use based on the user type
| String nodeName;
| if (preferences.isHimUser())
| {
| nodeName = NODE_HIM_USERS;
| }
| else if (preferences.isWebUser())
| {
| nodeName = NODE_WEB_USERS;
| }
| else
| {
| // log the error and throw a new Exception
| this.logger.error("Unable to determine the user type (HIM
or WEB) for the user with ID " + userId);
| throw new MBeanException(new Exception("Unable to determine
the user type (HIM or WEB) for the user with ID " + userId));
| }
|
| // create the fully qualified name using the node name and user
ID
| fullyQualifiedName = nodeName + "/" + userId;
|
| try
| {
| // create a UserActivity object and set the login time
| UserActivity userActivity = new UserActivity(preferences);
| userActivity.setLoginTime(new Date());
|
| // add the UserActivity to the TreeCache
| this.mbeanServer.invoke(this.cacheServiceName,
| "putObject",
| new Object[] {fullyQualifiedName,
userActivity},
| new String[]
{String.class.getName(), Object.class.getName()});
|
| // get the dynamic proxy for the UserActivity object which
is cached for the user
| userActivity = (UserActivity)
this.mbeanServer.invoke(this.cacheServiceName,
|
"getObject",
| new
Object[] {fullyQualifiedName},
| new
String[] {String.class.getName()});
|
| // return the dynamic proxy for the user's cached
UserActivity object
| return userActivity;
| }
| catch (Exception e)
| {
| // log the error and throw an Exception
| this.logger.error("Unable to cache a UserActivity object
for the user with ID " + userId +
| " using the fully qualified name " +
fullyQualifiedName);
| throw new MBeanException(new Exception("Unable to cache a
UserActivity object for the user with ID " + userId +
| " using the fully
qualified name " + fullyQualifiedName));
| }
| }
| else
| {
| // a corresponding UserActivity object wasn't found in the
cache,
| // and we don't want to create and cache a new one
| return null;
| }
| }
|
|
| /**
| * Get the fully qualified name for the UserActivity object for a user
with
| * the specified user ID. If the user has no cached UserActivity record
| * (doesn't exist) then a null string is returned.
| *
| * NO TRANSACTION
| *
| [EMAIL PROTECTED] userId the user's ID
| [EMAIL PROTECTED] the fully qualified name of the user's UserActivity
record,
| * or null if one doesn't yet exist
| [EMAIL PROTECTED] MBeanException
| */
| private String getFullyQualifiedName (String userId)
| throws MBeanException
| {
| // build fully qualified names using the node names and the user ID
| String himName = NODE_HIM_USERS + "/" + userId;
| String webName = NODE_WEB_USERS + "/" + userId;
|
| try
| {
| // see if a UserActivity object exists for the user under the
HIM node
| Boolean userExists =
| (Boolean) this.mbeanServer.invoke(this.cacheServiceName,
| "exists",
| new Object[] {himName},
| new String[]
{String.class.getName()});
|
| if (userExists.booleanValue())
| {
| // the fully qualified name using the HIM node is correct
| return himName;
| }
| else
| {
| // see if a UserActivity object exists for the user under
the WEB node
| userExists = (Boolean)
this.mbeanServer.invoke(this.cacheServiceName,
| "exists",
| new Object[]
{webName},
| new String[]
{String.class.getName()});
| if (userExists.booleanValue())
| {
| // the fully qualified name using the WEB node is
correct
| return webName;
| }
| else
| {
| // a UserActivity object doesn't yet exist for the user
| // and hence no corresponding fully qualified name is
available
| return null;
| }
| }
| }
| catch (Exception e)
| {
| // log the error and throw a new Exception
| this.logger.warn("Unable to find the fully qualified name for
user with ID " + userId, e);
| throw new MBeanException(e, "Unable to find the fully qualified
name for user with ID " + userId);
| }
| }
As you can see in the updateMessageSentTime() method the entire process of
updating the cached UserActivity object's properties is done within a
UserTransaction. All other methods which access the cached UserActivity
objects follow the same pattern.
Any suggestions would be greatly appreciated!
--James
View the original post :
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3876312#3876312
Reply to the post :
http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=3876312
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4
opportunities to win big! Highest score wins.NEC IT Guy Games. Play to
win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
JBoss-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jboss-user