/* * Copyright (c) 2012, 2013, 2015, 2016 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 { } }