/*************************************************************************
* Copyright 2009-2016 Eucalyptus Systems, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
************************************************************************/
package com.eucalyptus.network.applicator;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import com.eucalyptus.cluster.NetworkInfo;
import com.eucalyptus.cluster.callback.BroadcastNetworkInfoCallback;
import com.eucalyptus.cluster.common.internal.Cluster;
import com.eucalyptus.crypto.util.B64;
import com.eucalyptus.event.ClockTick;
import com.eucalyptus.event.EventListener;
import com.eucalyptus.event.Listeners;
import com.eucalyptus.util.async.AsyncRequests;
import com.eucalyptus.util.async.UnconditionalCallback;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import com.eucalyptus.cluster.common.msgs.BroadcastNetworkInfoResponseType;
/**
*
*/
public class BroadcastingApplicator implements Applicator {
private static final Logger logger = Logger.getLogger( BroadcastingApplicator.class );
private static final ConcurrentMap<String,Long> activeBroadcastMap = Maps.newConcurrentMap( );
@Override
public void apply( final ApplicatorContext context, final ApplicatorChain chain ) throws ApplicatorException {
final NetworkInfo netInfo = context.getNetworkInfo( );
final String networkInfo = MarshallingApplicatorHelper.getMarshalledNetworkInfo( context );
final String encodedNetworkInfo =
new String( B64.standard.enc( networkInfo.getBytes( Charsets.UTF_8 ) ), Charsets.UTF_8 );
final BroadcastNetworkInfoCallback callback = new BroadcastNetworkInfoCallback(
encodedNetworkInfo,
netInfo.getVersion( ),
netInfo.getAppliedVersion( )
);
for ( final Cluster cluster : context.getClusters( ) ) {
final Long broadcastTime = System.currentTimeMillis( );
if ( null == activeBroadcastMap.putIfAbsent( cluster.getPartition( ), broadcastTime ) ) {
try {
AsyncRequests.newRequest( callback.newInstance( ) ).then( new UnconditionalCallback<BroadcastNetworkInfoResponseType>() {
@Override
public void fire( ) {
activeBroadcastMap.remove( cluster.getPartition( ), broadcastTime );
}
} ).dispatch( cluster.getConfiguration( ) );
} catch ( Exception e ) {
activeBroadcastMap.remove( cluster.getPartition( ), broadcastTime );
logger.error( "Error broadcasting network information to cluster (" + cluster.getPartition() + ") ("+cluster.getName()+")", e );
}
} else {
logger.warn( "Skipping network information broadcast for active partition " + cluster.getPartition( ) );
}
}
chain.applyNext( context );
}
public static class BroadcastingApplicatorEventListener implements EventListener<ClockTick> {
private final int activeBroadcastTimeoutMins = 3;
public static void register( ) {
Listeners.register( ClockTick.class, new BroadcastingApplicatorEventListener( ) );
}
@SuppressWarnings("UnnecessaryQualifiedReference")
@Override
public void fireEvent( final ClockTick event ) {
for ( final Map.Entry<String,Long> entry : BroadcastingApplicator.activeBroadcastMap.entrySet( ) ) {
if ( entry.getValue() + TimeUnit.MINUTES.toMillis( activeBroadcastTimeoutMins ) < System.currentTimeMillis( ) &&
BroadcastingApplicator.activeBroadcastMap.remove( entry.getKey( ), entry.getValue( ) ) ) {
logger.warn( "Timed out active network information broadcast for partition " + entry.getKey( ) );
}
}
}
}
}