/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.jacorb.orb.giop;
import org.jacorb.config.Configuration;
import org.jacorb.config.ConfigurationException;
import org.jacorb.orb.iiop.IIOPConnection;
/**
* @author Nicolas Noffke
*/
public class ServerGIOPConnection
extends GIOPConnection
{
private static final byte[] CLOSE_CONNECTION_MESSAGE =
new byte[] {
// Byte casts are for JDK1.2 compatibility.
(byte )'G', (byte )'I', (byte )'O', (byte )'P', //magic start
1, //GIOP major
0, //GIOP minor
0, //endianess, big-endian
5, //message type, CloseConnection message
0, 0, 0, 0 // message size, 0 because CloseConnection has no body
};
private final GIOPConnectionManager manager;
private boolean closeOnReadTimeout = false;
private boolean delayClose = false;
public ServerGIOPConnection( org.omg.ETF.Profile profile,
org.omg.ETF.Connection transport,
RequestListener request_listener,
ReplyListener reply_listener,
StatisticsProvider statistics_provider,
GIOPConnectionManager manager )
{
super( profile, transport, request_listener, reply_listener, statistics_provider );
this.manager = manager;
}
public void configure(Configuration configuration)
throws ConfigurationException
{
super.configure(configuration);
delayClose =
configuration.getAttributeAsBoolean("jacorb.connection.delay_close", false);
int max_reply_write_time =
configuration.getAttributeAsInteger("jacorb.connection.reply.write_timeout", 0);
init_write_monitor (max_reply_write_time);
}
/**
* Try an orderly shutdown of this connection by sending a
* CloseConnection message. The CORBA spec only allows us to
* do that if we have no more pending messages for which we
* haven't sent a reply yet (CORBA 3.0, 15.5.1.1). If there are
* pending messages, this method does nothing and returns false.
* If there are no pending messages, it sets the connection into
* discarding mode, sends the CloseConnection message, and reports
* the connection as closed to any connection_listener that's registered
* with this connection. The actual closing of the connection will happen
* later, when the transport gets closed by the client, or the final
* timeout has passed.
*/
boolean tryClose()
{
if( tryDiscard() )
{
if (logger.isDebugEnabled())
{
logger.debug(this.toString()
+ ": tryClose() -- will send close connection");
}
sendCloseConnection();
closeOnReadTimeout = true;
if( connection_listener != null )
{
connection_listener.connectionClosed();
}
return true;
}
if (logger.isDebugEnabled())
{
logger.debug(this.toString()
+ ": tryClose() -- cannot close connection");
}
return false;
}
/**
* Atomically try to set this connection into discarding mode, if
* it doesn't have any pending messages.
*
* @return true, if the connection has been idle and discarding
* has been set
*/
private boolean tryDiscard()
{
if( ! hasPendingMessages() )
{
synchronized( pendingUndecidedSync )
{
discard_messages = true;
}
return true;
}
return false;
}
/**
* Sends a close connection message flushing the transport.
*/
private void sendCloseConnection()
{
try
{
getWriteLock(0);
write( CLOSE_CONNECTION_MESSAGE,
0,
CLOSE_CONNECTION_MESSAGE.length );
transport.flush();
if (getStatisticsProviderAdapter() != null)
{
getStatisticsProviderAdapter().flushed();
}
if( delayClose && transport instanceof IIOPConnection )
{
((IIOPConnection)transport).turnOnFinalTimeout();
}
else
{
// Set do_close to true so anything waiting in waitUntilConnection
// doesn't think there is a possibility of connecting. I think.
do_close = true;
transport.close();
}
}
catch( org.omg.CORBA.COMM_FAILURE e )
{
logger.error
(
"COMM_FAILURE in sendCloseConnection(), in " + this.toString(),
e
);
}
finally
{
releaseWriteLock();
}
if( manager != null )
{
manager.unregisterServerGIOPConnection( this );
}
}
/**
* Server-side implementation what to do when a read timeout occurs.
* We react by trying an orderly shutdown that's initiated with
* a CloseConnection message. If this timeout occured after we have
* already sent CloseConnection, just close down unconditionally.
*/
protected void readTimedOut()
{
if (logger.isDebugEnabled())
{
logger.debug (this.toString() + ": readTimedOut()");
}
if( closeOnReadTimeout )
{
// we get here if we have sent a CloseConnection message
// on this connection before
close();
}
else
{
// attempt an orderly shutdown by sending a CloseConnection
// message
tryClose();
}
}
/**
* Server-side implementation what to do if the underlying transport
* gets closed during a read operation. Since we're server-side and
* can't reopen, we simply close completely.
*/
protected void streamClosed()
{
if (logger.isDebugEnabled())
{
logger.debug (this.toString() + ": streamClosed()");
}
close();
}
/**
* @see GIOPConnection#close()
*/
public void close()
{
super.close();
if( manager != null )
{
manager.unregisterServerGIOPConnection( this );
}
}
public String toString()
{
if (profile != null)
{
return "ServerGIOPConnection to "
+ profile.toString()
+ " from "
+ orb.getBasicAdapter ().getEndpointProfiles ()
+ " (" + Integer.toHexString(this.hashCode()) + ")";
}
return super.toString();
}
}// ServerGIOPConnection