2013년 10월 4일 금요일

JacORB Chapter 3_03

Acceptor Exception Event Plugin
This plugin is implemented by org.jacorb.orb.listener.AcceptorExceptionListener.


package org.jacorb.orb.listener;
public interface AcceptorExceptionListener extends EventListener
  void exceptionCaught(AcceptorExceptionEvent ae);


The configuration property is


jacorb.acceptor_exception_listener


If the server listener thread receives an exception while doing the ServerSocket.accept() it will construct a org.jacorb.orb.listener.AcceptorExceptionEvent and notify the configured implementation. The Event allows the following to be retrieved:


public ORB getORB()
public Throwable getException()


The default implementation, org.jacorb.orb.listener.DefaultAcceptorExceptionListener, will simply shutdown the ORB on all Errors and for SSLExceptions that are thrown before any socket connections have been made. If the developer wishes they may plugin their own for more fine grained control.
In order to detect whether the exception has been thrown on the first attempt or any attempt after that the developer may use the following function within their listener implementation.


public void exceptionCaught(AcceptorExceptionEvent ae) {
...
if (((org.jacorb.orb.iiop.IIOPListener.Acceptor)
ae.getSource()).getAcceptorSocketLoop()) {
...


getAcceptorSocketLoop returns false if the event has been thrown on the initial loop, or true on any loop after that.
Note that if the default implementation is used it is possible that due to e.g. an SSLException the listener will fail to accept on the server socket after the root POA is resolved which means that the ORB will be shutdown. Therefore future calls on that POA will fail with a ’POA destroyed’ message.


3.3.1 JacORB Implname and CORBA Objects

A JacORB object key consists of <impl name>/<poa name>/<object oid>. The lifespan of CORBA objects are defined by the POA policy LifespanPolicyValue.
Transient objects are those whose lifespans are bounded by the process in which they were created. Once a transient object has been destroyed any clients still holding references to those objects should receive a OBJECT NOT EXIST. This applies even if the transient object is recreated as it is a new object reference. To achieve this JacORB replaces the implname portion of the key with transient data.
Persistent objects are those that may live beyond the lifetime of the process that created them. The implname property should be configured in this case. It should be set to a unique name to to form part of the object identity. If it is not set, an exception will be thrown. This property may be configured in the jacorb.properties (where an example shows it set to StandardImplName) or in the code of the server e.g.


/* create and set properties */
java.util.Properties props = new java.util.Properties();
props.setProperty("jacorb.use_imr","on");
props.setProperty("jacorb.implname","MyName");
/* init ORB */
orb = org.omg.CORBA.ORB.init(args, props);


The implname property allows a program to run with a different implementation name so that it will not accept references created by another persistent POA with the same POA name. A common problem is where the developer has two persistent servers running with the same implname and POA names when one tries to contact the other. Rather than calling server x, server y performs local call. This is because there is no way of distinguishing the two servers; the developer should have used different implnames (e.g. UUIDs).


Corbaloc with JacORB Implname and CORBA Objects


Normally corbaloc is used to provide a shortcut to refer to CORBA objects. However the stringified key portion corresponds to the octet sequence in the object key member of a GIOP Request or LocateRequest header as defined in section 15.4 of CORBA 2.3. Further the key string uses the escape conventions described in RFC 2396 to map away from octet values that cannot directly be part of a URL. This means the key string might look like:



corbaloc:iiop:10.1.0.4:18000/FooBar/ServiceName/V_3%f1%1c%9b%11%db%b7%e9
%bdsnQ%ea%85qV_3%f0%1c%9b%11%db%b7%e9%bdsnQ%ea%85TA5%f0%1c%9b%11
%db%b7%e9%bdsnQ%ea%85


With JacORB, for persistent objects, the developer may configure the implname, poa name and object key. This should mean that the corbaloc sequence should be more readable:


corbaloc:iiop:10.1.0.4:42811/imr_demo/ImRDemoServerPOA/imr_demo


With a transient object the key may look like:


corbaloc:iiop:10.1.0.4:42818/2649480905/%14%3e45%0d%0b!%10%3e


As it is not possible to construct a transient object with a readable key some developers may find it useful to use the objectKeyMap facility within JacORB to refer to their transient objects. Note the objectKey functionality may also be used with persistent objects.
This property provides more readable corbaloc URLs by mapping the actual object key to an arbitrary string. The mapping below would permit clients of a name service to access it using corbaloc::ipaddress:portnum/NameService. The property also accepts the following mappings:


  • IOR, resource, jndi, URL (e.g. file, http)


Note that jacorb.orb.objectKeyMap.name is configurable both through the jacorb.properties file and through the proprietary function


ORB::addObjectKey(String name, String)
Example usage


jacorb.orb.objectKeyMap.NameService=file:///home/rnc/NameSingleton.ior


This then allows the corbaloc key portion to simply be ’NameService’.



3.3.2 JacORB Network Event Logging



An enhancement has been added to JacORB that allows a developer to monitor TCP and SSL connections.
Note that for both of these implementations full information may only retrieved with a successful connection; e.g. if the connection could not be established there will be no certificates.


TCP Monitoring


To monitor TCP connections a developer should implement the following interface


package org.jacorb.orb.listener;
public interface TCPConnectionListener extends EventListener
void connectionOpened(TCPConnectionEvent e);
void connectionClosed(TCPConnectionEvent e);


The classname should then be specified in the property


jacorb.net.tcp_listener


The standard java event interface is followed; the developer’s code will receive the TCPConnection-Event which allows the following information to be retrieved:


public String getLocalIP()
public int getLocalPort()
public String getRemoteIP()
public int getRemotePort()


Note that the TCPConnectionEvent extends java.util.EventObject and the EventObject.getSource operation will return the IIOPConnection of the TCP connection.


SSL Monitoring


To monitor SSL sessions a developer should implement the following interface


package org.jacorb.orb.listener;
public interface SSLSessionListener extends EventListener
void sessionCreated(SSLSessionEvent e);
void handshakeException(SSLSessionEvent e);
void keyException(SSLSessionEvent e);
void peerUnverifiedException(SSLSessionEvent e);
void protocolException(SSLSessionEvent e);
void sslException(SSLSessionEvent e);


The classname should then be specified in the property


jacorb.security.ssl.ssl_listener


The standard java event interface is followed; the developer’s code will receive the SSLSessionEvent which allows the following information to be retrieved:


public String getLocalIP()
public int getLocalPort()
public String getRemoteIP()
public int getRemotePort()
public String getRemoteDN()
public X509Certificate[] getPeerCertificateChain()


Note that getRemoteDN will simply return a concatenated string of the certificates. For that reason it is deprecated; getPeerCertificateChain should be used instead as that allows a developer to extract specific information from the certificate. In order to detect a succesful handshake the implementation delegates to the JSSE javax.net.ssl.HandShakeCompletedListener. When using JDK1.3 JSSE the JSSE may not throw for instance a handshakeException but a sslException. Similar to above, SSLSessionEvent extends java.util.EventObject. The EventObject.getSource operation will return the source of the HandshakeCompletedEvent.


3.3.3 JacORB IORMutator



An enhancement has been added to JacORB that allows a developer to alter incoming and outgoing objects at a very low level within the ORB. While the majority of the users would not require this ability, it is useful within scenarios where for instance, a user is running with legacy network elements which have multiple, identical IP addresses. This allows them to mutate the IORs as shown below.


This is a very powerful ability that must be used with caution. As it operates at the CDRStream level it is easy to break the ORB and cause unpredictable behaviour


Adding a Mutator


The developer should firstly extend the following abstract class.


package org.jacorb.orb.IORMutator;
public abstract class IORMutator
protected org.omg.ETF.Connection connection;
public abstract IOR mutateIncoming (IOR object);
public abstract IOR mutateOutgoing (IOR object);


The classname should then be specified in the property


jacorb.iormutator

The IORMutator class also has a org.omg.ETF.Connection connection variable. This variable will be updated with the current transport information for the respective streams. Note, altering the information within the transport is undefined. The mutateIncoming operation will be called for CDRInputStream operations and the mutateOutgoing for CDROuputStream operations.

JacORB Chapter 16

16 Connection Management and Connection Timeouts

JacORB offers a certain level of control over connections and timeouts. You can
  • set connection idle timeouts.
  • set request timing.
  • set the maximum number of accepted TCP/IP connections on the server

16.1 Timeouts

Connection idle timeouts can be set individually for the client and the server. They control how long an idle connection, i.e. a connection that has no pending replies, will stay open. The corresponding properties are jacorb.connection.client.idle timeout and jacorb.connection.server.timeout and take their values as milliseconds. If not set, connections will stay open indefinitely (or until the OS decides to close them).
Request timing controls how long an individual request may take to complete. The programmer can specify this using QoS policies, discussed in chapter 15.

16.2 Connection Management

When a client wants to invoke a remote object, it needs to send the request over a connection to the server. If the connection isn’t present, it has to be created. In JacORB, this will only happen once for every combination of host name and port. Once the connection is established, all requests and replies between client and server will use the same connection. This saves resources while adding a thin layer of necessary synchronization, and is the recommended approach of the OMG. Occasionally people have requested to allow for multiple connections to the same server, but nobody has yet presented a good argument that more connections would speed up things considerably.
On the server side, the property jacorb.connection.max server transports allows to set the maximum number of TCP/IP connections that will be listened on for requests. When using a network sniffer or tools like netstat, more inbound TCP/IP connections than the configured number may be displayed. This is for the following reason: Whenever the connection limit is reached, JacORB tries to close existing idle connections (see the subsection below). This is done on the thread that accepts the new connections, so JacORB will not actively accept more connections. However, the ServerSocket is initialized with a backlog of 20. This means that 20 more connections will be quasi-accepted by the OS. Only the 21st will be rejected right away.


16.2.1 Basics and Design

Whenever there is the need to close an existing connection because of the connection limit, the question arises on which of the connection to close. To allow for maximum flexibility, JacORB provides the interface SelectionStrategy that allows for a custom way to select a connection to close. Because selecting a connection usually requires some sort of statistical data about it, the interface StatisticsProvider allows to implement a class that collects statistical data.

package org.jacorb.orb.giop;

public interface SelectionStrategy
{
public ServerGIOPConnection
selectForClose( java.util.List connections );
}

public interface StatisticsProvider
{
public void messageChunkSent( int size );
public void flushed();
public void messageReceived( int size );
}

The interface SelectionStrategy has only the single method of selectForClose(). This is called by the class GIOPConnectionManager when a connection needs to be closed. The argument is a List containing objects of type ServerGIOPConnection. The call itself is synchronized in the GIOPConnectionManager, so no additional synchronization has to be done by the implementor of SelectionStrategy. When examining the connections, the strategy can get hold of the StatisticsProvider via the method getStatisticsProvider() of the class GIOPConnection. The strategy implementor should take care only to return idle connections. While the connection state is checked anyway while closing (it may have changed in the meantime), it seems to be more efficient to avoid cycling through the connections. When no suitable connection is available, the strategy may return null. The GIOPConnectionManager will then wait for a configurable time, and try again. This goes on until a connection can be closed.
The interface StatisticsProvider is used to collect statistical data about a connection and provide it to the SelectionStrategy. Because the nature of this data may vary, there is no standard access to the data via the interface. Therefore, StatisticsProvider and SelectionStrategy usually need to be implemented together. Whenever a new connection is created, a new StatisticsProvider object is instanciated and stored with the GIOPConnection. The StatisticsProvider interface is oriented along the mode of use of the GIOPConnection.
For efficiency reasons, messages are not sent as one big byte array. Instead, they are sent piecewise over the wire. When such a chunk is sent, the method messageChunkSent(int size) will be called. After the message has been completely sent, method flush() is called. This whole process is synchronized, so all consecutive messageChunkSents until a flush() form a single message. Therefore, no synchronization on this level is necessary. However, access to gathered statistical data by the SelectionStrategy is concurrent, so care has to be taken. Receiving messages is done only on the whole, so there exists only one method, messageReceived(int size), to notify the StatisticsProvider of such an event.
JacORB comes with two pre-implemented strategies: least frequently used and least recently used. LFU and LRU are implemented by the classes org.jacorb.orb.giop.L[F|R]USelectionStrategyImpl and org.jacorb.orb.giop. L[F|R]UStatisticsProviderImpl.

16.2.2 Configuration

To configure connection management, the following properties are provided:
jacorb.connection.max_server_connections This property sets the maximum number of TCP/IP connections that will be listened on by the server–side ORB.
jacorb.connection.wait_for_idle_interval This property sets the interval to wait until the next try is made to find an idle connection to close. Value is in microseconds.
jacorb.connection.selection_strategy_class This property sets the SelectionStrategy.
jacorb.connection.statistics_provider_class This property sets the StatisticsProvider.
jacorb.connection.delay_close If turned on, JacORB will delay closing of TCP/IP connections to avoid certain situations, where message loss can occur. See also section 16.2.3.

16.2.3 Limitations

When trying to close a connection, it is first checked that the connection is idle, i.e. has no pending messages. If this is the case, a GIOP CloseConnection message is sent, and the TCP/IP connection is closed. Under high load, this can lead to the following situation:
  1. Server sends the CloseConnection message.
  2. Server closes the TCP/IP connection.
  3. The client sends a new request into the connection, because it hasn’t yet read and acted on the CloseConnection message.
  4. The server–side OS will send a TCP RST, which cancels out the CloseConnection message.
  5. The client finds the connection closed and must consider the request lost.
To get by this situation, JacORB takes the following approach. Instead of closing the connection right after sending the CloseConnection message, we delay closing and wait for the client to close the connection. This behaviour is turned off by default, but can be enabled by setting the property jacorb.connection.delay_close to “yes”. When non-JacORB clients are used care has to be taken that these ORBs do actively close the connection upon receiving a CloseConnection message.