0001: /*
0002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
0003: * notice. All rights reserved.
0004: */
0005: package com.tc.object.bytecode;
0006:
0007: import com.tc.asm.Type;
0008: import com.tc.aspectwerkz.reflect.ClassInfo;
0009: import com.tc.aspectwerkz.reflect.FieldInfo;
0010: import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo;
0011: import com.tc.cluster.Cluster;
0012: import com.tc.cluster.ClusterEventListener;
0013: import com.tc.lang.StartupHelper;
0014: import com.tc.lang.TCThreadGroup;
0015: import com.tc.lang.ThrowableHandler;
0016: import com.tc.lang.StartupHelper.StartupAction;
0017: import com.tc.logging.TCLogger;
0018: import com.tc.logging.TCLogging;
0019: import com.tc.management.beans.sessions.SessionMonitorMBean;
0020: import com.tc.object.ClientObjectManager;
0021: import com.tc.object.ClientShutdownManager;
0022: import com.tc.object.DistributedObjectClient;
0023: import com.tc.object.LiteralValues;
0024: import com.tc.object.ObjectID;
0025: import com.tc.object.Portability;
0026: import com.tc.object.SerializationUtil;
0027: import com.tc.object.TCObject;
0028: import com.tc.object.bytecode.hook.impl.PreparedComponentsFromL2Connection;
0029: import com.tc.object.config.DSOClientConfigHelper;
0030: import com.tc.object.event.DmiManager;
0031: import com.tc.object.loaders.ClassProvider;
0032: import com.tc.object.lockmanager.api.LockLevel;
0033: import com.tc.object.logging.NullRuntimeLogger;
0034: import com.tc.object.logging.RuntimeLogger;
0035: import com.tc.object.tx.ClientTransactionManager;
0036: import com.tc.object.tx.WaitInvocation;
0037: import com.tc.object.tx.optimistic.OptimisticTransactionManager;
0038: import com.tc.object.tx.optimistic.OptimisticTransactionManagerImpl;
0039: import com.tc.properties.TCProperties;
0040: import com.tc.properties.TCPropertiesImpl;
0041: import com.tc.util.Assert;
0042: import com.tc.util.Util;
0043: import com.tc.util.concurrent.SetOnceFlag;
0044: import com.tc.util.runtime.Vm;
0045:
0046: import java.lang.reflect.Field;
0047: import java.util.Collection;
0048: import java.util.HashMap;
0049: import java.util.Iterator;
0050: import java.util.Map;
0051:
0052: public class ManagerImpl implements Manager {
0053: private static final TCLogger logger = TCLogging
0054: .getLogger(Manager.class);
0055:
0056: private static final LiteralValues literals = new LiteralValues();
0057:
0058: private final SetOnceFlag clientStarted = new SetOnceFlag();
0059: private final DSOClientConfigHelper config;
0060: private final ClassProvider classProvider;
0061: private final boolean startClient;
0062: private final PreparedComponentsFromL2Connection connectionComponents;
0063: private final Thread shutdownAction;
0064: private final Portability portability;
0065: private final Cluster cluster;
0066:
0067: private RuntimeLogger runtimeLogger = new NullRuntimeLogger();
0068: private ClientObjectManager objectManager;
0069: private ClientShutdownManager shutdownManager;
0070: private ClientTransactionManager txManager;
0071: private DistributedObjectClient dso;
0072: private DmiManager methodCallManager;
0073: private OptimisticTransactionManager optimisticTransactionManager;
0074: private SerializationUtil serializer = new SerializationUtil();
0075: private MethodDisplayNames methodDisplay = new MethodDisplayNames(
0076: serializer);
0077:
0078: public ManagerImpl(DSOClientConfigHelper config,
0079: ClassProvider classProvider,
0080: PreparedComponentsFromL2Connection connectionComponents) {
0081: this (true, null, null, config, classProvider,
0082: connectionComponents, true);
0083: }
0084:
0085: // For tests
0086: public ManagerImpl(boolean startClient,
0087: ClientObjectManager objectManager,
0088: ClientTransactionManager txManager,
0089: DSOClientConfigHelper config, ClassProvider classProvider,
0090: PreparedComponentsFromL2Connection connectionComponents) {
0091: this (startClient, objectManager, txManager, config,
0092: classProvider, connectionComponents, true);
0093: }
0094:
0095: // For tests
0096: public ManagerImpl(boolean startClient,
0097: ClientObjectManager objectManager,
0098: ClientTransactionManager txManager,
0099: DSOClientConfigHelper config, ClassProvider classProvider,
0100: PreparedComponentsFromL2Connection connectionComponents,
0101: boolean shutdownActionRequired) {
0102: this .objectManager = objectManager;
0103: this .portability = config.getPortability();
0104: this .txManager = txManager;
0105: this .config = config;
0106: this .startClient = startClient;
0107: this .classProvider = classProvider;
0108: this .connectionComponents = connectionComponents;
0109: this .cluster = new Cluster();
0110: if (shutdownActionRequired) {
0111: shutdownAction = new Thread(new ShutdownAction());
0112: // Register a shutdown hook for the DSO client
0113: Runtime.getRuntime().addShutdownHook(shutdownAction);
0114: } else {
0115: shutdownAction = null;
0116: }
0117:
0118: }
0119:
0120: public SessionMonitorMBean getSessionMonitorMBean() {
0121: return dso.getSessionMonitorMBean();
0122: }
0123:
0124: public void init() {
0125: resolveClasses(); // call this before starting any threads (SEDA, DistributedMethod call stuff, etc)
0126:
0127: if (startClient) {
0128: if (clientStarted.attemptSet()) {
0129: startClient();
0130: }
0131: }
0132: }
0133:
0134: public String getClientID() {
0135: return String.valueOf(this .dso.getChannel()
0136: .getChannelIDProvider().getChannelID().toLong());
0137: }
0138:
0139: private void resolveClasses() {
0140: // See LKC-2323 -- A number of Manager methods can be entered from the internals of URLClassLoader (specifically
0141: // sun.misc.URLClassPath.getLoader()) and can cause deadlocks. Making sure these methods are invoked once, thus
0142: // resolving any class loads, should eliminate the problem.
0143: //
0144: // NOTE: it is entirely possible more signatures might need to added here
0145:
0146: Object o = new Manageable() {
0147: public void __tc_managed(TCObject t) {
0148: throw new AssertionError();
0149: }
0150:
0151: public TCObject __tc_managed() {
0152: return null;
0153: }
0154:
0155: public boolean __tc_isManaged() {
0156: return false;
0157: }
0158: };
0159: lookupExistingOrNull(o);
0160: monitorEnter(o, LOCK_TYPE_WRITE);
0161: monitorExit(o);
0162: logicalInvoke(new HashMap(), SerializationUtil.CLEAR_SIGNATURE,
0163: new Object[] {});
0164: }
0165:
0166: private void startClient() {
0167: final TCThreadGroup group = new TCThreadGroup(
0168: new ThrowableHandler(TCLogging
0169: .getLogger(DistributedObjectClient.class)));
0170:
0171: StartupAction action = new StartupHelper.StartupAction() {
0172: public void execute() throws Throwable {
0173: dso = new DistributedObjectClient(config, group,
0174: classProvider, connectionComponents,
0175: ManagerImpl.this , cluster);
0176: dso.start();
0177: objectManager = dso.getObjectManager();
0178: txManager = dso.getTransactionManager();
0179: runtimeLogger = dso.getRuntimeLogger();
0180:
0181: optimisticTransactionManager = new OptimisticTransactionManagerImpl(
0182: objectManager, txManager);
0183:
0184: methodCallManager = dso.getDmiManager();
0185:
0186: shutdownManager = new ClientShutdownManager(
0187: objectManager, dso
0188: .getRemoteTransactionManager(), dso
0189: .getStageManager(), dso
0190: .getCommunicationsManager(), dso
0191: .getChannel(), dso
0192: .getClientHandshakeManager(),
0193: connectionComponents);
0194: }
0195: };
0196:
0197: StartupHelper startupHelper = new StartupHelper(group, action);
0198: startupHelper.startUp();
0199: }
0200:
0201: public void stop() {
0202: shutdown(false);
0203: }
0204:
0205: private void shutdown(boolean fromShutdownHook) {
0206: if (shutdownManager != null) {
0207: try {
0208: // XXX: This "fromShutdownHook" flag should be removed. It's only here temporarily to make shutdown behave
0209: // before I started futzing with it
0210: shutdownManager.execute(fromShutdownHook);
0211: } finally {
0212: // If we're not being called as a result of the shutdown hook, de-register the hook
0213: if (Thread.currentThread() != shutdownAction) {
0214: try {
0215: Runtime.getRuntime().removeShutdownHook(
0216: shutdownAction);
0217: } catch (Exception e) {
0218: // ignore
0219: }
0220: }
0221: }
0222: }
0223: }
0224:
0225: public void logicalInvoke(Object object, String methodSignature,
0226: Object[] params) {
0227: Manageable m = (Manageable) object;
0228: if (m.__tc_managed() != null) {
0229: TCObject tco = lookupExistingOrNull(object);
0230:
0231: try {
0232: if (tco != null) {
0233:
0234: if (SerializationUtil.ADD_ALL_SIGNATURE
0235: .equals(methodSignature)) {
0236: logicalAddAllInvoke(serializer
0237: .methodToID(methodSignature),
0238: methodSignature,
0239: (Collection) params[0], tco);
0240: } else if (SerializationUtil.ADD_ALL_AT_SIGNATURE
0241: .equals(methodSignature)) {
0242: logicalAddAllAtInvoke(serializer
0243: .methodToID(methodSignature),
0244: methodSignature, ((Integer) params[0])
0245: .intValue(),
0246: (Collection) params[1], tco);
0247: } else {
0248: adjustForJava1ParametersIfNecessary(
0249: methodSignature, params);
0250: tco
0251: .logicalInvoke(
0252: serializer
0253: .methodToID(methodSignature),
0254: methodDisplay
0255: .getDisplayForSignature(methodSignature),
0256: params);
0257: }
0258: }
0259: } catch (Throwable t) {
0260: Util.printLogAndRethrowError(t, logger);
0261: }
0262: }
0263: }
0264:
0265: public void logicalInvokeWithTransaction(Object object,
0266: Object lockObject, String methodName, Object[] params) {
0267: monitorEnter(lockObject, LockLevel.WRITE);
0268: try {
0269: logicalInvoke(object, methodName, params);
0270: } finally {
0271: monitorExit(lockObject);
0272: }
0273: }
0274:
0275: private void adjustForJava1ParametersIfNecessary(String methodName,
0276: Object[] params) {
0277: if ((params.length == 2) && (params[1] != null)
0278: && (params[1].getClass().equals(Integer.class))) {
0279: if (SerializationUtil.SET_ELEMENT_SIGNATURE
0280: .equals(methodName)
0281: || SerializationUtil.INSERT_ELEMENT_AT_SIGNATURE
0282: .equals(methodName)) {
0283: // special case for reversing parameters
0284: Object tmp = params[0];
0285: params[0] = params[1];
0286: params[1] = tmp;
0287: }
0288: }
0289: }
0290:
0291: private void logicalAddAllInvoke(int method,
0292: String methodSignature, Collection collection,
0293: TCObject tcobj) {
0294: for (Iterator i = collection.iterator(); i.hasNext();) {
0295: tcobj.logicalInvoke(method, methodDisplay
0296: .getDisplayForSignature(methodSignature),
0297: new Object[] { i.next() });
0298: }
0299: }
0300:
0301: private void logicalAddAllAtInvoke(int method,
0302: String methodSignature, int index, Collection collection,
0303: TCObject tcobj) {
0304:
0305: for (Iterator i = collection.iterator(); i.hasNext();) {
0306: tcobj.logicalInvoke(method, methodDisplay
0307: .getDisplayForSignature(methodSignature),
0308: new Object[] { new Integer(index++), i.next() });
0309: }
0310: }
0311:
0312: public Object lookupOrCreateRoot(String name, Object object) {
0313: return lookupOrCreateRoot(name, object, false);
0314: }
0315:
0316: public Object lookupOrCreateRootNoDepth(String name, Object obj) {
0317: return lookupOrCreateRoot(name, obj, true);
0318: }
0319:
0320: public Object createOrReplaceRoot(String name, Object object) {
0321: try {
0322: return this .objectManager.createOrReplaceRoot(name, object);
0323: } catch (Throwable t) {
0324: Util.printLogAndRethrowError(t, logger);
0325:
0326: // shouldn't get here
0327: throw new AssertionError();
0328: }
0329: }
0330:
0331: private Object lookupOrCreateRoot(String rootName, Object object,
0332: boolean noDepth) {
0333: try {
0334: if (noDepth) {
0335: return this .objectManager.lookupOrCreateRootNoDepth(
0336: rootName, object);
0337: }
0338: return this .objectManager.lookupOrCreateRoot(rootName,
0339: object, true);
0340: } catch (Throwable t) {
0341: Util.printLogAndRethrowError(t, logger);
0342:
0343: // shouldn't get here
0344: throw new AssertionError();
0345: }
0346: }
0347:
0348: public void beginLock(String lockID, int type) {
0349: try {
0350: begin(lockID, type, null, null);
0351: } catch (Throwable t) {
0352: Util.printLogAndRethrowError(t, logger);
0353: }
0354: }
0355:
0356: public void beginVolatile(TCObject tcObject, String fieldName,
0357: int type) {
0358: if (tcObject == null) {
0359: throw new NullPointerException(
0360: "beginVolatile called on a null TCObject");
0361: }
0362:
0363: begin(generateVolatileLockName(tcObject, fieldName), type,
0364: null, null);
0365: }
0366:
0367: private void begin(String lockID, int type, Object instance,
0368: TCObject tcobj) {
0369: boolean locked = this .txManager.begin(lockID, type);
0370: if (locked && runtimeLogger.lockDebug()) {
0371: runtimeLogger.lockAcquired(lockID, type, instance, tcobj);
0372: }
0373: }
0374:
0375: private boolean tryBegin(String lockID, int type, Object instance,
0376: WaitInvocation timeout, TCObject tcobj) {
0377: boolean locked = this .txManager.tryBegin(lockID, timeout, type);
0378: if (locked && runtimeLogger.lockDebug()) {
0379: runtimeLogger.lockAcquired(lockID, type, instance, tcobj);
0380: }
0381: return locked;
0382: }
0383:
0384: private boolean tryBegin(String lockID, int type, Object instance,
0385: TCObject tcobj) {
0386: return tryBegin(lockID, type, instance, new WaitInvocation(0),
0387: tcobj);
0388: }
0389:
0390: public void commitVolatile(TCObject tcObject, String fieldName) {
0391: if (tcObject == null) {
0392: throw new NullPointerException(
0393: "commitVolatile called on a null TCObject");
0394: }
0395:
0396: commitLock(generateVolatileLockName(tcObject, fieldName));
0397: }
0398:
0399: public void commitLock(String lockName) {
0400:
0401: try {
0402: this .txManager.commit(lockName);
0403: } catch (Throwable t) {
0404: Util.printLogAndRethrowError(t, logger);
0405: }
0406: }
0407:
0408: public void objectNotify(Object obj) {
0409: if (obj == null) {
0410: throw new NullPointerException(
0411: "notify() called on a null reference");
0412: }
0413:
0414: TCObject tco = lookupExistingOrNull(obj);
0415:
0416: if (tco != null) {
0417: managedObjectNotify(obj, tco, false);
0418: } else {
0419: obj.notify();
0420: }
0421: }
0422:
0423: public void objectNotifyAll(Object obj) {
0424: if (obj == null) {
0425: throw new NullPointerException(
0426: "notifyAll() called on a null reference");
0427: }
0428:
0429: TCObject tco = lookupExistingOrNull(obj);
0430:
0431: if (tco != null) {
0432: managedObjectNotify(obj, tco, true);
0433: } else {
0434: obj.notifyAll();
0435: }
0436: }
0437:
0438: private void managedObjectNotify(Object obj, TCObject tco,
0439: boolean all) {
0440: try {
0441: if (runtimeLogger.waitNotifyDebug()) {
0442: runtimeLogger.objectNotify(all, obj, tco);
0443: }
0444: this .txManager.notify(generateAutolockName(tco), all, obj);
0445: } catch (Throwable t) {
0446: Util.printLogAndRethrowError(t, logger);
0447: }
0448: }
0449:
0450: public void objectWait0(Object obj) throws InterruptedException {
0451: TCObject tco = lookupExistingOrNull(obj);
0452:
0453: if (tco != null) {
0454: try {
0455: WaitInvocation call = new WaitInvocation();
0456: if (runtimeLogger.waitNotifyDebug()) {
0457: runtimeLogger.objectWait(call, obj, tco);
0458: }
0459: this .txManager.wait(generateAutolockName(tco), call,
0460: obj);
0461: } catch (InterruptedException ie) {
0462: throw ie;
0463: } catch (Throwable t) {
0464: Util.printLogAndRethrowError(t, logger);
0465: }
0466: } else {
0467: obj.wait();
0468: }
0469: }
0470:
0471: public void objectWait1(Object obj, long millis)
0472: throws InterruptedException {
0473: TCObject tco = lookupExistingOrNull(obj);
0474: if (tco != null) {
0475: try {
0476: WaitInvocation call = new WaitInvocation(millis);
0477: if (runtimeLogger.waitNotifyDebug()) {
0478: runtimeLogger.objectWait(call, obj, tco);
0479: }
0480: this .txManager.wait(generateAutolockName(tco), call,
0481: obj);
0482: } catch (InterruptedException ie) {
0483: throw ie;
0484: } catch (Throwable t) {
0485: Util.printLogAndRethrowError(t, logger);
0486: }
0487: } else {
0488: obj.wait(millis);
0489: }
0490: }
0491:
0492: public void objectWait2(Object obj, long millis, int nanos)
0493: throws InterruptedException {
0494: TCObject tco = lookupExistingOrNull(obj);
0495:
0496: if (tco != null) {
0497: try {
0498: WaitInvocation call = new WaitInvocation(millis, nanos);
0499: if (runtimeLogger.waitNotifyDebug()) {
0500: runtimeLogger.objectWait(call, obj, tco);
0501: }
0502: this .txManager.wait(generateAutolockName(tco), call,
0503: obj);
0504: } catch (InterruptedException ie) {
0505: throw ie;
0506: } catch (Throwable t) {
0507: Util.printLogAndRethrowError(t, logger);
0508: }
0509: } else {
0510: obj.wait(millis, nanos);
0511: }
0512: }
0513:
0514: private boolean isLiteralAutolock(Object o) {
0515: if (o instanceof Manageable) {
0516: return false;
0517: }
0518: return (!(o instanceof Class)) && literals.isLiteralInstance(o);
0519: }
0520:
0521: public boolean isDsoMonitorEntered(Object o) {
0522: String lockName = getLockName(o);
0523: if (lockName == null) {
0524: return false;
0525: }
0526: boolean dsoMonitorEntered = txManager
0527: .isLockOnTopStack(lockName);
0528:
0529: if (!dsoMonitorEntered && isManaged(o)) {
0530: logger
0531: .info("Object "
0532: + o
0533: + " is a shared object, but a shared lock is not obtained within a locking context. This usually means the object get shared within a synchronized block/method.");
0534: }
0535:
0536: return dsoMonitorEntered;
0537: }
0538:
0539: private String getLockName(Object obj) {
0540: TCObject tco = lookupExistingOrNull(obj);
0541: if (tco != null) {
0542: return generateAutolockName(tco);
0543: } else if (isLiteralAutolock(obj)) {
0544: return generateLiteralLockName(obj);
0545: }
0546: return null;
0547: }
0548:
0549: public void monitorEnter(Object obj, int type) {
0550: if (obj == null) {
0551: throw new NullPointerException(
0552: "monitorEnter called on a null object");
0553: }
0554:
0555: TCObject tco = lookupExistingOrNull(obj);
0556:
0557: try {
0558: if (tco != null) {
0559: if (tco.autoLockingDisabled()) {
0560: return;
0561: }
0562:
0563: begin(generateAutolockName(tco), type, obj, tco);
0564: } else if (isLiteralAutolock(obj)) {
0565: begin(generateLiteralLockName(obj), type, obj, null);
0566: }
0567: } catch (Throwable t) {
0568: Util.printLogAndRethrowError(t, logger);
0569: }
0570: }
0571:
0572: public void monitorExit(Object obj) {
0573: if (obj == null) {
0574: throw new NullPointerException(
0575: "monitorExit called on a null object");
0576: }
0577:
0578: TCObject tco = lookupExistingOrNull(obj);
0579:
0580: try {
0581: if (tco != null) {
0582: if (tco.autoLockingDisabled()) {
0583: return;
0584: }
0585:
0586: // don't call this.commit() here, the error handling would happen twice in that case
0587: this .txManager.commit(generateAutolockName(tco));
0588: } else if (isLiteralAutolock(obj)) {
0589: this .txManager.commit(generateLiteralLockName(obj));
0590: }
0591: } catch (Throwable t) {
0592: Util.printLogAndRethrowError(t, logger);
0593: }
0594: }
0595:
0596: public boolean isLocked(Object obj, int lockLevel) {
0597: if (obj == null) {
0598: throw new NullPointerException(
0599: "isLocked called on a null object");
0600: }
0601:
0602: TCObject tco = lookupExistingOrNull(obj);
0603:
0604: if (tco != null) {
0605: return this .txManager.isLocked(generateAutolockName(tco),
0606: lockLevel);
0607: } else {
0608: return this .txManager.isLocked(
0609: generateLiteralLockName(obj), lockLevel);
0610: }
0611: }
0612:
0613: public boolean tryMonitorEnter(Object obj, long timeoutInNanos,
0614: int type) {
0615: if (obj == null) {
0616: throw new NullPointerException(
0617: "monitorEnter called on a null object");
0618: }
0619:
0620: TCObject tco = lookupExistingOrNull(obj);
0621:
0622: try {
0623: WaitInvocation timeout = null;
0624: if (timeoutInNanos <= 0) {
0625: timeout = new WaitInvocation(0);
0626: } else {
0627: long mills = Util.getMillis(timeoutInNanos);
0628: int nanos = Util.getNanos(timeoutInNanos, mills);
0629: timeout = new WaitInvocation(mills, nanos);
0630: }
0631:
0632: if (tco != null) {
0633: if (tco.autoLockingDisabled()) {
0634: return false;
0635: }
0636:
0637: return tryBegin(generateAutolockName(tco), type, obj,
0638: timeout, tco);
0639: } else if (isLiteralAutolock(obj)) {
0640: return tryBegin(generateLiteralLockName(obj), type,
0641: obj, timeout, null);
0642: }
0643: } catch (Throwable t) {
0644: Util.printLogAndRethrowError(t, logger);
0645: }
0646: return false;
0647: }
0648:
0649: public boolean tryBeginLock(String lockID, int type) {
0650: return tryBegin(lockID, type, null, null);
0651: }
0652:
0653: public int localHeldCount(Object obj, int lockLevel) {
0654: if (obj == null) {
0655: throw new NullPointerException(
0656: "isHeldByCurrentThread called on a null object");
0657: }
0658:
0659: TCObject tco = lookupExistingOrNull(obj);
0660:
0661: if (tco != null) {
0662: return this .txManager.localHeldCount(
0663: generateAutolockName(tco), lockLevel);
0664: } else {
0665: return this .txManager.localHeldCount(
0666: generateLiteralLockName(obj), lockLevel);
0667: }
0668:
0669: }
0670:
0671: public boolean isHeldByCurrentThread(Object obj, int lockLevel) {
0672: if (obj == null) {
0673: throw new NullPointerException(
0674: "isHeldByCurrentThread called on a null object");
0675: }
0676:
0677: TCObject tco = lookupExistingOrNull(obj);
0678:
0679: if (tco != null) {
0680: return this .txManager.isHeldByCurrentThread(
0681: generateAutolockName(tco), lockLevel);
0682: } else {
0683: return this .txManager.isHeldByCurrentThread(
0684: generateLiteralLockName(obj), lockLevel);
0685: }
0686:
0687: }
0688:
0689: public int queueLength(Object obj) {
0690: if (obj == null) {
0691: throw new NullPointerException(
0692: "queueLength called on a null object");
0693: }
0694:
0695: TCObject tco = lookupExistingOrNull(obj);
0696:
0697: if (tco != null) {
0698: return this .txManager
0699: .queueLength(generateAutolockName(tco));
0700: } else {
0701: return this .txManager
0702: .queueLength(generateLiteralLockName(obj));
0703: }
0704: }
0705:
0706: public int waitLength(Object obj) {
0707: if (obj == null) {
0708: throw new NullPointerException(
0709: "waitLength called on a null object");
0710: }
0711:
0712: TCObject tco = lookupExistingOrNull(obj);
0713:
0714: if (tco != null) {
0715: return this .txManager.waitLength(generateAutolockName(tco));
0716: } else {
0717: return this .txManager
0718: .waitLength(generateLiteralLockName(obj));
0719: }
0720: }
0721:
0722: public boolean isCreationInProgress() {
0723: // I think the condition this.txManager.isTransactionLoggingDisabled() is not necessary and is causing the
0724: // problem in DEV-602.
0725: // return this.objectManager.isCreationInProgress() || this.txManager.isTransactionLoggingDisabled();
0726: return this .objectManager.isCreationInProgress();
0727: }
0728:
0729: public TCObject shareObjectIfNecessary(Object pojo) {
0730: TCObject tobj = lookupExistingOrNull(pojo);
0731: if (tobj != null) {
0732: return tobj;
0733: }
0734:
0735: try {
0736: return this .objectManager.lookupOrShare(pojo);
0737: } catch (Throwable t) {
0738: Util.printLogAndRethrowError(t, logger);
0739:
0740: // shouldn't get here
0741: throw new AssertionError();
0742: }
0743: }
0744:
0745: public TCObject lookupOrCreate(Object obj) {
0746: if (obj instanceof Manageable) {
0747: return ((Manageable) obj).__tc_managed();
0748: }
0749: return this .objectManager.lookupOrCreate(obj);
0750: }
0751:
0752: public TCObject lookupExistingOrNull(Object pojo) {
0753: if (pojo instanceof Manageable) {
0754: return ((Manageable) pojo).__tc_managed();
0755: }
0756:
0757: try {
0758: return this .objectManager.lookupExistingOrNull(pojo);
0759: } catch (Throwable t) {
0760: Util.printLogAndRethrowError(t, logger);
0761:
0762: // shouldn't get here
0763: throw new AssertionError();
0764: }
0765: }
0766:
0767: public Object lookupObject(ObjectID id)
0768: throws ClassNotFoundException {
0769: return this .objectManager.lookupObject(id);
0770: }
0771:
0772: public Object lookupObject(ObjectID id, ObjectID parentContext)
0773: throws ClassNotFoundException {
0774: return this .objectManager.lookupObject(id, parentContext);
0775: }
0776:
0777: public boolean distributedMethodCall(Object receiver,
0778: String method, Object[] params, boolean runOnAllNodes) {
0779: TCObject tco = lookupExistingOrNull(receiver);
0780:
0781: try {
0782: if (tco != null) {
0783: return methodCallManager.distributedInvoke(receiver,
0784: method, params, runOnAllNodes);
0785: } else {
0786: return false;
0787: }
0788: } catch (Throwable t) {
0789: Util.printLogAndRethrowError(t, logger);
0790: return false;
0791: }
0792: }
0793:
0794: public void distributedMethodCallCommit() {
0795: methodCallManager.distributedInvokeCommit();
0796: }
0797:
0798: public void checkWriteAccess(Object context) {
0799: // XXX: make sure that "context" is the ALWAYS the right object to check here, and then rename it
0800: if (isManaged(context)) {
0801: try {
0802: txManager.checkWriteAccess(context);
0803: } catch (Throwable t) {
0804: Util.printLogAndRethrowError(t, logger);
0805: }
0806: }
0807: }
0808:
0809: public boolean isManaged(Object obj) {
0810: if (obj instanceof Manageable) {
0811: TCObject tcobj = ((Manageable) obj).__tc_managed();
0812:
0813: return tcobj != null && tcobj.isShared();
0814: }
0815: return this .objectManager.isManaged(obj);
0816: }
0817:
0818: public boolean isDsoMonitored(Object obj) {
0819: if (this .objectManager.isCreationInProgress()
0820: || this .txManager.isTransactionLoggingDisabled()) {
0821: return false;
0822: }
0823:
0824: TCObject tcobj = lookupExistingOrNull(obj);
0825: if (tcobj != null) {
0826: return tcobj.isShared();
0827: } else {
0828: return isLiteralAutolock(obj);
0829: }
0830: }
0831:
0832: public Object lookupRoot(String name) {
0833: try {
0834: return this .objectManager.lookupRoot(name);
0835: } catch (Throwable t) {
0836: Util.printLogAndRethrowError(t, logger);
0837:
0838: // shouldn't get here
0839: throw new AssertionError();
0840: }
0841: }
0842:
0843: private static String generateVolatileLockName(TCObject tcobj,
0844: String fieldName) {
0845: Assert.assertNotNull(tcobj);
0846: return ByteCodeUtil.generateVolatileLockName(tcobj
0847: .getObjectID(), fieldName);
0848: }
0849:
0850: private static String generateAutolockName(TCObject tcobj) {
0851: Assert.assertNotNull(tcobj);
0852: return ByteCodeUtil.generateAutolockName(tcobj.getObjectID());
0853: }
0854:
0855: private static String generateLiteralLockName(Object obj) {
0856: Assert.assertNotNull(obj);
0857: return ByteCodeUtil.generateLiteralLockName(literals
0858: .valueFor(obj), obj);
0859: }
0860:
0861: public boolean isLogical(Object object) {
0862: return this .config.isLogical(object.getClass().getName());
0863: }
0864:
0865: public boolean isRoot(Field field) {
0866: String fName = field.getName();
0867: Class c = field.getDeclaringClass();
0868:
0869: if (Vm.isIBM() && c.getName().startsWith("java.lang.reflect.")) {
0870: // This avoids a StackOverFlow on ibm jdk -- it does mean that roots defined in classes in java.lang.reflect.*
0871: // won't work right, but there are other chicken/egg reasons why roots there won't work there too
0872: return false;
0873: }
0874:
0875: ClassInfo classInfo = JavaClassInfo.getClassInfo(c);
0876:
0877: FieldInfo[] fields = classInfo.getFields();
0878: for (int i = 0; i < fields.length; i++) {
0879: FieldInfo fieldInfo = fields[i];
0880: if (fieldInfo.getName().equals(fName)) {
0881: return this .config.isRoot(fieldInfo);
0882: }
0883: }
0884:
0885: return false;
0886: }
0887:
0888: public Object deepCopy(Object source) {
0889: Object ret = null;
0890: try {
0891: ret = this .objectManager.deepCopy(source,
0892: optimisticTransactionManager);
0893: } catch (Throwable t) {
0894: Util.printLogAndRethrowError(t, logger);
0895: }
0896: return ret;
0897: }
0898:
0899: public TCProperties getTCProperites() {
0900: return TCPropertiesImpl.getProperties();
0901: }
0902:
0903: private class ShutdownAction implements Runnable {
0904: public void run() {
0905: // XXX: we should just call stop(), but for the 1.5 (chex) release, I'm reverting the behavior
0906: // stop();
0907:
0908: shutdown(true);
0909: }
0910: }
0911:
0912: public void optimisticBegin() {
0913: this .optimisticTransactionManager.begin();
0914: }
0915:
0916: public void optimisticCommit() throws ClassNotFoundException {
0917: this .optimisticTransactionManager.commit();
0918: }
0919:
0920: public void optimisticRollback() {
0921: this .optimisticTransactionManager.rollback();
0922: }
0923:
0924: public boolean isPhysicallyInstrumented(Class clazz) {
0925: return this .portability.isClassPhysicallyInstrumented(clazz);
0926: }
0927:
0928: public TCLogger getLogger(String loggerName) {
0929: return TCLogging.getLogger(loggerName);
0930: }
0931:
0932: private static class MethodDisplayNames {
0933:
0934: private final Map display = new HashMap();
0935:
0936: public MethodDisplayNames(SerializationUtil serializer) {
0937: String[] sigs = serializer.getSignatures();
0938: for (int i = 0; i < sigs.length; i++) {
0939: display.put(sigs[i], getDisplayStringFor(sigs[i]));
0940: }
0941: }
0942:
0943: private String getDisplayStringFor(String signature) {
0944: String methodName = signature.substring(0, signature
0945: .indexOf('('));
0946: StringBuffer rv = new StringBuffer(methodName);
0947: rv.append('(');
0948:
0949: Type[] args = Type.getArgumentTypes(signature
0950: .substring(signature.indexOf('(')));
0951: for (int i = 0; i < args.length; i++) {
0952: if (i > 0) {
0953: rv.append(',');
0954: }
0955: Type t = args[i];
0956: int sort = t.getSort();
0957: switch (sort) {
0958: case Type.ARRAY:
0959: Type elemType = t.getElementType();
0960: if (elemType.getSort() == Type.OBJECT) {
0961: rv.append(getShortName(elemType));
0962: } else {
0963: rv.append(elemType.getClassName());
0964: }
0965: for (int d = t.getDimensions(); d > 0; --d) {
0966: rv.append("[]");
0967: }
0968: break;
0969: case Type.OBJECT:
0970: rv.append(getShortName(t));
0971: break;
0972: case Type.BOOLEAN:
0973: case Type.BYTE:
0974: case Type.CHAR:
0975: case Type.DOUBLE:
0976: case Type.FLOAT:
0977: case Type.INT:
0978: case Type.LONG:
0979: case Type.SHORT:
0980: rv.append(t.getClassName());
0981: break;
0982: default:
0983: throw new AssertionError("unknown sort: " + sort);
0984: }
0985: }
0986:
0987: rv.append(')');
0988: return rv.toString();
0989: }
0990:
0991: private String getShortName(Type t) {
0992: String fqName = t.getClassName();
0993: int lastDot = fqName.lastIndexOf('.');
0994: if (lastDot > -1) {
0995: return fqName.substring(lastDot + 1);
0996: }
0997: return fqName;
0998: }
0999:
1000: String getDisplayForSignature(String methodSignature) {
1001: String rv = (String) display.get(methodSignature);
1002: if (rv == null) {
1003: throw new AssertionError(
1004: "missing display string for signature: "
1005: + methodSignature);
1006: }
1007: return rv;
1008: }
1009: }
1010:
1011: public void addClusterEventListener(ClusterEventListener cel) {
1012: cluster.addClusterEventListener(cel);
1013: }
1014:
1015: public DmiManager getDmiManager() {
1016: return this .methodCallManager;
1017: }
1018:
1019: public boolean isFieldPortableByOffset(Object pojo, long fieldOffset) {
1020: TCObject tcObj = lookupExistingOrNull(pojo);
1021: return tcObj != null
1022: && tcObj.isFieldPortableByOffset(fieldOffset);
1023: }
1024:
1025: }
|