All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.refcodes.rest.ext.eureka.EurekaRegistrySidecarImpl Maven / Gradle / Ivy

// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/LICENSE-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.rest.ext.eureka;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;

import org.refcodes.component.InitializeException;
import org.refcodes.component.LifeCycleStatus;
import org.refcodes.component.OpenException;
import org.refcodes.component.PauseException;
import org.refcodes.component.ResumeException;
import org.refcodes.component.StartException;
import org.refcodes.component.StopException;
import org.refcodes.data.Scheme;
import org.refcodes.exception.ExceptionUtility;
import org.refcodes.logger.RuntimeLogger;
import org.refcodes.logger.RuntimeLoggerFactorySingleton;
import org.refcodes.net.HttpResponseException;
import org.refcodes.net.HttpStatusException;
import org.refcodes.net.IpAddress;
import org.refcodes.net.MediaType;
import org.refcodes.net.Url;
import org.refcodes.net.UrlBuilderImpl;
import org.refcodes.net.UrlImpl;
import org.refcodes.rest.AbstractHttpRegistrySidecar;
import org.refcodes.rest.HttpRegistrySidecar;
import org.refcodes.rest.HttpRestClient;
import org.refcodes.rest.HttpRestClientImpl;
import org.refcodes.rest.HttpServerDescriptor;
import org.refcodes.rest.RestRequestBuilder;
import org.refcodes.rest.RestResponse;
import org.refcodes.runtime.SystemUtility;
import org.refcodes.security.TrustStoreDescriptor;

import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.util.EC2MetadataUtils;
import com.amazonaws.util.EC2MetadataUtils.NetworkInterface;

/**
 * The {@link EurekaRegistrySidecarImpl} provides you with a library for
 * registering your web-services at Eureka service registry and discovery.
 */
public class EurekaRegistrySidecarImpl extends AbstractHttpRegistrySidecar implements EurekaRegistrySidecar {

	private static RuntimeLogger LOGGER = RuntimeLoggerFactorySingleton.createRuntimeLogger();

	// /////////////////////////////////////////////////////////////////////////
	// STATICS:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// CONSTANTS:
	// /////////////////////////////////////////////////////////////////////////

	private static final String DEFAULT_PING_PATH = "/ping";
	private static final String DEFAULT_HOME_PATH = "/home";
	private static final String DEFAULT_STATUS_PATH = "/status";

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	private ExecutorService _executorService;
	private Timer _scheduler;
	private EurekaDataCenterType _dataCenterType;
	private String _statusPath;
	private String _homePath;
	private int _port = -1;
	private Scheme _scheme = null;
	private String _protocol = null;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTORS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * @param aExecutorService An executor service to be used when creating
	 *        {@link Thread}s.
	 */
	public EurekaRegistrySidecarImpl( ExecutorService aExecutorService ) {
		_executorService = aExecutorService;
	}

	// /////////////////////////////////////////////////////////////////////////
	// INJECTION:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// LIFECYCLE:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void initialize( EurekaServerDescriptor aServerDescriptor, Url aRegistryUrl, TrustStoreDescriptor aStoreDescriptor ) throws InitializeException {
		super.initialize();
		aRegistryUrl = toHttpRegistryUrl( aRegistryUrl, this );
		aStoreDescriptor = toTrustStoreDescriptor( aStoreDescriptor, this );
		aServerDescriptor = toHttpServerDescriptor( aServerDescriptor, this );
		try {
			doRegister( EurekaServiceStatus.STARTING );
		}
		catch ( Exception e ) {
			_lifeCycleAutomaton.setLifeCycleStatus( LifeCycleStatus.ERROR );
			throw new InitializeException( ExceptionUtility.toMessage( e ), e );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void start() throws StartException {
		try {
			super.start();
			doStatusUpdate( EurekaServiceStatus.UP );
			_scheduler = new Timer( true );
			_scheduler.schedule( new HeartBeatDaemon( this, _executorService ), EurekaLoopSleepTime.REGISTRY_SERVICE_HEARBEAT.getMillis(), EurekaLoopSleepTime.REGISTRY_SERVICE_HEARBEAT.getMillis() );
		}
		catch ( Exception e ) {
			_lifeCycleAutomaton.setLifeCycleStatus( LifeCycleStatus.ERROR );
			throw new StartException( ExceptionUtility.toMessage( e ), e );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void pause() throws PauseException {
		super.pause();
		try {
			doStatusUpdate( EurekaServiceStatus.DOWN );
		}
		catch ( Exception e ) {
			_lifeCycleAutomaton.setLifeCycleStatus( LifeCycleStatus.ERROR );
			throw new PauseException( ExceptionUtility.toMessage( e ), e );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void resume() throws ResumeException {
		super.resume();
		try {
			doStatusUpdate( EurekaServiceStatus.UP );
		}
		catch ( Exception e ) {
			_lifeCycleAutomaton.setLifeCycleStatus( LifeCycleStatus.ERROR );
			throw new ResumeException( ExceptionUtility.toMessage( e ), e );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void stop() throws StopException {
		super.stop();
		try {
			_scheduler.cancel();
			doStatusUpdate( EurekaServiceStatus.OUT_OF_SERVICE );
		}
		catch ( Exception e ) {
			_lifeCycleAutomaton.setLifeCycleStatus( LifeCycleStatus.ERROR );
			throw new StopException( ExceptionUtility.toMessage( e ), e );
		}

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void destroy() {
		super.destroy();
		try {
			_scheduler.cancel();
			doDeregister();
		}
		catch ( Exception e ) {
			LOGGER.warn( ExceptionUtility.toMessage( e ), e );
			_lifeCycleAutomaton.setLifeCycleStatus( LifeCycleStatus.ERROR );

		}
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setPort( int aPort ) {
		_port = aPort;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getPort() {
		return _port;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toProtocol() {
		if ( _scheme != null ) {
			return _scheme.toProtocol();
		}
		return _protocol;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setProtocol( String aProtocol ) {
		Scheme theScheme = Scheme.fromProtocol( aProtocol );
		if ( theScheme != null ) {
			_scheme = theScheme;
			_protocol = null;
		}
		else {
			_protocol = aProtocol;

			_scheme = null;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setScheme( Scheme aScheme ) {
		_scheme = aScheme;
		_protocol = null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Scheme getScheme() {
		return _scheme;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getHomePath() {
		return _homePath;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setHomePath( String aHomePath ) {
		_homePath = aHomePath;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getStatusPath() {
		return _statusPath;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setStatusPath( String aStatusPath ) {
		_statusPath = aStatusPath;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public EurekaDataCenterType getEurekaDataCenterType() {
		return _dataCenterType;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setEurekaDataCenterType( EurekaDataCenterType aDataCenterType ) {
		_dataCenterType = aDataCenterType;
	}

	// /////////////////////////////////////////////////////////////////////////
	// TWEAKS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */
	@Override
	public EurekaServerDescriptor toHttpServerDescriptor( String aAlias, String aInstanceId, Scheme aScheme, String aHost, String aVirtualHost, int[] aIpAddress, int aPort, String aPingPath, String aStatusPath, String aHomePath, EurekaDataCenterType aDataCenterType ) {
		return toHttpServerDescriptor( aAlias, aInstanceId, aScheme, aHost, aVirtualHost, aIpAddress, aPort, aPingPath, aStatusPath, aHomePath, aDataCenterType, this );
	}

	/**
	 * Attention: This method is package local! As it does some well known casts
	 * which are not obvious from the method signature!
	 * 
	 * !!! ONLY INTENDED TO BE USED BY THE MAINTAINER OF THIS CLASS !!!
	 * 
	 * Prepares the {@link HttpServerDescriptor} by creating it from this
	 * instance's state and the provided arguments. The provided arguments can
	 * modify theinstance's state. The {@link HttpServerDescriptor} as finally
	 * used is returned. You may modify this context and use it after
	 * modification to initialize the server via
	 * {@link HttpRegistrySidecar#initialize(HttpServerDescriptor, Url)} or
	 * {@link HttpRegistrySidecar#initialize(HttpServerDescriptor, Url, TrustStoreDescriptor)}.
	 * 
	 * @param aAlias The name ("alias") which identifies the server in the
	 *        registry.
	 * @param aInstanceId The ID for the instance when being registered at the
	 *        service registry. If omitted, then the host name is used.
	 * @param aScheme The {@link Scheme} to which this server is being attached
	 *        (HTTP or HTTPS).
	 * @param aHost The host name to be used to address this server. If omitted,
	 *        then the system's host name should be used.
	 * @param aVirtualHost The virtual host name to be used for resolving.
	 * @param aIpAddress The IP-Address identifying the host.
	 * @param aPort The port of your service being registered. Make sure, you do
	 *        not
	 * @param aPingPath The path to use as health-check end-point by this
	 *        server.
	 * @param aStatusPath The path to use as status-page end-point by this
	 *        server.
	 * @param aHomePath The path to use as home-page end-point by this server.
	 * @param aDataCenterType The data center type to be used.
	 * 
	 * @param aRegistryService The service which's state is to be used.
	 * 
	 * @return The {@link HttpServerDescriptor} as would be used when
	 *         initializing this instance via
	 *         {@link HttpRegistrySidecar#initialize()}
	 */
	static EurekaServerDescriptor toHttpServerDescriptor( String aAlias, String aInstanceId, Scheme aScheme, String aHost, String aVirtualHost, int[] aIpAddress, int aPort, String aPingPath, String aStatusPath, String aHomePath, EurekaDataCenterType aDataCenterType, EurekaRegistry aRegistryService ) {
		try {
			aHost = toHost( aHost, aRegistryService );
		}
		catch ( UnknownHostException e ) {
			LOGGER.warn( "Unable to determine host as of <" + e.getClass().getName() + ">: " + ExceptionUtility.toMessage( e ) );
		}
		try {
			aIpAddress = toIpAddress( aIpAddress, aRegistryService );
		}
		catch ( IOException e ) {
			LOGGER.warn( "Unable to determine host as of <" + e.getClass().getName() + ">: " + ExceptionUtility.toMessage( e ) );
		}
		aPort = toPort( aPort, (PortProperty) aRegistryService );
		aScheme = toScheme( aScheme, (SchemeProperty) aRegistryService );
		aAlias = toAlias( aAlias, aRegistryService );
		aVirtualHost = toVirtualHost( aVirtualHost, aRegistryService );
		aDataCenterType = toDataCenterType( aDataCenterType, aRegistryService );
		aInstanceId = toInstanceId( aInstanceId, aHost, aRegistryService );
		EurekaServerDescriptor theServerDescriptor = new EurekaServerDescriptorImpl();
		aPingPath = toPingPath( aPingPath, DEFAULT_PING_PATH, aRegistryService );
		Url thePingUrl = new UrlImpl( aScheme, aHost, ((PortProperty) aRegistryService).getPort(), aPingPath );
		theServerDescriptor.setPingUrl( thePingUrl );
		aHomePath = toHomePath( aHomePath, DEFAULT_HOME_PATH, aRegistryService );
		Url theHomeUrl = new UrlImpl( aScheme, aHost, ((PortProperty) aRegistryService).getPort(), aHomePath );
		theServerDescriptor.setHomeUrl( theHomeUrl );
		aStatusPath = toStatusPath( aStatusPath, DEFAULT_STATUS_PATH, aRegistryService );
		Url theStatusUrl = new UrlImpl( aScheme, aHost, ((PortProperty) aRegistryService).getPort(), aStatusPath );
		theServerDescriptor.setStatusUrl( theStatusUrl );
		theServerDescriptor.setHost( aInstanceId ); // Host := instance!
		theServerDescriptor.setAlias( aAlias );
		theServerDescriptor.setPort( aPort );
		theServerDescriptor.setIpAddress( aIpAddress );
		theServerDescriptor.setLeaseEvictionDurationInSecs( 30 );
		theServerDescriptor.setVirtualHost( aVirtualHost );
		AmazonMetaData theMetaData = toAmazonMetaData();
		if ( theMetaData != null ) {
			theServerDescriptor.setAmazonMetaData( theMetaData );
		}
		if ( aDataCenterType == null ) {
			aDataCenterType = theMetaData != null ? EurekaDataCenterType.AMAZON : EurekaDataCenterType.MY_OWN;
		}
		theServerDescriptor.setEurekaDataCenterType( aDataCenterType );
		// Meta-Data |-->
		theServerDescriptor.putMetaData( "host", aHost );
		theServerDescriptor.putMetaData( "uname", SystemUtility.getUname() );
		theServerDescriptor.putMetaData( "ipAddress", IpAddress.toString( aIpAddress ) );
		// Meta-Data <--|
		return theServerDescriptor;
	}

	// /////////////////////////////////////////////////////////////////////////
	// HOOKS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Resolves the property from the provided value and the provided property
	 * and sets the property in case the provided value is not null.
	 * 
	 * @param aHomePath The value to be used when not null.
	 * @param aDefaultHomePath The value to be used when instance ID is null.
	 * @param aProperty The property to be used when the value is null and which
	 *        is to be set when the value is not null.
	 * 
	 * @return The value when not null, else the value of the provided property.
	 */
	protected static String toHomePath( String aHomePath, String aDefaultHomePath, HomePathProperty aProperty ) {
		if ( aHomePath != null ) {
			aProperty.setHomePath( aHomePath );
		}
		else {
			aHomePath = aProperty.getHomePath();
			if ( aHomePath == null ) {
				aHomePath = aDefaultHomePath;
				aProperty.setHomePath( aHomePath );
			}
		}
		return aHomePath;
	}

	/**
	 * Resolves the property from the provided value and the provided property
	 * and sets the property in case the provided value is not null.
	 * 
	 * @param aStatusPath The value to be used when not null.
	 * @param aDefaultStatusPath The value to be used when instance ID is null.
	 * @param aProperty The property to be used when the value is null and which
	 *        is to be set when the value is not null.
	 * 
	 * @return The value when not null, else the value of the provided property.
	 */
	protected static String toStatusPath( String aStatusPath, String aDefaultStatusPath, StatusPathProperty aProperty ) {
		if ( aStatusPath != null ) {
			aProperty.setStatusPath( aStatusPath );
		}
		else {
			aStatusPath = aProperty.getStatusPath();
			if ( aStatusPath == null ) {
				aStatusPath = aDefaultStatusPath;
				aProperty.setStatusPath( aStatusPath );
			}
		}
		return aStatusPath;
	}

	/**
	 * Resolves the property from the provided value and the provided property
	 * and sets the property in case the provided value is not null.
	 * 
	 * @param aInstanceId The value to be used when not null.
	 * @param aHost The value to be used when instance ID is null.
	 * @param aProperty The property to be used when the value is null and which
	 *        is to be set when the value is not null.
	 * 
	 * @return The value when not null, else the value of the provided property.
	 */
	protected static String toInstanceId( String aInstanceId, String aHost, InstanceIdProperty aProperty ) {
		if ( aInstanceId != null ) {
			aProperty.setInstanceId( aInstanceId );
		}
		else {
			aInstanceId = aProperty.getInstanceId();
			if ( aInstanceId == null ) {
				try {
					String theInstanceId = EC2MetadataUtils.getInstanceId();
					if ( theInstanceId != null && theInstanceId.length() != 0 ) {
						aInstanceId = theInstanceId;
						aProperty.setInstanceId( aInstanceId );
					}
				}
				catch ( Throwable ignore ) { /* ignore */ }
				if ( aInstanceId == null ) {
					aInstanceId = aHost;
					aProperty.setInstanceId( aInstanceId );
				}
			}
		}
		return aInstanceId;
	}

	/**
	 * Registers the given service at Eureka.
	 * 
	 * @param aServiceStatus The {@link EurekaServiceStatus} to be set.
	 * @throws HttpStatusException Thrown in case a HTTP response was of an
	 *         erroneous status.
	 * @throws OpenException Thrown in case opening or accessing an open line
	 *         (connection, junction, link) caused problems.
	 */
	protected void doRegister( EurekaServiceStatus aServiceStatus ) throws HttpStatusException, OpenException {
		doRegister( aServiceStatus, this, _executorService );
	}

	/**
	 * Registers the given service at Eureka.
	 * 
	 * @param aServiceStatus The {@link EurekaServiceStatus} to be set.
	 * @param aRegistryService The registry service to be used for registering.
	 * @param aExecutorService The {@link ExecutorService} used to create
	 *        threads.
	 * @throws HttpStatusException Thrown in case a HTTP response was of an
	 *         erroneous status.
	 * @throws OpenException Thrown in case opening or accessing an open line
	 *         (connection, junction, link) caused problems.
	 */
	protected static void doRegister( EurekaServiceStatus aServiceStatus, EurekaRegistry aRegistryService, ExecutorService aExecutorService ) throws HttpStatusException, OpenException {
		Url theRegistryUrl = new UrlImpl( aRegistryService.getHttpRegistryUrl(), aRegistryService.getHttpServerDescriptor().getAlias() );
		HttpRestClient theRestClient = new HttpRestClientImpl( aExecutorService );
		theRestClient.open( aRegistryService.getTrustStoreDescriptor() );
		RestRequestBuilder theBuilder = theRestClient.buildPost( theRegistryUrl );
		aRegistryService.getHttpServerDescriptor().put( "instance/status", aServiceStatus != null ? aServiceStatus.name() : EurekaServiceStatus.UNKNOWN.name() );
		theBuilder.setRequest( aRegistryService.getHttpServerDescriptor() );
		theBuilder.getHeaderFields().putContentType( MediaType.APPLICATION_XML );
		LOGGER.info( "Registering status <" + aServiceStatus + "> at <" + aRegistryService.getHttpRegistryUrl().toHttpUrl() + "> Eureka service registry for app-ID <" + aRegistryService.getHttpServerDescriptor().getAlias() + "> with instance-ID <" + aRegistryService.getHttpServerDescriptor().getHost() + "> ..." );
		RestResponse theResponse = theBuilder.toRestResponse();
		if ( theResponse.getHttpStatusCode().isErrorStatus() ) {
			throw theResponse.getHttpStatusCode().toHttpStatusException( "Cannot register service with alias <" + aRegistryService.getHttpServerDescriptor().getAlias() + "> with service registry <" + aRegistryService.getHttpRegistryUrl().toHttpUrl() + "> due to HTTP-Status-Code " + theResponse.getHttpStatusCode() + " <" + theResponse.getHttpStatusCode().getStatusCode() + ">: " + theResponse.getHttpBody() );
		}
	}

	/**
	 * Does a Eureka status update for the given service.
	 * 
	 * @param aServiceStatus The {@link EurekaServiceStatus} to be set.
	 * @throws HttpStatusException Thrown in case a HTTP response was of an
	 *         erroneous status.
	 * @throws OpenException Thrown in case opening or accessing an open line
	 *         (connection, junction, link) caused problems.
	 * @throws UnknownHostException Thrown in case the targeted host is unknown.
	 */
	protected void doStatusUpdate( EurekaServiceStatus aServiceStatus ) throws OpenException, UnknownHostException, HttpStatusException {
		doStatusUpdate( aServiceStatus, this, _executorService );
	}

	/**
	 * Does a Eureka status update for the given service.
	 * 
	 * @param aServiceStatus The {@link EurekaServiceStatus} to be set.
	 * @param aRegistryService The registry service to be used for registering.
	 * @param aExecutorService The {@link ExecutorService} used to create
	 *        threads.
	 * @throws HttpStatusException Thrown in case a HTTP response was of an
	 *         erroneous status.
	 * @throws OpenException Thrown in case opening or accessing an open line
	 *         (connection, junction, link) caused problems.
	 * @throws UnknownHostException Thrown in case the targeted host is unknown.
	 */
	protected static void doStatusUpdate( EurekaServiceStatus aServiceStatus, EurekaRegistry aRegistryService, ExecutorService aExecutorService ) throws OpenException, UnknownHostException, HttpStatusException {
		Url theRegistryUrl = new UrlBuilderImpl( aRegistryService.getHttpRegistryUrl(), aRegistryService.getAlias(), aRegistryService.getInstanceId(), "status" );
		theRegistryUrl.getQueryFields().put( "value", aServiceStatus.name() );
		HttpRestClient theRestClient = new HttpRestClientImpl( aExecutorService );
		theRestClient.open( aRegistryService.getTrustStoreDescriptor() );
		LOGGER.info( "Status update <" + aServiceStatus + "> at <" + theRegistryUrl.toHttpUrl() + "> Eureka service registry for app-ID <" + aRegistryService.getAlias() + "> with instance-ID <" + aRegistryService.getInstanceId() + "> ..." );
		RestResponse theResponse;
		theResponse = theRestClient.doPut( theRegistryUrl );
		if ( theResponse.getHttpStatusCode().isErrorStatus() ) {
			throw theResponse.getHttpStatusCode().toHttpStatusException( "Cannot register service with alias <" + aRegistryService.getAlias() + "> with service registry <" + aRegistryService.getHttpRegistryUrl().toHttpUrl() + "> due to HTTP-Status-Code " + theResponse.getHttpStatusCode() + " <" + theResponse.getHttpStatusCode().getStatusCode() + ">: " + theResponse.getHttpBody() );
		}
	}

	/**
	 * Unregisters the given service at Eureka.
	 * 
	 * @throws HttpStatusException Thrown in case a HTTP response was of an
	 *         erroneous status.t
	 * @throws OpenException Thrown in case opening or accessing an open line
	 *         (connection, junction, link) caused problems.
	 */
	protected void doDeregister() throws OpenException, HttpStatusException {
		doDeregister( this, _executorService );
	}

	/**
	 * Unregisters the given service at Eureka.
	 * 
	 * @param aRegistryService The registry service to be used for registering.
	 * @param aExecutorService The {@link ExecutorService} used to create
	 *        threads.
	 * @throws HttpStatusException Thrown in case a HTTP response was of an
	 *         erroneous status.t
	 * @throws OpenException Thrown in case opening or accessing an open line
	 *         (connection, junction, link) caused problems.
	 */
	protected static void doDeregister( EurekaRegistry aRegistryService, ExecutorService aExecutorService ) throws OpenException, HttpStatusException {
		Url theRegistryUrl = new UrlImpl( aRegistryService.getHttpRegistryUrl(), aRegistryService.getAlias(), aRegistryService.getInstanceId() );
		HttpRestClient theRestClient = new HttpRestClientImpl( aExecutorService );
		theRestClient.open( aRegistryService.getTrustStoreDescriptor() );
		RestResponse theResponse;
		LOGGER.info( "Derigstering at <" + aRegistryService.getHttpRegistryUrl().toHttpUrl() + "> Eureka service registry for app-ID <" + aRegistryService.getAlias() + "> with instance-ID <" + aRegistryService.getInstanceId() + "> ..." );
		theResponse = theRestClient.doDelete( theRegistryUrl );
		if ( theResponse.getHttpStatusCode().isErrorStatus() ) {
			throw theResponse.getHttpStatusCode().toHttpStatusException( "Cannot register service with alias <" + aRegistryService.getAlias() + "> with service registry <" + aRegistryService.getHttpRegistryUrl().toHttpUrl() + "> due to HTTP-Status-Code " + theResponse.getHttpStatusCode() + " <" + theResponse.getHttpStatusCode().getStatusCode() + ">: " + theResponse.getHttpBody() );
		}
	}

	/**
	 * Resolves the property from the provided value and the provided property
	 * and sets the property in case the provided value is not null.
	 * 
	 * @param aRegistryUrl The value to be used when not null.
	 * @param aProperty The property to be used when the value is null and which
	 *        is to be set when the value is not null.
	 * 
	 * @return The value when not null, else the value of the provided property.
	 */
	protected static Url toHttpRegistryUrl( Url aRegistryUrl, HttpRegistryUrlProperty aProperty ) {
		aRegistryUrl = AbstractHttpRegistrySidecar.toHttpRegistryUrl( aRegistryUrl, aProperty );
		if ( aRegistryUrl != null && aRegistryUrl.getPath() == null ) {
			aRegistryUrl = new UrlImpl( aRegistryUrl, EUREKA_BASE_PATH );
			aProperty.setHttpRegistryUrl( aRegistryUrl );
		}
		return aRegistryUrl;
	}

	/**
	 * Resolves the property from the provided value and the provided property
	 * and sets the property in case the provided value is not null.
	 * 
	 * @param aDataCenterType The value to be used when not null.
	 * @param aProperty The property to be used when the value is null and which
	 *        is to be set when the value is not null.
	 * 
	 * @return The value when not null, else the value of the provided property.
	 */
	protected static EurekaDataCenterType toDataCenterType( EurekaDataCenterType aDataCenterType, EurekaDataCenterTypeProperty aProperty ) {
		if ( aDataCenterType != null ) {
			aProperty.setEurekaDataCenterType( aDataCenterType );
		}
		else {
			aDataCenterType = aProperty.getEurekaDataCenterType();
		}
		return aDataCenterType;
	}

	/**
	 * Constructs the Amazon Meta-Data from the Machine's network and AWS
	 * settings.
	 * 
	 * @return The according Amazon Meta-Data.
	 */
	protected static AmazonMetaData toAmazonMetaData() {
		AmazonMetaData theMetaData = null;
		try {
			Region theRegion = Regions.getCurrentRegion();
			if ( theRegion != null ) {
				theMetaData = new AmazonMetaDataImpl();
				theMetaData.setAmiId( EC2MetadataUtils.getAmiId() );
				String theAmiLaunchIndex = EC2MetadataUtils.getAmiLaunchIndex();
				Integer theLaunchIndex = 0;
				if ( theAmiLaunchIndex != null ) {
					theLaunchIndex = Integer.valueOf( theAmiLaunchIndex );
					theMetaData.setAmiLaunchIndex( theLaunchIndex );
				}
				theMetaData.setAmiManifestPath( EC2MetadataUtils.getAmiManifestPath() );
				theMetaData.setAvailabilityZone( EC2MetadataUtils.getAvailabilityZone() );
				theMetaData.setInstanceId( EC2MetadataUtils.getInstanceId() );
				theMetaData.setInstanceType( EC2MetadataUtils.getInstanceType() );
				theMetaData.setLocalHostName( EC2MetadataUtils.getLocalHostName() );
				// Too much information |-->
				List theInterfaces = EC2MetadataUtils.getNetworkInterfaces();
				if ( theInterfaces != null ) {
					List eLocalIPv4s = null;
					List ePublicIPv4s = null;
					String ePublicHostName = null;
					for ( NetworkInterface eInterface : theInterfaces ) {
						if ( eLocalIPv4s == null || eLocalIPv4s.size() == 0 ) {
							eLocalIPv4s = eInterface.getLocalIPv4s();
							if ( eLocalIPv4s != null && eLocalIPv4s.size() != 0 ) {
								theMetaData.setLocalIpv4( eLocalIPv4s.get( 0 ) );
							}
						}
						if ( ePublicHostName == null || ePublicHostName.length() == 0 ) {
							ePublicHostName = eInterface.getPublicHostname();
							if ( ePublicHostName != null && ePublicHostName.length() != 0 ) {
								theMetaData.setPublicHostname( ePublicHostName );
							}
						}
						if ( ePublicIPv4s == null || ePublicIPv4s.size() == 0 ) {
							ePublicIPv4s = eInterface.getPublicIPv4s();
							if ( ePublicIPv4s != null && ePublicIPv4s.size() != 0 ) {
								theMetaData.setPublicIpv4( ePublicIPv4s.get( 0 ) );
							}
						}
					}
				}
				// Too much information <--|
			}
		}
		catch ( Throwable ignore ) { /* ignore */ }
		return theMetaData;
	}

	// /////////////////////////////////////////////////////////////////////////
	// HELPER:
	// /////////////////////////////////////////////////////////////////////////

	// /////////////////////////////////////////////////////////////////////////
	// INNER CLASSES:
	// /////////////////////////////////////////////////////////////////////////

	public static class HeartBeatDaemon extends TimerTask {

		private HttpRestClient _client;
		private EurekaRegistry _registry;

		public HeartBeatDaemon( EurekaRegistry aRegistry, ExecutorService aExecutorService ) {
			_client = new HttpRestClientImpl( aExecutorService ).withTrustStoreDescriptor( aRegistry.getTrustStoreDescriptor() );
			_registry = aRegistry;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void run() {
			if ( _registry.isRunning() ) {
				UrlImpl theUrl = new UrlImpl( _registry.getHttpRegistryUrl(), _registry.getAlias(), _registry.getInstanceId() );
				LOGGER.debug( "Sending heartbeat to <" + theUrl.toHttpUrl() + ">..." );
				try {
					RestResponse theResponse = _client.doPut( theUrl );
					if ( theResponse.getHttpStatusCode().isErrorStatus() ) {
						LOGGER.warn( "Received HTTP status code <" + theResponse.getHttpStatusCode().getStatusCode() + "> (" + theResponse.getHttpStatusCode() + ") send heartbeat to URL <" + theUrl.toHttpUrl() + ">: " + theResponse.getHttpBody() );
					}
				}
				catch ( HttpResponseException e ) {
					LOGGER.warn( "Unable to send heartbeat to URL <" + theUrl.toHttpUrl() + ">: " + e.getMessage(), e );
				}
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy