001: /*
002: * JacORB - a free Java ORB
003: *
004: * Copyright (C) 1997-2004 Gerald Brose.
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Library General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Library General Public License for more details.
015: *
016: * You should have received a copy of the GNU Library General Public
017: * License along with this library; if not, write to the Free
018: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
019: */
020:
021: package org.jacorb.orb.giop;
022:
023: import org.apache.avalon.framework.configuration.Configuration;
024: import org.apache.avalon.framework.configuration.ConfigurationException;
025: import org.jacorb.orb.iiop.IIOPConnection;
026:
027: /**
028: * @author Nicolas Noffke
029: * @version $Id: ServerGIOPConnection.java,v 1.24 2007/02/06 18:47:40 andre.spiegel Exp $
030: */
031:
032: public class ServerGIOPConnection extends GIOPConnection {
033: private static final byte[] CLOSE_CONNECTION_MESSAGE = new byte[] {
034: // Byte casts are for JDK1.2 compatibility.
035: (byte) 'G', (byte) 'I', (byte) 'O', (byte) 'P', //magic start
036: 1, //GIOP major
037: 0, //GIOP minor
038: 0, //endianess, big-endian
039: 5, //message type, CloseConnection message
040: 0, 0, 0, 0 // message size, 0 because CloseConnection has no body
041: };
042:
043: private final GIOPConnectionManager manager;
044: private boolean closeOnReadTimeout = false;
045: private boolean delayClose = false;
046:
047: public ServerGIOPConnection(org.omg.ETF.Profile profile,
048: org.omg.ETF.Connection transport,
049: RequestListener request_listener,
050: ReplyListener reply_listener,
051: StatisticsProvider statistics_provider,
052: GIOPConnectionManager manager) {
053: super (profile, transport, request_listener, reply_listener,
054: statistics_provider);
055: this .manager = manager;
056: }
057:
058: public void configure(Configuration configuration)
059: throws ConfigurationException {
060: super .configure(configuration);
061:
062: delayClose = configuration.getAttribute(
063: "jacorb.connection.delay_close", "off").equals("on");
064: }
065:
066: /*
067: * Try an orderly shutdown of this connection by sending a
068: * CloseConnection message. The CORBA spec only allows us to
069: * do that if we have no more pending messages for which we
070: * haven't sent a reply yet (CORBA 3.0, 15.5.1.1). If there are
071: * pending messages, this method does nothing and returns false.
072: * If there are no pending messages, it sets the connection into
073: * discarding mode, sends the CloseConnection message, and reports
074: * the connection as closed to any connection_listener that's registered
075: * with this connection. The actual closing of the connection will happen
076: * later, when the transport gets closed by the client, or the final
077: * timeout has passed.
078: */
079: boolean tryClose() {
080: if (tryDiscard()) {
081: if (logger.isDebugEnabled()) {
082: logger.debug(this .toString()
083: + ": tryClose() -- will send close connection");
084: }
085:
086: sendCloseConnection();
087:
088: closeOnReadTimeout = true;
089:
090: if (connection_listener != null) {
091: connection_listener.connectionClosed();
092: }
093:
094: return true;
095: }
096: if (logger.isDebugEnabled()) {
097: logger.debug(this .toString()
098: + ": tryClose() -- cannot close connection");
099: }
100: return false;
101: }
102:
103: /**
104: * Atomically try to set this connection into discarding mode, if
105: * it doesn't have any pending messages.
106: *
107: * @return true, if the connection has been idle and discarding
108: * has been set
109: */
110: private boolean tryDiscard() {
111: if (!hasPendingMessages()) {
112: synchronized (pendingUndecidedSync) {
113: discard_messages = true;
114: }
115:
116: return true;
117: }
118: return false;
119: }
120:
121: /**
122: * <code>sendCloseConnection</code> sends a close connection message
123: * flushing the transport.
124: */
125: private void sendCloseConnection() {
126: try {
127: getWriteLock();
128:
129: write(CLOSE_CONNECTION_MESSAGE, 0,
130: CLOSE_CONNECTION_MESSAGE.length);
131:
132: transport.flush();
133:
134: if (getStatisticsProviderAdapter() != null) {
135: getStatisticsProviderAdapter().flushed();
136: }
137:
138: if (delayClose && transport instanceof IIOPConnection) {
139: ((IIOPConnection) transport).turnOnFinalTimeout();
140: } else {
141: // Set do_close to true so anything waiting in waitUntilConnection
142: // doesn't think there is a possibility of connecting. I think.
143: do_close = true;
144:
145: transport.close();
146: }
147: } catch (org.omg.CORBA.COMM_FAILURE e) {
148: logger.error("COMM_FAILURE in sendCloseConnection(), in "
149: + this .toString(), e);
150: } finally {
151: releaseWriteLock();
152: }
153:
154: if (manager != null) {
155: manager.unregisterServerGIOPConnection(this );
156: }
157: }
158:
159: /**
160: * Server-side implementation what to do when a read timeout occurs.
161: * We react by trying an orderly shutdown that's initiated with
162: * a CloseConnection message. If this timeout occured after we have
163: * already sent CloseConnection, just close down unconditionally.
164: */
165: protected void readTimedOut() {
166: if (logger.isDebugEnabled()) {
167: logger.debug(this .toString() + ": readTimedOut()");
168: }
169:
170: if (closeOnReadTimeout) {
171: // we get here if we have sent a CloseConnection message
172: // on this connection before
173: close();
174: } else {
175: // attempt an orderly shutdown by sending a CloseConnection
176: // message
177: tryClose();
178: }
179: }
180:
181: /**
182: * Server-side implementation what to do if the underlying transport
183: * gets closed during a read operation. Since we're server-side and
184: * can't reopen, we simply close completely.
185: */
186: protected void streamClosed() {
187: if (logger.isDebugEnabled()) {
188: logger.debug(this .toString() + ": streamClosed()");
189: }
190: close();
191: }
192:
193: /**
194: * @see GIOPConnection#close()
195: */
196: public void close() {
197: super .close();
198: if (manager != null) {
199: manager.unregisterServerGIOPConnection(this );
200: }
201: }
202:
203: public String toString() {
204: if (profile != null) {
205: return "ServerGIOPConnection to " + profile.toString()
206: + " (" + Integer.toHexString(this .hashCode()) + ")";
207: }
208: return super .toString();
209: }
210:
211: }// ServerGIOPConnection
|