package com.eucalyptus.ws.client;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.List;
import org.apache.log4j.Logger;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpVersion;
import com.eucalyptus.component.ServiceConfiguration;
import com.eucalyptus.config.ComponentConfiguration;
import com.eucalyptus.http.MappingHttpRequest;
import com.eucalyptus.util.LogUtil;
import com.google.common.collect.Lists;
import edu.ucsb.eucalyptus.msgs.ComponentType;
import edu.ucsb.eucalyptus.msgs.HeartbeatComponentType;
import edu.ucsb.eucalyptus.msgs.HeartbeatType;
public class HeartbeatClient {
private static Logger LOG = Logger.getLogger( HeartbeatClient.class );
private InetSocketAddress remoteAddr;
private ChannelFuture channelOpenFuture;
private ChannelFuture channelWriteFuture;
private Channel channel;
private NioBootstrap clientBootstrap;
private String hostName;
private int port;
private List<ComponentType> started = Lists.newArrayList( );
private List<ComponentType> stopped = Lists.newArrayList( );
public HeartbeatClient( NioBootstrap clientBootstrap, String hostName, int port ) {
this.remoteAddr = new InetSocketAddress( hostName, port );
this.clientBootstrap = clientBootstrap;
this.hostName = hostName;
this.port = port;
}
public void send( Collection<ServiceConfiguration> componentConfigurations ) {
try {
HeartbeatType hbmsg = this.getMessage( componentConfigurations );
MappingHttpRequest httpRequest = new MappingHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, this.getHostName( ), this.getPort(), "/services/Heartbeat", hbmsg );
this.write( httpRequest );
} catch ( Exception e ) {
LOG.error( "Error sending configuration to " + LogUtil.dumpObject( componentConfigurations ) );
}
}
public void write( final HttpRequest httpRequest ) throws Exception {
if ( this.channel == null || !this.channel.isOpen( ) || !this.channel.isConnected( ) ) {
this.channelOpenFuture = clientBootstrap.connect( this.remoteAddr );
this.channelOpenFuture.addListener( new DeferedWriter( httpRequest ) );
} else {
channelWriteFuture = this.channel.write( httpRequest );
channelWriteFuture.addListener( ChannelFutureListener.CLOSE );
}
}
class DeferedWriter implements ChannelFutureListener {
private HttpRequest httpRequest;
public DeferedWriter( HttpRequest httpRequest ) {
this.httpRequest = httpRequest;
}
@Override
public void operationComplete( ChannelFuture channelFuture ) throws Exception {
if ( channelFuture.isSuccess( ) ) {
channel = channelFuture.getChannel( );
channelWriteFuture = channelFuture.getChannel( ).write( httpRequest );
channelWriteFuture.addListener( ChannelFutureListener.CLOSE );
LOG.debug( "Sending configuration info to: " + channel.getRemoteAddress( ) );
LOG.info( "Greetings to: " + channel.getRemoteAddress( ) );
} else {
LOG.warn( "Failed to connect to heartbeat service at " + remoteAddr + ": " + channelFuture.getCause( ).getMessage( ) );
if( channel != null ) {
channel.close( );
}
}
}
}
public void close( ) {
if( this.channel != null ) {
this.channel.close( );
}
}
public final String getHostName( ) {
return this.hostName;
}
public int getPort( ) {
return port;
}
private synchronized HeartbeatType getMessage( Collection<ServiceConfiguration> componentConfigurations ) {
HeartbeatType hbmsg = new HeartbeatType( );
hbmsg.getStarted( ).addAll( started );
this.started.clear( );
hbmsg.getStopped( ).addAll( stopped );
this.stopped.clear( );
for( ServiceConfiguration c : componentConfigurations ) {
hbmsg.getComponents( ).add( new HeartbeatComponentType( c.getComponent( ).name( ), c.getName( ) ) );
}
return hbmsg;
}
public synchronized boolean addStarted( ServiceConfiguration e ) {
return this.started.add( new ComponentType( e.getComponent( ).name( ), e.getName( ), e.getUri( ) ) );
}
public synchronized boolean addStopped( ServiceConfiguration e ) {
return this.stopped.add( new ComponentType( e.getComponent( ).name( ), e.getName( ), e.getUri( ) ) );
}
}