blob: 164a03a435dccc6734d7a73be06270546f5d9c7a [file] [log] [blame]
/*
* Copyright (c) 2012, 2013, 2015 Eike Stepper (Berlin, 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
* Christian W. Damus (CEA LIST) - bug 418454
*/
package org.eclipse.emf.cdo.internal.admin;
import org.eclipse.emf.cdo.admin.CDOAdminClient;
import org.eclipse.emf.cdo.admin.CDOAdminClientRepository;
import org.eclipse.emf.cdo.common.CDOCommonRepository.State;
import org.eclipse.emf.cdo.common.CDOCommonRepository.Type;
import org.eclipse.emf.cdo.common.admin.CDOAdminRepository;
import org.eclipse.emf.cdo.internal.admin.protocol.CDOAdminClientProtocol;
import org.eclipse.emf.cdo.spi.common.admin.AbstractCDOAdmin;
import org.eclipse.net4j.channel.IChannelMultiplexer;
import org.eclipse.net4j.connector.IConnector;
import org.eclipse.net4j.util.concurrent.ExecutorServiceFactory;
import org.eclipse.net4j.util.confirmation.IConfirmationProvider;
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.lifecycle.ILifecycle;
import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.security.CredentialsProviderFactory;
import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
import org.eclipse.spi.net4j.ConnectorFactory;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
/**
* @author Eike Stepper
*/
public class CDOAdminClientImpl extends AbstractCDOAdmin
implements CDOAdminClient, IPasswordCredentialsProvider.Provider, IConfirmationProvider.Provider
{
private static final String URL_SEPARATOR = "://";
private final String url;
private final IManagedContainer container;
private final ExecutorService executorService;
private boolean connected;
private ConnectLock connectLock = new ConnectLock();
private long connectAttempt;
private CDOAdminClientProtocol protocol;
public CDOAdminClientImpl(String url, long timeout, IManagedContainer container)
{
super(timeout);
this.url = url;
this.container = container;
executorService = ExecutorServiceFactory.get(container);
}
public final String getURL()
{
return url;
}
public final IManagedContainer getContainer()
{
return container;
}
public boolean isConnected()
{
return connected;
}
public IConnector getConnector()
{
if (!connected)
{
return null;
}
IChannelMultiplexer multiplexer = protocol.getChannel().getMultiplexer();
if (multiplexer instanceof IConnector)
{
return (IConnector)multiplexer;
}
return null;
}
@Override
public CDOAdminClientRepository[] getRepositories()
{
CDOAdminRepository[] repositories = super.getRepositories();
CDOAdminClientRepository[] result = new CDOAdminClientRepository[repositories.length];
for (int i = 0; i < repositories.length; i++)
{
result[i] = (CDOAdminClientRepository)repositories[i];
}
return result;
}
@Override
public synchronized CDOAdminClientRepository getRepository(String name)
{
return (CDOAdminClientRepository)super.getRepository(name);
}
@Override
public CDOAdminClientRepository createRepository(String name, String type, Map<String, Object> properties)
{
return (CDOAdminClientRepository)super.createRepository(name, type, properties);
}
@Override
public CDOAdminClientRepository waitForRepository(String name)
{
return (CDOAdminClientRepository)super.waitForRepository(name);
}
public void repositoryTypeChanged(String name, Type oldType, Type newType)
{
CDOAdminClientRepositoryImpl repository = (CDOAdminClientRepositoryImpl)getRepository(name);
if (repository != null)
{
repository.typeChanged(oldType, newType);
}
}
public void repositoryStateChanged(String name, State oldState, State newState)
{
CDOAdminClientRepositoryImpl repository = (CDOAdminClientRepositoryImpl)getRepository(name);
if (repository != null)
{
repository.stateChanged(oldState, newState);
}
}
public void repositoryReplicationProgressed(String name, double totalWork, double work)
{
CDOAdminClientRepositoryImpl repository = (CDOAdminClientRepositoryImpl)getRepository(name);
if (repository != null)
{
repository.replicationProgressed(totalWork, work);
}
}
public IPasswordCredentialsProvider getCredentialsProvider()
{
try
{
return (IPasswordCredentialsProvider)container.getElement(CredentialsProviderFactory.PRODUCT_GROUP, "interactive", //$NON-NLS-1$
null);
}
catch (Exception ex)
{
return null;
}
}
public IConfirmationProvider getConfirmationProvider()
{
try
{
return (IConfirmationProvider)container.getElement(IConfirmationProvider.Factory.PRODUCT_GROUP,
IConfirmationProvider.Factory.INTERACTIVE_TYPE, null);
}
catch (Exception ex)
{
return null;
}
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + (url == null ? 0 : url.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof CDOAdminClient))
{
return false;
}
CDOAdminClient other = (CDOAdminClient)obj;
if (url == null)
{
if (other.getURL() != null)
{
return false;
}
}
else if (!url.equals(other.getURL()))
{
return false;
}
return true;
}
@Override
public String toString()
{
return url;
}
@Override
protected boolean doCreateRepository(String name, String type, Map<String, Object> properties)
{
return protocol.createRepository(name, type, properties);
}
@Override
protected boolean doDeleteRepository(String name, String type)
{
return protocol.deleteRepository(name, type);
}
@Override
protected void doActivate() throws Exception
{
super.doActivate();
connect();
}
@Override
protected void doDeactivate() throws Exception
{
setConnected(false);
protocol.close();
protocol = null;
super.doDeactivate();
}
protected void setConnected(final boolean on)
{
connected = on;
if (!on)
{
clear();
}
fireEvent(new ConnectionStateChangedEvent()
{
public CDOAdminClient getSource()
{
return CDOAdminClientImpl.this;
}
public boolean isConnected()
{
return on;
}
@Override
public String toString()
{
return "ConnectionStateChangedEvent[connected=" + on + "]";
}
});
}
protected void connect()
{
if (LifecycleUtil.isActive(executorService))
{
synchronized (connectLock)
{
executorService.submit(new ConnectRunnable());
}
}
}
/**
* @author Eike Stepper
*/
protected class ConnectRunnable implements Runnable
{
public void run()
{
if (!container.isActive())
{
return;
}
try
{
sleep();
int pos = url.indexOf(URL_SEPARATOR);
String type = url.substring(0, pos);
String description = url.substring(pos + URL_SEPARATOR.length());
IConnector connector = (IConnector)container.getElement(ConnectorFactory.PRODUCT_GROUP, type, description);
protocol = new CDOAdminClientProtocol(CDOAdminClientImpl.this);
protocol.open(connector);
protocol.addListener(new LifecycleEventAdapter()
{
@Override
protected void onDeactivated(ILifecycle lifecycle)
{
setConnected(false);
protocol = null;
if (isActive())
{
connect();
}
}
});
Set<CDOAdminClientRepository> repositories = protocol.queryRepositories();
for (CDOAdminClientRepository repository : repositories)
{
addElement(repository);
}
setConnected(true);
}
catch (InterruptedException ex)
{
return;
}
catch (Throwable ex)
{
if (protocol != null)
{
LifecycleUtil.deactivate(protocol.getChannel());
protocol = null;
}
connect();
}
}
private void sleep() throws InterruptedException
{
long now = System.currentTimeMillis();
if (connectAttempt != 0)
{
long passed = now - connectAttempt;
long timeout = getTimeout();
long sleep = Math.max(timeout - passed, timeout);
Thread.sleep(sleep);
}
connectAttempt = now;
}
}
/**
* A separate class for better monitor debugging.
*
* @author Eike Stepper
*/
private static final class ConnectLock
{
}
}