001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object;
006:
007: import com.tc.async.api.StageManager;
008: import com.tc.config.schema.dynamic.ConfigItem;
009: import com.tc.logging.TCLogger;
010: import com.tc.logging.TCLogging;
011: import com.tc.net.core.ConnectionInfo;
012: import com.tc.net.protocol.tcm.CommunicationsManager;
013: import com.tc.object.bytecode.hook.impl.PreparedComponentsFromL2Connection;
014: import com.tc.object.handshakemanager.ClientHandshakeManager;
015: import com.tc.object.net.DSOClientMessageChannel;
016: import com.tc.object.tx.RemoteTransactionManager;
017:
018: public class ClientShutdownManager {
019: private static final TCLogger logger = TCLogging
020: .getLogger(ClientShutdownManager.class);
021: private final RemoteTransactionManager rtxManager;
022: private final StageManager stageManager;
023: private final ClientObjectManager objectManager;
024: private final DSOClientMessageChannel channel;
025: private final CommunicationsManager commsManager;
026: private final ClientHandshakeManager handshakeManager;
027: private final PreparedComponentsFromL2Connection connectionComponents;
028:
029: public ClientShutdownManager(ClientObjectManager objectManager,
030: RemoteTransactionManager rtxManager,
031: StageManager stageManager,
032: CommunicationsManager commsManager,
033: DSOClientMessageChannel channel,
034: ClientHandshakeManager handshakeManager,
035: PreparedComponentsFromL2Connection connectionComponents) {
036: this .objectManager = objectManager;
037: this .rtxManager = rtxManager;
038: this .stageManager = stageManager;
039: this .commsManager = commsManager;
040: this .channel = channel;
041: this .handshakeManager = handshakeManager;
042: this .connectionComponents = connectionComponents;
043: }
044:
045: public void execute(boolean fromShutdownHook) {
046: closeLocalWork();
047:
048: if (!fromShutdownHook) {
049: shutdown();
050: }
051: }
052:
053: private void closeLocalWork() {
054:
055: boolean immediate = isImmediate();
056: if (!immediate) {
057: if (rtxManager != null) {
058: try {
059: rtxManager.stop();
060: } catch (Throwable t) {
061: logger
062: .error(
063: "Error shutting down remote transaction manager",
064: t);
065: }
066: }
067: } else {
068: logger
069: .warn("DSO Client exiting without flushing local work");
070: }
071:
072: }
073:
074: private boolean isImmediate() {
075: // XXX: Race condition here --> we can start the non-immediate shutdown procedure becuase we think the channel is
076: // open, but it can die before we start (or in the middle of) flushing the local work
077: if (channel.isConnected()) {
078: return false;
079: }
080:
081: // If we've connected to a persisent server, we should try to flush
082: if (handshakeManager.serverIsPersistent()) {
083: return false;
084: }
085:
086: // If we think there is more than one server out there, we should try to flush
087: ConfigItem connectionInfoItem = this .connectionComponents
088: .createConnectionInfoConfigItem();
089: ConnectionInfo[] connectionInfo = (ConnectionInfo[]) connectionInfoItem
090: .getObject();
091: return connectionInfo.length == 1;
092: }
093:
094: private void shutdown() {
095:
096: if (stageManager != null) {
097: try {
098: stageManager.stopAll();
099: } catch (Throwable t) {
100: logger.error("Error stopping stage manager", t);
101: }
102: }
103:
104: if (objectManager != null) {
105: try {
106: objectManager.shutdown();
107: } catch (Throwable t) {
108: logger.error(
109: "Error shutting down client object manager", t);
110: }
111: }
112:
113: if (channel != null) {
114: try {
115: channel.close();
116: } catch (Throwable t) {
117: logger.error("Error closing channel", t);
118: }
119: }
120:
121: if (commsManager != null) {
122: try {
123: commsManager.shutdown();
124: } catch (Throwable t) {
125: logger
126: .error(
127: "Error shutting down communications manager",
128: t);
129: }
130: }
131: }
132:
133: }
|