/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.ha;
import java.util.HashMap;
import java.util.Map;
import org.neo4j.com.MismatchingVersionHandler;
import org.neo4j.kernel.impl.nioneo.store.StoreId;
import org.neo4j.kernel.impl.util.StringLogger;
import org.neo4j.kernel.lifecycle.LifeSupport;
public class MasterClientResolver implements MasterClientFactory, MismatchingVersionHandler
{
private volatile MasterClientFactory currentFactory;
private volatile ProtocolVersionCombo currentVersion;
private boolean downgradeForbidden = false;
@Override
public MasterClient instantiate( String hostNameOrIp, int port, StoreId storeId, LifeSupport life )
{
MasterClient result = currentFactory.instantiate( hostNameOrIp, port, storeId, life );
result.addMismatchingVersionHandler( this );
return result;
}
@Override
public void versionMismatched( int expected, int received )
{
getFor( received, 2 );
}
private static final class ProtocolVersionCombo implements Comparable<ProtocolVersionCombo>
{
final int applicationProtocol;
final int internalProtocol;
ProtocolVersionCombo( int applicationProtocol, int internalProtocol )
{
this.applicationProtocol = applicationProtocol;
this.internalProtocol = internalProtocol;
}
@Override
public boolean equals( Object obj )
{
if ( obj == null )
{
return false;
}
if ( obj.getClass() != ProtocolVersionCombo.class )
{
return false;
}
ProtocolVersionCombo other = (ProtocolVersionCombo) obj;
return other.applicationProtocol == applicationProtocol && other.internalProtocol == internalProtocol;
}
@Override
public int hashCode()
{
return ( 31 * applicationProtocol ) | internalProtocol;
}
@Override
public int compareTo( ProtocolVersionCombo o )
{
return ( applicationProtocol < o.applicationProtocol ? -1
: ( applicationProtocol == o.applicationProtocol ? 0 : 1 ) );
}
static final ProtocolVersionCombo PC_153 = new ProtocolVersionCombo( 2, 2 );
static final ProtocolVersionCombo PC_17 = new ProtocolVersionCombo( 3, 2 );
static final ProtocolVersionCombo PC_18 = new ProtocolVersionCombo( 4, 2 );
}
private final Map<ProtocolVersionCombo, MasterClientFactory> protocolToFactoryMapping;
public MasterClientResolver( StringLogger messageLogger, int readTimeout, int lockReadTimeout, int channels,
int chunkSize )
{
protocolToFactoryMapping = new HashMap<ProtocolVersionCombo, MasterClientFactory>();
protocolToFactoryMapping.put( ProtocolVersionCombo.PC_153, new F153( messageLogger, readTimeout, lockReadTimeout,
channels, chunkSize ) );
protocolToFactoryMapping.put( ProtocolVersionCombo.PC_17, new F17( messageLogger, readTimeout, lockReadTimeout,
channels, chunkSize ) );
protocolToFactoryMapping.put( ProtocolVersionCombo.PC_18, new F18( messageLogger, readTimeout, lockReadTimeout,
channels, chunkSize ) );
}
public MasterClientFactory getFor( int applicationProtocol, int internalProtocol )
{
ProtocolVersionCombo incomingCombo = new ProtocolVersionCombo( applicationProtocol, internalProtocol );
MasterClientFactory candidate = protocolToFactoryMapping.get( incomingCombo );
/*
* Things that can happen here regarding replacing the current factory, in order:
* 1. We do not know the protocol - candidate is null: We don't change the current factory
* 2. The current factory is null: We always set it to the latest requested
* 3. We receive a version newer than the current one: Always replace the current factory
* 4. We receive a version older than the current: Replace if downgrades are allowed, else leave as is.
*/
if ( ( candidate != null )
&& ( currentVersion == null || !downgradeForbidden || currentVersion.compareTo( incomingCombo ) <= 0 ) )
{
currentFactory = candidate;
currentVersion = incomingCombo;
}
return candidate;
}
public MasterClientFactory getDefault()
{
return getFor( ProtocolVersionCombo.PC_18.applicationProtocol, ProtocolVersionCombo.PC_18.internalProtocol );
}
protected static abstract class StaticMasterClientFactory implements MasterClientFactory
{
protected final StringLogger stringLogger;
protected final int readTimeoutSeconds;
protected final int lockReadTimeout;
protected final int maxConcurrentChannels;
protected final int chunkSize;
StaticMasterClientFactory( StringLogger stringLogger, int readTimeoutSeconds, int lockReadTimeout,
int maxConcurrentChannels, int chunkSize )
{
this.stringLogger = stringLogger;
this.readTimeoutSeconds = readTimeoutSeconds;
this.lockReadTimeout = lockReadTimeout;
this.maxConcurrentChannels = maxConcurrentChannels;
this.chunkSize = chunkSize;
}
}
public static final class F153 extends StaticMasterClientFactory
{
public F153( StringLogger stringLogger, int readTimeoutSeconds, int lockReadTimeout, int maxConcurrentChannels,
int chunkSize )
{
super( stringLogger, readTimeoutSeconds, lockReadTimeout, maxConcurrentChannels, chunkSize );
}
@Override
public MasterClient instantiate( String hostNameOrIp, int port, StoreId storeId, LifeSupport life )
{
return life.add( new MasterClient153( hostNameOrIp, port, stringLogger, storeId,
readTimeoutSeconds, lockReadTimeout, maxConcurrentChannels, chunkSize ) );
}
};
public static final class F17 extends StaticMasterClientFactory
{
public F17( StringLogger stringLogger, int readTimeoutSeconds, int lockReadTimeout, int maxConcurrentChannels,
int chunkSize )
{
super( stringLogger, readTimeoutSeconds, lockReadTimeout, maxConcurrentChannels, chunkSize );
}
@Override
public MasterClient instantiate( String hostNameOrIp, int port, StoreId storeId, LifeSupport life )
{
return life.add( new MasterClient17( hostNameOrIp, port, stringLogger, storeId,
readTimeoutSeconds, lockReadTimeout, maxConcurrentChannels, chunkSize ) );
}
};
public static final class F18 extends StaticMasterClientFactory
{
public F18( StringLogger stringLogger, int readTimeoutSeconds, int lockReadTimeout, int maxConcurrentChannels,
int chunkSize )
{
super( stringLogger, readTimeoutSeconds, lockReadTimeout, maxConcurrentChannels, chunkSize );
}
@Override
public MasterClient instantiate( String hostNameOrIp, int port, StoreId storeId, LifeSupport life )
{
return life.add( new MasterClient18( hostNameOrIp, port, stringLogger, storeId,
readTimeoutSeconds, lockReadTimeout, maxConcurrentChannels, chunkSize ) );
}
}
public void enableDowngradeBarrier()
{
downgradeForbidden = true;
}
}