[jboss-svn-commits] JBL Code SVN: r37814 - in labs/jbosstm/branches/JBOSSTS_4_16: ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/tools and 2 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Dec 15 16:43:39 EST 2011


Author: mmusgrov
Date: 2011-12-15 16:43:39 -0500 (Thu, 15 Dec 2011)
New Revision: 37814

Added:
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBean.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBeanMBean.java
Modified:
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBean.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBeanWrapperInterface.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/LogRecordWrapper.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ObjStoreBrowser.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/UidWrapper.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/tools/ObjStoreBrowserTest.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/JTAActionBean.java
   labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jts/ArjunaTransactionImpleWrapper.java
Log:
JBTM-1000 and JBTM-995 (the new system property is ObjStoreBrowserHandlers.OBJ_STORE_BROWSER_HANDLERS)

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBean.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBean.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBean.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -1,308 +1,417 @@
 package com.arjuna.ats.arjuna.tools.osb.mbean;
 
+import com.arjuna.ats.arjuna.coordinator.BasicAction;
 import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome;
 import com.arjuna.ats.arjuna.logging.tsLogger;
-import com.arjuna.ats.arjuna.AtomicAction;
 import com.arjuna.ats.arjuna.common.Uid;
 import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
 import com.arjuna.ats.arjuna.coordinator.RecordList;
-import com.arjuna.ats.arjuna.coordinator.TxControl;
 import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
 import com.arjuna.ats.arjuna.objectstore.StoreManager;
 import com.arjuna.ats.arjuna.tools.osb.util.JMXServer;
 
 import java.lang.reflect.Constructor;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
 
 /**
  * MBean implementation of an ObjectStore entry that represents an AtomicAction
  */
 public class ActionBean extends OSEntryBean implements ActionBeanMBean {
-	// Basic properties this enty
-	private StateManagerWrapper sminfo;
-	// collection of participants belonging to this BasicAction
-	private Collection<LogRecordWrapper> participants = new ArrayList<LogRecordWrapper>();
-	// wrapper around the real AtomicAction
-	private ActionBeanWrapperInterface ra;
+    // Basic properties this enty
+    private StateManagerWrapper sminfo;
+    // collection of participants belonging to this BasicAction
+    private Collection<LogRecordWrapper> participants = new ArrayList<LogRecordWrapper>();
+    // wrapper around the real AtomicAction
+    protected ActionBeanWrapperInterface ra;
 
-	public ActionBean(UidWrapper w) {
-		super(w);
+    public ActionBean(UidWrapper w) {
+        super(w);
 
-		boolean isJTS = JMXServer.isJTS() && w.getType().endsWith("ArjunaTransactionImple");
-		// Participants in a JTS transaction are represented by entries in the ObjectStore
-		List<UidWrapper> recuids = null;
+        boolean isJTS = JMXServer.isJTS() && w.getType().endsWith("ArjunaTransactionImple");
+        // Participants in a JTS transaction are represented by entries in the ObjectStore
+        List<UidWrapper> recuids = null;
 
-		if (isJTS) {
-			try {
-				Class<ActionBeanWrapperInterface> cl = (Class<ActionBeanWrapperInterface>) Class.forName(JMXServer.AJT_WRAPPER_TYPE);
-				Constructor<ActionBeanWrapperInterface> constructor = cl.getConstructor(ActionBean.class, UidWrapper.class);
-				ra = constructor.newInstance(this, w);
-			} catch (Exception e) { // ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException
-				if (tsLogger.logger.isTraceEnabled())
-					tsLogger.logger.trace("Error constructing " + JMXServer.AJT_WRAPPER_TYPE + ": " + e);
-				ra = new AtomicActionWrapper(w);
-			}
-		} else {
-			ra = new AtomicActionWrapper(w);
-		}
+        if (isJTS) {
+            try {
+                Class<ActionBeanWrapperInterface> cl = (Class<ActionBeanWrapperInterface>) Class.forName(JMXServer.AJT_WRAPPER_TYPE);
+                Constructor<ActionBeanWrapperInterface> constructor = cl.getConstructor(ActionBean.class, UidWrapper.class);
+                ra = constructor.newInstance(this, w);
+                ra.activate();
+            } catch (Exception e) { // ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException
+                if (tsLogger.logger.isTraceEnabled())
+                    tsLogger.logger.trace("Error constructing " + JMXServer.AJT_WRAPPER_TYPE + ": " + e);
+                ra = createWrapper(w, true);
+            }
 
-		ra.activate();
-		sminfo = new StateManagerWrapper(StoreManager.getRecoveryStore(), getUid(), getType());
+            /*
+                * for JTS actions the participants will have entries in the ObjectStore.
+                * these entries will be associated with the current MBean (refer to
+                * the method findParticipants below for details)
+                */
+            recuids = w.probe(JMXServer.AJT_RECORD_TYPE, JMXServer.AJT_XAREC_TYPE);
+        } else {
+            ra = createWrapper(w, true);  // com.arjuna.ats.arjuna.coordinator.abstractrecord.RecordTypeManager.manager()
+        }
 
-		if (isJTS) {
-			/*
-			 * for JTS actions the participants will have entries in the ObjectStore.
-			 * these entries will be associated with the current MBean (refer to
-			 * the method findParticipants below for details)
-			 */
-			recuids = w.probe(JMXServer.AJT_RECORD_TYPE, JMXServer.AJT_XAREC_TYPE);
-		}
+        sminfo = new StateManagerWrapper(StoreManager.getRecoveryStore(), getUid(), getType());
 
-		for (ParticipantStatus lt : ParticipantStatus.values()) {
-			findParticipants(recuids, ra.getRecords(lt), lt);
-		}
-	}
+        for (ParticipantStatus lt : ParticipantStatus.values()) {
+            findParticipants(recuids, ra.getRecords(lt), lt);
+        }
+    }
 
-	public StringBuilder toString(String prefix, StringBuilder sb) {
-		ra.toString(prefix, sb);
-		prefix += '\t';
-		sb.append('\n').append(prefix).append(sminfo.getCreationTime());
-		sb.append('\n').append(prefix).append(sminfo.getAgeInSeconds());
+    protected ActionBeanWrapperInterface createWrapper(UidWrapper w, boolean activate) {
+        GenericAtomicActionWrapper action = new GenericAtomicActionWrapper(w.getClassName(), w);
 
-		for (LogRecordWrapper p : participants) {
-			p.toString(prefix, sb);
-		}
+        if (activate)
+            action.activate();
 
-		return sb;
-	}
+        return action;
+    }
 
-	/**
-	 * return the Uid for given AbstractRecord
-	 * @param rec the record whose Uid is required
-	 * @return  the Uid of the requested record
-	 */
-	public Uid getUid(AbstractRecord rec) {
-		return ra.getUid(rec);
-	}
 
-	/**
-	 * Remove this AtomicAction from the ObjectStore
-	 * @return a textual indication of whether the remove operation succeeded
-	 */
-	public String remove() {
-		try {
-			if (!StoreManager.getRecoveryStore().remove_committed(getUid(), getType()))
-				return "remove committed failed"; // TODO com.arjuna.ats.arjuna.tools.osb.mbean.m_1
-			else
-				w.probe();
+    public StringBuilder toString(String prefix, StringBuilder sb) {
+        ra.toString(prefix, sb);
+        prefix += '\t';
+        sb.append('\n').append(prefix).append(sminfo.getCreationTime());
+        sb.append('\n').append(prefix).append(sminfo.getAgeInSeconds());
 
-			return "remove ok"; // TODO com.arjuna.ats.arjuna.tools.osb.mbean.m_2
-		} catch (ObjectStoreException e) {
-			return "remove committed exception: " + e.getMessage(); // TODO com.arjuna.ats.arjuna.tools.osb.mbean.m_3
-		}
-	}
+        for (LogRecordWrapper p : participants) {
+            p.toString(prefix, sb);
+        }
 
-	/**
-	 * create MBean representations of the participants of this transaction
-	 * @param recuids some transaction participants are represented in the ObjectStore
-	 * - if this is the case then recuids contains a list of MBean wrappers representing them.
-	 * Otherwise this list will be empty.
-	 * @param list the records representing the participants
-	 * @param listType indicates the type of the records in list (PREPARED, PENDING, FAILED, READONLY, HEURISTIC)
-	 */
-	private void findParticipants(List<UidWrapper> recuids, RecordList list, ParticipantStatus listType) {
-		if (list != null) {
-			for (AbstractRecord rec = list.peekFront(); rec != null; rec = list.peekNext(rec)) {
-				LogRecordWrapper lw;
-				int i = recuids == null ? -1 : recuids.indexOf(new UidWrapper(ra.getUid(rec)));
+        return sb;
+    }
 
-				if (i != -1) {
-					OSEntryBean p = recuids.get(i).getMBean();
+    /**
+     * return the Uid for given AbstractRecord
+     * @param rec the record whose Uid is required
+     * @return  the Uid of the requested record
+     */
+    public Uid getUid(AbstractRecord rec) {
+        return ra.getUid(rec);
+    }
 
-					if (p instanceof LogRecordWrapper) {
-						lw = (LogRecordWrapper) p;
-						lw.init(this, rec, listType);
-					} else {
-						if (tsLogger.logger.isTraceEnabled())
-							tsLogger.logger.trace("participant record is not a LogRecordWrapper");
-						lw = createParticipant(rec, listType);
-					}
-				} else {
-					lw = createParticipant(rec, listType);
-				}
+    /**
+     * Remove this AtomicAction from the ObjectStore
+     * @return a textual indication of whether the remove operation succeeded
+     */
+    public String remove() {
+        try {
+            if (!StoreManager.getRecoveryStore().remove_committed(getUid(), getType()))
+                return "Attempt to remove transaction failed";
+            else
+                w.probe();
 
-				lw.activate();				
-				participants.add(lw);
-			}
-		}
-	}
+            return "Transaction successfully removed";
+        } catch (ObjectStoreException e) {
+            return "Unable to remove transaction: " + e.getMessage();
+        }
+    }
 
-	/**
-	 * Extension point for other Bean implementations to provide an implementation bean for its participants.
-	 * For example @see com.arjuna.ats.internal.jta.tools.osb.mbean.jta.JTAActionBean
-	 * @param rec the record that should be represented by an MBean
-	 * @param listType the status of the record
-	 * @return the MBean implementation of the participant
-	 */
-	protected LogRecordWrapper createParticipant(AbstractRecord rec, ParticipantStatus listType) {
-		return new LogRecordWrapper(this, rec, listType);
-	}
+    /**
+     * create MBean representations of the participants of this transaction
+     * @param recuids some transaction participants are represented in the ObjectStore
+     * - if this is the case then recuids contains a list of MBean wrappers representing them.
+     * Otherwise this list will be empty.
+     * @param list the records representing the participants
+     * @param listType indicates the type of the records in list (PREPARED, PENDING, FAILED, READONLY, HEURISTIC)
+     */
+    private void findParticipants(List<UidWrapper> recuids, RecordList list, ParticipantStatus listType) {
+        if (list != null) {
+            for (AbstractRecord rec = list.peekFront(); rec != null; rec = list.peekNext(rec)) {
+                LogRecordWrapper lw;
+                int i = recuids == null ? -1 : recuids.indexOf(new UidWrapper(ra.getUid(rec)));
 
-	/**
-	 * See if there is participant Bean corresponding to the given record
-	 * @param rec the record for the target participant
-	 * @return the bean corresponding to the requested record
-	 */
-	public LogRecordWrapper getParticipant(AbstractRecord rec) {
-		for (LogRecordWrapper w : participants)
-			if (w.getRecord().equals(rec))
-				return w;
+                if (i != -1) {
+                    OSEntryBean p = recuids.get(i).getMBean();
 
-		return null;
-	}
+                    if (p instanceof LogRecordWrapper) {
+                        lw = (LogRecordWrapper) p;
+                        lw.init(this, rec, listType);
+                    } else {
+                        if (tsLogger.logger.isTraceEnabled())
+                            tsLogger.logger.trace("participant record is not a LogRecordWrapper");
+                        lw = createParticipant(rec, listType);
+                    }
+                } else {
+                    lw = createParticipant(rec, listType);
+                }
 
-	/**
-	 * register this bean (and its participants) with the MBeanServer
-	 */
-	public void register() {
-		super.register();
+                lw.activate();
+                participants.add(lw);
+            }
+        }
+    }
 
-		for (LogRecordWrapper p : participants)
-			JMXServer.getAgent().registerMBean(p.getName(), p);
-	}
+    /**
+     * Extension point for other Bean implementations to provide an implementation bean for its participants.
+     * For example @see com.arjuna.ats.internal.jta.tools.osb.mbean.jta.JTAActionBean
+     * @param rec the record that should be represented by an MBean
+     * @param listType the status of the record
+     * @return the MBean implementation of the participant
+     */
+    protected LogRecordWrapper createParticipant(AbstractRecord rec, ParticipantStatus listType) {
+        return new LogRecordWrapper(this, rec, listType);
+    }
 
-	/**
-	 * unregister this bean (and its participants) with the MBeanServer
-	 */
-	public void unregister() {
-		for (LogRecordWrapper p : participants)
-			JMXServer.getAgent().unregisterMBean(p.getName());
+    /**
+     * See if there is participant Bean corresponding to the given record
+     * @param rec the record for the target participant
+     * @return the bean corresponding to the requested record
+     */
+    public LogRecordWrapper getParticipant(AbstractRecord rec) {
+        for (LogRecordWrapper w : participants)
+            if (w.getRecord().equals(rec))
+                return w;
 
-		super.unregister();
-	}
+        return null;
+    }
 
-	public long getAgeInSeconds() {
-		return sminfo.getAgeInSeconds();
-	}
+    /**
+     * register this bean (and its participants) with the MBeanServer
+     */
+    public void register() {
+        super.register();
 
-	public String getCreationTime() {
-		return sminfo.getCreationTime();
-	}
+        for (LogRecordWrapper p : participants)
+            JMXServer.getAgent().registerMBean(p.getName(), p);
+    }
 
-	public boolean isParticipant() {
-		return false;
-	}
+    /**
+     * unregister this bean (and its participants) with the MBeanServer
+     */
+    public void unregister() {
+        for (LogRecordWrapper p : participants)
+            JMXServer.getAgent().unregisterMBean(p.getName());
 
-	/**
-	 * Request a change in status of a participant. For example if a record has a
-	 * heuristic status then this method could be used to move it back into the
-	 * prepared state so that the recovery system can replay phase 2 of the
-	 * committment protocol
-	 * @param logrec the record whose status is to be changed
-	 * @param newStatus the desired status
-	 * @return true if the status was changed
-	 */
-	public boolean setStatus(LogRecordWrapper logrec, ParticipantStatus newStatus) {
-		ParticipantStatus lt = logrec.getListType();
-		AbstractRecord targRecord = logrec.getRecord();
+        super.unregister();
+    }
 
-		RecordList oldList = ra.getRecords(lt);
-		RecordList newList = ra.getRecords(newStatus);
+    public long getAgeInSeconds() {
+        return sminfo.getAgeInSeconds();
+    }
 
-		if (lt.equals(ParticipantStatus.HEURISTIC) && !targRecord.forgetHeuristic()) {
-			return false;
-		}
+    public String getCreationTime() {
+        return sminfo.getCreationTime();
+    }
 
-		// move the record from currList to targList
-		if (oldList.remove(targRecord)) {
-			
-			if (newList.insert(targRecord)) {
-				if (lt.equals(ParticipantStatus.HEURISTIC)) {
-					switch (newStatus) {
-						case FAILED:
-							ra.clearHeuristicDecision(TwoPhaseOutcome.FINISH_ERROR);
-							break;
-						case PENDING:
-							ra.clearHeuristicDecision(TwoPhaseOutcome.NOT_PREPARED);
-							break;
-						case PREPARED:
-							ra.clearHeuristicDecision(TwoPhaseOutcome.PREPARE_OK);
-							break;
-						case READONLY:
-							ra.clearHeuristicDecision(TwoPhaseOutcome.PREPARE_READONLY);
-							break;
-						default:
-							break;
-					}
-				}
+    public boolean isParticipant() {
+        return false;
+    }
 
-				ra.doUpdateState();
-				
-				return true;
-			}
-		}
+    /**
+     * Request a change in status of a participant. For example if a record has a
+     * heuristic status then this method could be used to move it back into the
+     * prepared state so that the recovery system can replay phase 2 of the
+     * commitment protocol
+     * @param logrec the record whose status is to be changed
+     * @param newStatus the desired status
+     * @return true if the status was changed
+     */
+    public boolean setStatus(LogRecordWrapper logrec, ParticipantStatus newStatus) {
+        ParticipantStatus lt = logrec.getListType();
+        AbstractRecord targRecord = logrec.getRecord();
 
-		return false;
-	}
+        RecordList oldList = ra.getRecords(lt);
+        RecordList newList = ra.getRecords(newStatus);
 
-	/**
-	 *
-	 * @return the MBeans corresponding to the participants within this action
-	 */
-	public Collection<LogRecordWrapper> getParticipants() {
-		return Collections.unmodifiableCollection(participants);
-	}
+        if (lt.equals(ParticipantStatus.HEURISTIC) && !targRecord.forgetHeuristic()) {
+            return false;
+        }
 
-	/**
-	 * The ActionBean needs access to the participant lists maintained by an AtomicAction but these
-	 * lists are protected. Therefore define a simple extension class to get at these records:
-	 */
-	class AtomicActionWrapper extends AtomicAction implements ActionBeanWrapperInterface {
-		boolean activated;
+        // move the record from currList to targList
+        if (oldList.remove(targRecord)) {
 
-		public AtomicActionWrapper(UidWrapper w) {
-			super(w.getUid());
-		}
+            if (newList.insert(targRecord)) {
+                if (lt.equals(ParticipantStatus.HEURISTIC)) {
+                    switch (newStatus) {
+                        case FAILED:
+                            ra.clearHeuristicDecision(TwoPhaseOutcome.FINISH_ERROR);
+                            break;
+                        case PENDING:
+                            ra.clearHeuristicDecision(TwoPhaseOutcome.NOT_PREPARED);
+                            break;
+                        case PREPARED:
+                            ra.clearHeuristicDecision(TwoPhaseOutcome.PREPARE_OK);
+                            break;
+                        case READONLY:
+                            ra.clearHeuristicDecision(TwoPhaseOutcome.PREPARE_READONLY);
+                            break;
+                        default:
+                            break;
+                    }
+                }
 
-		public boolean activate() {
-			if (!activated)
-				activated = super.activate();
+                ra.doUpdateState();
 
-			return activated;
-		}
+                return true;
+            }
+        }
 
-		public void doUpdateState() {
-			updateState();
-		}
+        return false;
+    }
 
-		public Uid getUid(AbstractRecord rec) {
-			return get_uid();
-		}
-		
-		public StringBuilder toString(String prefix, StringBuilder sb) {
-			prefix += '\t';
-			return sb.append('\n').append(prefix).append(get_uid());
-		}
+    /**
+     *
+     * @return the MBeans corresponding to the participants within this action
+     */
+    public Collection<LogRecordWrapper> getParticipants() {
+        return Collections.unmodifiableCollection(participants);
+    }
 
-		public void clearHeuristicDecision(int newDecision) {
-			if (super.heuristicList.size() == 0)
-				setHeuristicDecision(newDecision);
-		}
+    /**
+     * The ActionBean needs access to the participant lists maintained by an AtomicAction but these
+     * lists are protected. Therefore define a simple extension class to get at these records:
+     */
+    public class GenericAtomicActionWrapper implements ActionBeanWrapperInterface {
+        boolean activated;
+        BasicAction action;
+        Map<String, RecordList> recs;
+        Method setHeuristicDecision;
+        Method updateState = null;
+        UidWrapper uidWrapper;
 
-		public RecordList getRecords(ParticipantStatus type) {
-			switch (type) {
-				default:
-				case PREPARED: return preparedList;
-				case FAILED: return failedList;
-				case HEURISTIC: return heuristicList;
-				case PENDING: return pendingList;
-				case READONLY: return readonlyList;
-			}
-		}
-	}
+        public GenericAtomicActionWrapper(String classType, UidWrapper w) {
+            uidWrapper = w;
+            recs = new HashMap<String, RecordList>();
 
+            if (classType == null)
+                classType = "com.arjuna.ats.arjuna.AtomicAction";
+
+            try {
+                Class cls = Class.forName(classType);
+                Class pTypes[] = new Class[1];
+                pTypes[0] = Uid.class;
+                Constructor ctor = cls.getConstructor(pTypes);
+                Object args[] = new Object[1];
+                args[0] = w.getUid();
+                action = (BasicAction) ctor.newInstance(args);
+
+                setHeuristicDecision = getMethod(action.getClass(), "setHeuristicDecision", int.class);
+                updateState = getMethod(action.getClass(), "updateState");
+
+                if (setHeuristicDecision != null)
+                    setHeuristicDecision.setAccessible(true);
+
+                if (updateState != null)
+                    updateState.setAccessible(true);
+
+            } catch (Exception e) {
+                action = null;
+
+                if (tsLogger.logger.isDebugEnabled())
+                    tsLogger.logger.debug("unable to create log wrapper for type " + w.getType() + ": error: " + e.getMessage());
+            }
+        }
+
+        public BasicAction getAction() {
+            return action;
+        }
+
+        public boolean activate() {
+            if (!activated && action != null) {
+                activated = action.activate();
+            }
+
+            return activated;
+        }
+
+        public void doUpdateState() {
+            if (updateState != null && action != null) {
+                try {
+                    updateState.invoke(action);
+                } catch (IllegalAccessException e) {
+                    if (tsLogger.logger.isDebugEnabled())
+                        tsLogger.logger.debug("failed to update heuristic for " + action.toString() + ": error: " + e.getMessage());
+                } catch (InvocationTargetException e) {
+                    if (tsLogger.logger.isDebugEnabled())
+                        tsLogger.logger.debug("failed to update heuristic for " + action.toString() + ": error: " + e.getMessage());
+                }
+            }
+        }
+
+        public Uid get_uid() {
+            return action != null ? action.get_uid() : uidWrapper.getUid();
+        }
+
+        public Uid getUid(AbstractRecord rec) {
+            return rec.order(); //get_uid();
+        }
+
+        public StringBuilder toString(String prefix, StringBuilder sb) {
+            prefix += '\t';
+            return sb.append('\n').append(prefix).append(get_uid());
+        }
+
+        public void clearHeuristicDecision(int newDecision) {
+            RecordList rl = getRecords("heuristicList");
+
+            if (setHeuristicDecision != null && rl != null && rl.size() == 0)
+                try {
+                    setHeuristicDecision.invoke(action, newDecision);
+                } catch (IllegalAccessException e) {
+                    if (tsLogger.logger.isDebugEnabled())
+                        tsLogger.logger.debug("failed to update heuristic for " + action.toString() + ": error: " + e.getMessage());
+                } catch (InvocationTargetException e) {
+                    if (tsLogger.logger.isDebugEnabled())
+                        tsLogger.logger.debug("failed to update heuristic for " + action.toString() + ": error: " + e.getMessage());
+                }
+        }
+
+        private Field getField(Class cl, String fn) {
+            try {
+                return cl.getDeclaredField(fn);
+            } catch (NoSuchFieldException e) {
+                return getField(cl.getSuperclass(), fn);
+            }
+        }
+
+        private Method getMethod(Class cl, String mn, Class<?>... parameterTypes) {
+            try {
+                if (cl == null)
+                    return null;
+                return cl.getDeclaredMethod(mn, parameterTypes);
+            } catch (NoSuchMethodException e) {
+                return getMethod(cl.getSuperclass(), mn, parameterTypes);
+            }
+        }
+
+        public RecordList getRecords(String ln) {
+            if (action == null)
+                return null;
+
+            if (recs.containsKey(ln))
+                return recs.get(ln);
+
+            Field f = getField(action.getClass(), ln);
+            f.setAccessible(true);
+            try {
+                RecordList rl = (RecordList) f.get(action);
+
+                if (rl != null)
+                    recs.put(ln, rl);
+
+                return rl;
+            } catch (IllegalAccessException e) {
+                return null;
+            }
+        }
+
+        public RecordList getRecords(ParticipantStatus type) {
+
+            switch (type) {
+                default:
+                case PREPARED: return getRecords("preparedList");
+                case FAILED: return getRecords("failedList");
+                case HEURISTIC: return getRecords("heuristicList");
+                case PENDING: return getRecords("pendingList");
+                case READONLY: return getRecords("readonlyList");
+            }
+        }
+    }
 }

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBeanWrapperInterface.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBeanWrapperInterface.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ActionBeanWrapperInterface.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -2,6 +2,7 @@
 
 import com.arjuna.ats.arjuna.common.Uid;
 import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
+import com.arjuna.ats.arjuna.coordinator.BasicAction;
 import com.arjuna.ats.arjuna.coordinator.RecordList;
 
 /**
@@ -14,6 +15,7 @@
 	Uid get_uid();
 	Uid getUid(AbstractRecord rec);
 	StringBuilder toString(String prefix, StringBuilder sb);
+    BasicAction getAction();
 
     void clearHeuristicDecision(int newDecision);
 }
\ No newline at end of file

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/LogRecordWrapper.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/LogRecordWrapper.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/LogRecordWrapper.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -65,11 +65,18 @@
 	}
 
 	public String setStatus(ParticipantStatus newState) {
+        if (getListType().equals(newState))
+            return "participant is prepared for recovery";
+
 		if (parent != null && parent.setStatus(this, newState)) {
 			listType = newState;
-			return "status change was successful";
+
+            if (newState == ParticipantStatus.PREPARED )
+			    return "participant recovery will be attempted during the next recovery pass";
+
+            return "participant status change was successful";
 		} else {
-			return "failed";
+			return "participant status change failed";
 		}
 	}
 

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ObjStoreBrowser.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ObjStoreBrowser.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/ObjStoreBrowser.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -4,28 +4,34 @@
 import java.net.URL;
 import java.util.*;
 
+import com.arjuna.ats.arjuna.StateManager;
+import com.arjuna.ats.arjuna.common.arjPropertyManager;
 import com.arjuna.ats.arjuna.logging.tsLogger;
 import com.arjuna.ats.arjuna.common.Uid;
-import com.arjuna.ats.arjuna.coordinator.TxControl;
 import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
 import com.arjuna.ats.arjuna.objectstore.ObjectStoreIterator;
 import com.arjuna.ats.arjuna.objectstore.StoreManager;
 import com.arjuna.ats.arjuna.state.InputObjectState;
 import com.arjuna.ats.arjuna.tools.osb.util.JMXServer;
 
-import com.arjuna.ats.arjuna.common.*;
-
 /**
  * An MBean implementation for walking an ObjectStore and creating/deleting MBeans
  * that represent completing transactions (ie ones on which the user has called commit)
  */
 public class ObjStoreBrowser implements ObjStoreBrowserMBean {
+    public static final String OBJ_STORE_BROWSER_HANDLERS = "com.arjuna.ats.arjuna.tools.osb.mbean.ObjStoreBrowserHandlers";
 	private static final String STORE_MBEAN_NAME = "jboss.jta:type=ObjectStore";
-	private static final String OS_BEAN_PROPFILE = "osmbean.properties";
 
-    // define which object store types can be represented by mbeans
-	private Properties typeHandlers;
+    // defines a (default) map of object store types to the corresponding MBean for instrumentation.
+    // The format is OSType1=BeanType1,OSType2=BeanType2,etc
+    // Can be over-ridden by setting a system property called com.arjuna.ats.arjuna.tools.osb.mbean.ObjStoreBrowserHandlers
+    private static final String defaultStateHandlers =
+            "com.arjuna.ats.arjuna.AtomicAction=com.arjuna.ats.internal.jta.tools.osb.mbean.jta.JTAActionBean"
+//            + ",com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.SubordinateAtomicAction=com.arjuna.ats.internal.jta.tools.osb.mbean.jta.SubordinateActionBean"
+            + ",com.arjuna.ats.internal.jta.tools.osb.mbean.jts.ArjunaTransactionImpleWrapper=com.arjuna.ats.arjuna.tools.osb.mbean.ActionBean";
 
+    private Map<String, String> stateTypes = null; // defines which object store types will be instrumented
+    private Map<String, String> beanTypes = null;  // defines which bean types are used to represent object store types
 	private Map<String, List<UidWrapper>> allUids;
 
 	public static void main(String[] args) throws Exception {
@@ -106,13 +112,26 @@
      * as MBeans
      */
 	public void setTypes(Map<String, String> types) {
-		for (Map.Entry<String, String> entry : types.entrySet()) {
-			if (tsLogger.logger.isTraceEnabled())
-				tsLogger.logger.trace("ObjStoreBrowser: adding type handler " + entry.getKey() + "," + entry.getValue());
-			typeHandlers.put(entry.getKey(), entry.getValue());
-		}
 	}
 
+    private void initTypeHandlers(String handlers) {
+        for (String h : handlers.split(",")) {
+            String[] handler = h.split("=");
+
+            if (handler.length == 2) {
+                String typeName = getOSType(handler[0]);
+                if (typeName != null) {
+
+                    if (typeName.startsWith("/"))
+                        typeName = typeName.substring(1);
+
+                    stateTypes.put(typeName, handler[0]);
+                    beanTypes.put(typeName, handler[1]);
+                }
+            }
+        }
+    }
+
 	private void init(String logDir) {
 		if (logDir != null)
 			arjPropertyManager.getObjectStoreEnvironmentBean().setObjectStoreDir(logDir);
@@ -121,10 +140,11 @@
 			tsLogger.logger.trace("ObjectStoreDir: " + arjPropertyManager.getObjectStoreEnvironmentBean().getObjectStoreDir());
 
 		allUids = new HashMap<String, List<UidWrapper>> ();
-		typeHandlers = loadProperties(OS_BEAN_PROPFILE);
-        
-		if (typeHandlers.size() == 0)
-			typeHandlers = loadProperties("META-INF/" + OS_BEAN_PROPFILE);
+        stateTypes = new HashMap<String, String>();
+        beanTypes = new HashMap<String, String>();
+
+        initTypeHandlers(defaultStateHandlers);
+        initTypeHandlers(System.getProperty(OBJ_STORE_BROWSER_HANDLERS, ""));
 	}
 
 	public ObjStoreBrowser() {
@@ -164,7 +184,20 @@
 
 		return null;
 	}
+;
+    private String getOSType(String classType) {
+        try {
+            Class cls = Class.forName(classType);
+            StateManager sm = (StateManager) cls.getConstructor().newInstance();
 
+            return sm.type();
+        } catch (Exception e) {
+            if (tsLogger.logger.isDebugEnabled())
+                tsLogger.logger.debug("Invalid class type in system property ObjStoreBrowserHandlers: " + classType);
+        }
+
+        return null;
+    }
     /**
      * See if any new MBeans need to be registered or if any existing MBeans no longer exist
      * as ObjectStore entries.
@@ -187,8 +220,8 @@
 								allUids.put(tname, uids);
 							}
 
-							if (typeHandlers.containsKey(tname))
-								updateMBeans(uids, System.currentTimeMillis(), true, tname, typeHandlers.getProperty(tname));
+                            if (beanTypes.containsKey(tname))
+								updateMBeans2(uids, System.currentTimeMillis(), true, tname);
 						}
 					} catch (IOException e1) {
 						tname = "";
@@ -215,20 +248,21 @@
 
 		List<UidWrapper> uids = allUids.get(type);
 
-		updateMBeans(uids, System.currentTimeMillis(), false, type, beantype);
+		updateMBeans2(uids, System.currentTimeMillis(), false, type);
 
 		return uids;
 	}
 
-	private void updateMBeans(List<UidWrapper> uids, long tstamp, boolean register, String type, String thandler) {
+	private void updateMBeans2(List<UidWrapper> uids, long tstamp, boolean register, String type) {
 		ObjectStoreIterator iter = new ObjectStoreIterator(StoreManager.getRecoveryStore(), type);
 
 		while (true) {
 			Uid u = iter.iterate();
-			if (Uid.nullUid().equals(u))
+			if (u == null || Uid.nullUid().equals(u))
 				break;
 
-			UidWrapper w = new UidWrapper(this, thandler, type, u);
+
+			UidWrapper w = new UidWrapper(this, beanTypes.get(type), type, stateTypes.get(type), u);
 			int i = uids.indexOf(w);
 
 			if (i == -1) {

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/UidWrapper.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/UidWrapper.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/tools/osb/mbean/UidWrapper.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -13,6 +13,7 @@
 	private String name;
 	private ObjStoreBrowser browser;
 	private String beantype;
+    private String className;
 	private String ostype;
 	private Uid uid;
 	private long tstamp;
@@ -23,19 +24,22 @@
 		this.name = "";
 		this.beantype = "";
 		this.ostype = "";
+        this.className = null;
 	}
 
 	public OSEntryBean getMBean() {
 		return mbean;
 	}
 
-	public UidWrapper(ObjStoreBrowser browser, String beantype, String ostype, Uid uid) {
+	public UidWrapper(ObjStoreBrowser browser, String beantype, String ostype, String className, Uid uid) {
 		this.browser = browser;
 		this.ostype = ostype;
 		this.beantype = beantype;
+        this.className = className;
 		this.uid = uid;
 		this.tstamp = 0L;
 		this.name = "jboss.jta:type=ObjectStore,itype=" + ostype + ",uid=" + uid.fileStringForm(); // + ",participant=false";
+
 	}
 
     /**
@@ -53,6 +57,10 @@
 		return name;
 	}
 
+	public String getClassName() {
+		return className;
+	}
+
 	void register() {
 		mbean.register();
 	}

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/tools/ObjStoreBrowserTest.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/tools/ObjStoreBrowserTest.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/tools/ObjStoreBrowserTest.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -73,14 +73,10 @@
 	 * @return An object that maintains MBeans representing completing transactions
 	 */
 	private ObjStoreBrowser createObjStoreBrowser() {
-		ObjStoreBrowser osb = new ObjStoreBrowser();
-
 		// define which object store types we are prepared to represent by mbeans
-		osb.setTypes( new HashMap<String, String>() {{
-			put("StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction", "com.arjuna.ats.arjuna.tools.osb.mbean.ActionBean");
-		}});
+        System.setProperty("ObjStoreBrowserHandlers", "com.arjuna.ats.arjuna.AtomicAction=com.arjuna.ats.arjuna.tools.osb.mbean.ActionBean");
 
-		return osb;
+		return new ObjStoreBrowser();
 	}
 
 	@Test

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/JTAActionBean.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/JTAActionBean.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/JTAActionBean.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -1,10 +1,11 @@
 package com.arjuna.ats.internal.jta.tools.osb.mbean.jta;
 
+import com.arjuna.ats.arjuna.common.Uid;
 import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
-import com.arjuna.ats.arjuna.tools.osb.mbean.ActionBean;
-import com.arjuna.ats.arjuna.tools.osb.mbean.ParticipantStatus;
-import com.arjuna.ats.arjuna.tools.osb.mbean.LogRecordWrapper;
-import com.arjuna.ats.arjuna.tools.osb.mbean.UidWrapper;
+import com.arjuna.ats.arjuna.coordinator.BasicAction;
+import com.arjuna.ats.arjuna.coordinator.RecordList;
+import com.arjuna.ats.arjuna.tools.osb.mbean.*;
+import com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.SubordinateAtomicAction;
 
 /**
  * JTA specific version of an ActionBean that knows when a participant record
@@ -23,4 +24,56 @@
         else
             return super.createParticipant(rec, listType);
     }
+/*
+    protected ActionBeanWrapperInterface createWrapper(UidWrapper w) {
+        String cn = SubordinateAtomicAction.class.getCanonicalName();
+        return new GenericAtomicActionWrapper("com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.SubordinateAtomicAction", w);
+    }
+
+
+
+    class SubordinateAtomicActionWrapper extends SubordinateAtomicAction implements ActionBeanWrapperInterface {
+        boolean activated;
+
+        public SubordinateAtomicActionWrapper(UidWrapper w) {
+            super(w.getUid());
+        }
+
+        public boolean activate() {
+            if (!activated)
+                activated = super.activate();
+
+            return activated;
+        }
+
+        public void doUpdateState() {
+            updateState();
+        }
+
+        public Uid getUid(AbstractRecord rec) {
+            return get_uid();
+        }
+
+        public StringBuilder toString(String prefix, StringBuilder sb) {
+            prefix += '\t';
+            return sb.append('\n').append(prefix).append(get_uid());
+        }
+
+        public void clearHeuristicDecision(int newDecision) {
+            if (super.heuristicList.size() == 0)
+                setHeuristicDecision(newDecision);
+        }
+
+        public RecordList getRecords(ParticipantStatus type) {
+            switch (type) {
+                default:
+                case PREPARED: return preparedList;
+                case FAILED: return failedList;
+                case HEURISTIC: return heuristicList;
+                case PENDING: return pendingList;
+                case READONLY: return readonlyList;
+            }
+        }
+
+    }*/
 }

Added: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBean.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBean.java	                        (rev 0)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBean.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -0,0 +1,44 @@
+package com.arjuna.ats.internal.jta.tools.osb.mbean.jta;
+
+import com.arjuna.ats.arjuna.coordinator.BasicAction;
+import com.arjuna.ats.arjuna.logging.tsLogger;
+import com.arjuna.ats.arjuna.tools.osb.mbean.UidWrapper;
+import com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.SubordinateAtomicAction;
+
+public class SubordinateActionBean extends JTAActionBean implements SubordinateActionBeanMBean {
+    public SubordinateActionBean(UidWrapper w) {
+        super(w);
+    }
+
+    public String getXid() {
+        try {
+            SubordinateAtomicAction sub = (SubordinateAtomicAction) ra.getAction();
+
+            return sub.getXid().toString();
+        } catch (ClassCastException e) {
+            if (tsLogger.logger.isDebugEnabled()) {
+                BasicAction ba = ra.getAction();
+
+    		    tsLogger.logger.debug("unable to cast " + ba.toString() + e.getMessage());
+            }
+
+            return e.getMessage();
+        }
+    }
+
+    public String getParentNodeName() {
+        try {
+            SubordinateAtomicAction sub = (SubordinateAtomicAction) ra.getAction();
+
+            return sub.getParentNodeName();
+        } catch (ClassCastException e) {
+            if (tsLogger.logger.isDebugEnabled()) {
+                BasicAction ba = ra.getAction();
+
+    		    tsLogger.logger.debug("unable to cast " + (ba == null ? "null" : ba.toString()) + ": " + e.getMessage());
+            }
+
+            return e.getMessage();
+        }
+    }
+}

Added: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBeanMBean.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBeanMBean.java	                        (rev 0)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jta/SubordinateActionBeanMBean.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -0,0 +1,13 @@
+package com.arjuna.ats.internal.jta.tools.osb.mbean.jta;
+
+import com.arjuna.ats.arjuna.tools.osb.annotation.MXBeanDescription;
+import com.arjuna.ats.arjuna.tools.osb.annotation.MXBeanPropertyDescription;
+import com.arjuna.ats.arjuna.tools.osb.mbean.ActionBeanMBean;
+
+ at MXBeanDescription("Management view of a subordinate transaction")
+public interface SubordinateActionBeanMBean extends ActionBeanMBean {
+    @MXBeanPropertyDescription("A unique id for this transaction")
+	String getXid();
+    @MXBeanPropertyDescription("The (XA) node name assigned by the administrator of the server from which this transaction was propagated")
+	String getParentNodeName();
+}
\ No newline at end of file

Modified: labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jts/ArjunaTransactionImpleWrapper.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jts/ArjunaTransactionImpleWrapper.java	2011-12-15 16:56:59 UTC (rev 37813)
+++ labs/jbosstm/branches/JBOSSTS_4_16/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/tools/osb/mbean/jts/ArjunaTransactionImpleWrapper.java	2011-12-15 21:43:39 UTC (rev 37814)
@@ -2,6 +2,7 @@
 
 import com.arjuna.ats.arjuna.common.Uid;
 import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
+import com.arjuna.ats.arjuna.coordinator.BasicAction;
 import com.arjuna.ats.arjuna.coordinator.RecordList;
 import com.arjuna.ats.arjuna.tools.osb.mbean.*;
 import com.arjuna.ats.internal.jts.orbspecific.coordinator.ArjunaTransactionImple;
@@ -16,6 +17,9 @@
     ActionBean action;
     boolean activated;
 
+    public ArjunaTransactionImpleWrapper () {
+        super(Uid.nullUid());
+    }
     public ArjunaTransactionImpleWrapper (ActionBean action, UidWrapper w) {
         super(w.getUid());
         this.action = action;
@@ -60,6 +64,10 @@
         return sb.append('\n').append(prefix).append(get_uid());
     }
 
+    public BasicAction getAction() {
+        return null;
+    }
+
     public void clearHeuristicDecision(int newDecision) {
         if (super.heuristicList.size() == 0)
             setHeuristicDecision(newDecision);



More information about the jboss-svn-commits mailing list