blob: d9a08e2a393295fc4d98ee7e8885b55fa97c60fa [file] [log] [blame]
/*
* Copyright (c) 2010-2012, 2016, 2019 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.server.net4j;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.server.CDOServerUtil;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.IRepositorySynchronizer;
import org.eclipse.emf.cdo.server.ISynchronizableRepository;
import org.eclipse.emf.cdo.session.CDOSessionConfiguration;
import org.eclipse.emf.cdo.session.CDOSessionConfigurationFactory;
import org.eclipse.emf.cdo.spi.server.InternalFailoverParticipant;
import org.eclipse.emf.cdo.spi.server.InternalRepositorySynchronizer;
import org.eclipse.net4j.connector.IConnector;
import org.eclipse.net4j.signal.Indication;
import org.eclipse.net4j.signal.SignalReactor;
import org.eclipse.net4j.signal.heartbeat.HeartBeatProtocol;
import org.eclipse.net4j.util.concurrent.TimerLifecycle;
import org.eclipse.net4j.util.concurrent.TimerLifecycle.DaemonFactory;
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.container.IManagedContainerProvider;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.io.ExtendedDataInputStream;
import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
import org.eclipse.net4j.util.lifecycle.Lifecycle;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import java.io.IOException;
import java.util.Timer;
/**
* A repository-side agent for a {@link FailoverMonitor fail-over monitor}.
*
* @author Eike Stepper
* @since 4.0
*/
public abstract class FailoverAgent extends Lifecycle implements CDOSessionConfigurationFactory, IManagedContainerProvider
{
private IConnector monitorConnector;
private Timer timer;
private long rate;
private long timeout;
private String group;
private String connectorDescription;
private InternalFailoverParticipant repository;
private long repositoryActivationTimeout = 10000L;
private Protocol protocol;
private String masterConnectorDescription;
private String masterRepositoryName;
private InternalRepositorySynchronizer synchronizer;
public FailoverAgent()
{
}
/**
* @since 4.1
*/
@Override
public IManagedContainer getContainer()
{
return IPluginContainer.INSTANCE;
}
public IConnector getMonitorConnector()
{
return monitorConnector;
}
public void setMonitorConnector(IConnector connector)
{
checkInactive();
monitorConnector = connector;
}
public Timer getTimer()
{
return timer;
}
public void setTimer(Timer timer)
{
checkInactive();
this.timer = timer;
}
public long getRate()
{
return rate;
}
public void setRate(long rate)
{
checkInactive();
this.rate = rate;
}
public long getTimeout()
{
return timeout;
}
public void setTimeout(long timeout)
{
checkInactive();
this.timeout = timeout;
}
public String getGroup()
{
return group;
}
public void setGroup(String group)
{
checkInactive();
this.group = group;
}
public String getConnectorDescription()
{
return connectorDescription;
}
public void setConnectorDescription(String connectorDescription)
{
checkInactive();
this.connectorDescription = connectorDescription;
}
public ISynchronizableRepository getRepository()
{
return repository;
}
public void setRepository(ISynchronizableRepository repository)
{
checkInactive();
if (!(repository instanceof InternalFailoverParticipant))
{
throw new IllegalArgumentException("Not a failover participant: " + repository);
}
if (repository.getSynchronizer() != null)
{
throw new IllegalArgumentException("Synchronizer must be null: " + repository);
}
this.repository = (InternalFailoverParticipant)repository;
}
/**
* @since 4.1
*/
public long getRepositoryActivationTimeout()
{
return repositoryActivationTimeout;
}
/**
* @since 4.1
*/
public void setRepositoryActivationTimeout(long repositoryActivationTimeout)
{
checkInactive();
this.repositoryActivationTimeout = repositoryActivationTimeout;
}
public Protocol getProtocol()
{
return protocol;
}
@Override
public CDOSessionConfiguration createSessionConfiguration()
{
return createSessionConfiguration(masterConnectorDescription, masterRepositoryName);
}
@Override
protected void doBeforeActivate() throws Exception
{
super.doBeforeActivate();
checkState(monitorConnector, "monitorConnector");
checkState(group, "group");
checkState(connectorDescription, "connectorDescription");
checkState(repository, "repository");
}
@Override
protected void doActivate() throws Exception
{
super.doActivate();
IManagedContainer container = getContainer();
if (timer == null)
{
timer = (Timer)container.getElement(TimerLifecycle.PRODUCT_GROUP, DaemonFactory.TYPE, null);
}
synchronizer = (InternalRepositorySynchronizer)createRepositorySynchronizer();
repository.setSynchronizer(synchronizer);
// setMaster(); // Will be adjusted with the following SIGNAL_PUBLISH_MASTER
protocol = new Protocol(this);
protocol.start(rate, timeout);
// Repository will be activated asynchronously by the agent protocol, so wait
if (!LifecycleUtil.waitForActive(repository, repositoryActivationTimeout))
{
LifecycleUtil.checkActive(repository);
}
}
@Override
protected void doDeactivate() throws Exception
{
protocol.close();
protocol = null;
timer = null;
monitorConnector = null;
super.doDeactivate();
}
protected void setMaster()
{
repository.setType(CDOCommonRepository.Type.MASTER);
masterConnectorDescription = null;
masterRepositoryName = null;
}
protected void setBackup(String connectorDescription, String repositoryName)
{
masterConnectorDescription = connectorDescription;
masterRepositoryName = repositoryName;
repository.setType(CDOCommonRepository.Type.BACKUP);
}
/**
* @since 4.1
*/
protected IRepositorySynchronizer createRepositorySynchronizer()
{
return CDOServerUtil.createRepositorySynchronizer(this);
}
protected abstract CDOSessionConfiguration createSessionConfiguration(String connectorDescription, String repositoryName);
/**
* The agent-side implementation of the {@link FailoverMonitor fail-over monitor} protocol.
*
* @author Eike Stepper
*/
public static class Protocol extends HeartBeatProtocol
{
private FailoverAgent agent;
public Protocol(FailoverAgent agent)
{
super(FailoverMonitor.PROTOCOL_NAME, agent.getMonitorConnector(), agent.getTimer());
this.agent = agent;
}
public FailoverAgent getAgent()
{
return agent;
}
@Override
protected void requestingStart(ExtendedDataOutputStream out, long rate) throws IOException
{
out.writeString(agent.getGroup());
out.writeString(agent.getConnectorDescription());
out.writeString(agent.getRepository().getName());
super.requestingStart(out, rate);
}
@Override
protected SignalReactor createSignalReactor(short signalID)
{
switch (signalID)
{
case FailoverMonitor.SIGNAL_PUBLISH_MASTER:
return new Indication(this, FailoverMonitor.SIGNAL_PUBLISH_MASTER)
{
@Override
protected void indicating(ExtendedDataInputStream in) throws Exception
{
boolean master = in.readBoolean();
if (master)
{
agent.setMaster();
}
else
{
String connectorDescription = in.readString();
String repositoryName = in.readString();
agent.setBackup(connectorDescription, repositoryName);
}
IRepository repository = agent.getRepository();
if (!repository.isActive())
{
IManagedContainer container = agent.getContainer();
CDOServerUtil.addRepository(container, repository);
}
}
};
default:
return super.createSignalReactor(signalID);
}
}
}
}