blob: 8125a4f56a86eb5d8662c3d5526baca1dd8893f6 [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
*/
package org.eclipse.emf.cdo.examples.client.offline.nodes;
import org.eclipse.emf.cdo.common.CDOCommonRepository.State;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.revision.CDORevisionCache;
import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
import org.eclipse.emf.cdo.examples.client.offline.Application;
import org.eclipse.emf.cdo.examples.company.CompanyPackage;
import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration;
import org.eclipse.emf.cdo.net4j.CDONet4jUtil;
import org.eclipse.emf.cdo.server.CDOServerBrowser;
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.IStore;
import org.eclipse.emf.cdo.server.ISynchronizableRepository;
import org.eclipse.emf.cdo.server.db.CDODBUtil;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.net4j.FailoverAgent;
import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.emf.cdo.session.CDOSessionConfigurationFactory;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.view.CDOAdapterPolicy;
import org.eclipse.emf.cdo.view.CDOViewTargetChangedEvent;
import org.eclipse.net4j.Net4jUtil;
import org.eclipse.net4j.acceptor.IAcceptor;
import org.eclipse.net4j.connector.IConnector;
import org.eclipse.net4j.db.IDBAdapter;
import org.eclipse.net4j.db.IDBConnectionProvider;
import org.eclipse.net4j.db.h2.H2Adapter;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.container.SetContainer;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.event.ThrowableEventAdapter;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.wb.swt.ExampleResourceManager;
import org.h2.jdbcx.JdbcDataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* @author Eike Stepper
*/
public abstract class NodeType extends SetContainer<Node>implements IElement
{
public static final String TYPE_PROPERTY = "Type";
public static final String NAME_PROPERTY = "Name";
public static final String PORT_PROPERTY = "Port";
public static final String SERVER_PROPERTY = "Server";
public static final String MONITOR_PROPERTY = "Monitor";
public static final String BRANCH_PROPERTY = "Branch";
public static final String BROWSER_PROPERTY = "BrowserPort";
private static final String REPOSITORY_NAME = "repository";
private final NodeManager manager;
private final List<Property> properties = new ArrayList<Property>();
private final Properties settings = new Properties();
private final Composite[] detailsControls = { null, null };
public NodeType(NodeManager manager)
{
super(Node.class);
this.manager = manager;
addProperty(new Property.Entry(this, NAME_PROPERTY));
settings.setProperty(TYPE_PROPERTY, getTypeName());
activate();
}
public NodeManager getManager()
{
return manager;
}
public List<Property> getProperties()
{
return properties;
}
public Properties getSettings()
{
return settings;
}
public void showSettings()
{
showSettings(null);
}
public void showSettings(Node node)
{
Composite composite = getDetailsControl(node);
Control[] children = composite.getChildren();
Properties settings = node == null ? this.settings : node.getSettings();
for (Property property : properties)
{
String name = property.getName();
Control control = getControl(children, name);
if (control != null)
{
String value = settings.getProperty(name, "");
property.showSetting(control, value);
}
}
}
public void configureWindow(IWorkbenchWindowConfigurer configurer)
{
configurer.setInitialSize(new Point(800, 500));
configurer.setTitle(Application.NODE.getName());
configurer.setShowCoolBar(false);
configurer.setShowMenuBar(false);
configurer.setShowStatusLine(false);
}
private Control getControl(Control[] children, String name)
{
for (Control control : children)
{
if (name.equals(control.getData("name")))
{
return control;
}
}
return null;
}
public Image getImage()
{
return ExampleResourceManager.getPluginImage(Application.PLUGIN_ID, "icons/Folder.gif");
}
public Image getInstanceImage()
{
return ExampleResourceManager.getPluginImage(Application.PLUGIN_ID, "icons/" + getTypeName() + ".gif");
}
public String getTypeName()
{
String name = getClass().getSimpleName();
int lastDot = name.lastIndexOf('.');
if (lastDot != -1)
{
name = name.substring(lastDot + 1);
}
return name;
}
public Composite getDetailsControl()
{
return getDetailsControl(null);
}
public Composite getDetailsControl(Node node)
{
if (node == null)
{
return detailsControls[0];
}
return detailsControls[1];
}
public void start(Node node)
{
IRepository repository = createRepository(node);
node.setObject(IRepository.class, repository);
IAcceptor acceptor = createAcceptor(node);
node.setObject(IAcceptor.class, acceptor);
String browserPort = node.getSetting(BROWSER_PROPERTY);
if (browserPort != null && browserPort.length() != 0)
{
CDOServerBrowser browser = (CDOServerBrowser)IPluginContainer.INSTANCE
.getElement("org.eclipse.emf.cdo.server.browsers", "default", browserPort);
node.setObject(CDOServerBrowser.class, browser);
}
}
public void stop(Node node)
{
CDOServerBrowser browser = node.getObject(CDOServerBrowser.class);
LifecycleUtil.deactivate(browser);
IAcceptor acceptor = node.getObject(IAcceptor.class);
LifecycleUtil.deactivate(acceptor);
IRepository repository = node.getObject(IRepository.class);
LifecycleUtil.deactivate(repository);
}
public Button createUI(final NodeManagerDialog dialog, int kind)
{
Composite composite = new Composite(dialog.getDetails(), SWT.NONE);
composite.setLayout(new GridLayout(2, false));
for (Property property : properties)
{
property.createField(dialog, composite);
}
new Label(composite, SWT.NONE);
Button button = new Button(composite, SWT.PUSH);
button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
if (kind == NodeManagerDialog.NODE)
{
button.setText("Delete");
button.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
dialog.onDelete(NodeType.this);
}
});
composite.setEnabled(false);
detailsControls[1] = composite;
}
else
{
button.setText("Create");
button.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
dialog.onCreate(NodeType.this);
}
});
detailsControls[0] = composite;
}
return button;
}
protected void addProperty(Property property)
{
properties.add(property);
}
@Override
protected Node[] sortElements(Node[] array)
{
Arrays.sort(array);
return array;
}
protected IRepository createRepository(Node node)
{
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL("jdbc:h2:" + node.getFolder() + "/db/repository");
IMappingStrategy mappingStrategy = CDODBUtil.createHorizontalMappingStrategy(true, true);
IDBAdapter dbAdapter = new H2Adapter();
IDBConnectionProvider dbConnectionProvider = dbAdapter.createConnectionProvider(dataSource);
IStore store = CDODBUtil.createStore(mappingStrategy, dbAdapter, dbConnectionProvider);
Map<String, String> props = new HashMap<String, String>();
props.put(IRepository.Props.OVERRIDE_UUID, REPOSITORY_NAME);
props.put(IRepository.Props.SUPPORTING_AUDITS, "true");
props.put(IRepository.Props.SUPPORTING_BRANCHES, "true");
props.put(IRepository.Props.ID_GENERATION_LOCATION, "CLIENT");
IRepository repository = createRepository(node, store, props);
repository.setInitialPackages(CompanyPackage.eINSTANCE);
activateRepository(repository);
return repository;
}
protected IRepository createRepository(Node node, IStore store, Map<String, String> props)
{
return CDOServerUtil.createRepository(REPOSITORY_NAME, store, props);
}
protected void activateRepository(IRepository repository)
{
// Don't do this with failover participants!
CDOServerUtil.addRepository(IPluginContainer.INSTANCE, repository);
}
protected IAcceptor createAcceptor(Node node)
{
String description = "0.0.0.0:" + node.getSetting(PORT_PROPERTY);
return (IAcceptor)IPluginContainer.INSTANCE.getElement("org.eclipse.net4j.acceptors", "tcp", description);
}
/**
* @author Eike Stepper
*/
public static abstract class Property
{
private final NodeType container;
private final String name;
public Property(NodeType container, String name)
{
this.container = container;
this.name = name;
}
public NodeType getContainer()
{
return container;
}
public String getName()
{
return name;
}
public abstract void createField(NodeManagerDialog dialog, Composite parent);
public abstract void showSetting(Control control, String value);
/**
* @author Eike Stepper
*/
public static abstract class Labelled extends Property
{
public Labelled(NodeType container, String name)
{
super(container, name);
}
@Override
public void createField(NodeManagerDialog dialog, Composite parent)
{
String name = getName();
Label label = new Label(parent, SWT.NONE);
label.setText(name + ":");
label.setLayoutData(new GridData(GridData.END));
Control control = createControl(dialog, parent);
control.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
control.setData("name", name);
}
protected abstract Control createControl(NodeManagerDialog dialog, Composite parent);
}
/**
* @author Eike Stepper
*/
public static class Entry extends Labelled
{
public Entry(NodeType container, String name)
{
super(container, name);
}
@Override
protected Control createControl(final NodeManagerDialog dialog, Composite parent)
{
final Text text = new Text(parent, SWT.BORDER);
text.addModifyListener(new ModifyListener()
{
public void modifyText(ModifyEvent e)
{
if (!dialog.isUpdatingDetails())
{
dialog.onModify(Entry.this, text.getText());
}
}
});
return text;
}
@Override
public void showSetting(Control control, String value)
{
((Text)control).setText(value);
}
}
/**
* @author Eike Stepper
*/
public static class Selection extends Labelled
{
private final Class<? extends NodeType> type;
public Selection(NodeType container, String name, Class<? extends NodeType> type)
{
super(container, name);
this.type = type;
}
public Class<? extends NodeType> getType()
{
return type;
}
@Override
protected Control createControl(final NodeManagerDialog dialog, Composite parent)
{
final ComboViewer comboViewer = new ComboViewer(parent, SWT.NONE);
comboViewer.setLabelProvider(new LabelProvider());
comboViewer.setContentProvider(new IStructuredContentProvider()
{
public Object[] getElements(Object inputElement)
{
List<Node> result = new ArrayList<Node>();
Node[] nodes = getContainer().getManager().getNodes();
for (Node node : nodes)
{
if (type.isAssignableFrom(node.getType().getClass()))
{
result.add(node);
}
}
Collections.sort(result);
return result.toArray(new Node[result.size()]);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
}
public void dispose()
{
}
});
comboViewer.addSelectionChangedListener(new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
if (!dialog.isUpdatingDetails())
{
IStructuredSelection selection = (IStructuredSelection)comboViewer.getSelection();
Node node = (Node)selection.getFirstElement();
if (node != null)
{
dialog.onModify(Selection.this, node.getName());
}
}
}
});
comboViewer.setInput(new Object());
Combo combo = comboViewer.getCombo();
combo.setData("viewer", comboViewer);
return combo;
}
@Override
public void showSetting(Control control, String value)
{
ComboViewer comboViewer = (ComboViewer)control.getData("viewer");
comboViewer.refresh(true);
Node node = getContainer().getManager().getNode(value);
if (node != null)
{
comboViewer.setSelection(new StructuredSelection(node));
}
else
{
comboViewer.setSelection(StructuredSelection.EMPTY);
}
}
}
}
/**
* @author Eike Stepper
*/
public static class Client extends NodeType
{
public Client(NodeManager manager)
{
super(manager);
addProperty(new Property.Selection(this, SERVER_PROPERTY, Server.class));
addProperty(new Property.Entry(this, BROWSER_PROPERTY));
}
@Override
public void start(final Node node)
{
super.start(node);
final CDOSession session = (CDOSession)IPluginContainer.INSTANCE.getElement("org.eclipse.emf.cdo.sessions", "cdo",
"jvm://example?repositoryName=" + REPOSITORY_NAME);
session.getPackageRegistry().putEPackage(CompanyPackage.eINSTANCE);
node.setObject(CDOSession.class, session);
if (session.getRepositoryInfo().getState() == State.INITIAL)
{
session.addListener(new IListener()
{
public void notifyEvent(IEvent event)
{
if (session.getRepositoryInfo().getState() != State.INITIAL)
{
session.removeListener(this);
createTransaction(node);
}
}
});
}
else
{
createTransaction(node);
}
}
@Override
public void stop(Node node)
{
CDOSession session = node.getObject(CDOSession.class);
LifecycleUtil.deactivate(session);
super.stop(node);
}
@Override
protected IRepository createRepository(Node node, IStore store, Map<String, String> props)
{
String serverName = node.getSetting(SERVER_PROPERTY);
final Node serverNode = getManager().getNode(serverName);
if (serverNode == null)
{
throw new IllegalStateException("Server not found: " + serverName);
}
CDOSessionConfigurationFactory factory = new CDOSessionConfigurationFactory()
{
public CDONet4jSessionConfiguration createSessionConfiguration()
{
String serverAddress = "localhost:" + serverNode.getSetting(PORT_PROPERTY);
CDONet4jSessionConfiguration configuration;
if (serverNode.getType() instanceof FailoverMonitor)
{
configuration = CDONet4jUtil.createFailoverSessionConfiguration(serverAddress, serverNode.getName());
}
else
{
IConnector connector = Net4jUtil.getConnector(IPluginContainer.INSTANCE, "tcp", serverAddress);
configuration = CDONet4jUtil.createNet4jSessionConfiguration();
configuration.setConnector(connector);
configuration.setRepositoryName(REPOSITORY_NAME);
}
configuration.setRevisionManager(CDORevisionUtil.createRevisionManager(CDORevisionCache.NOOP));
return configuration;
}
};
IRepositorySynchronizer synchronizer = CDOServerUtil.createRepositorySynchronizer(factory);
synchronizer.setRetryInterval(2);
synchronizer.setMaxRecommits(10);
synchronizer.setRecommitInterval(2);
return CDOServerUtil.createOfflineClone(REPOSITORY_NAME, store, props, synchronizer);
}
@Override
protected IAcceptor createAcceptor(Node node)
{
return (IAcceptor)IPluginContainer.INSTANCE.getElement("org.eclipse.net4j.acceptors", "jvm", "example");
}
protected void createTransaction(final Node node)
{
CDOSession session = node.getObject(CDOSession.class);
String branchPath = node.getSettings().getProperty(BRANCH_PROPERTY, CDOBranch.MAIN_BRANCH_NAME);
CDOBranch branch = session.getBranchManager().getBranch(branchPath);
if (branch == null)
{
branch = session.getBranchManager().getMainBranch();
node.getSettings().setProperty(BRANCH_PROPERTY, branch.getPathName());
getManager().saveNode(node);
}
CDOTransaction transaction = session.openTransaction(branch);
transaction.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
transaction.addListener(new IListener()
{
public void notifyEvent(IEvent event)
{
if (event instanceof CDOViewTargetChangedEvent)
{
CDOViewTargetChangedEvent e = (CDOViewTargetChangedEvent)event;
String branchPath = e.getBranchPoint().getBranch().getPathName();
node.getSettings().setProperty(BRANCH_PROPERTY, branchPath);
getManager().saveNode(node);
}
}
});
node.setObject(CDOTransaction.class, transaction);
}
@Override
public String toString()
{
return "Clients";
}
}
/**
* @author Eike Stepper
*/
public static abstract class Server extends NodeType
{
public Server(NodeManager manager)
{
super(manager);
addProperty(new Property.Entry(this, PORT_PROPERTY));
}
@Override
public void configureWindow(IWorkbenchWindowConfigurer configurer)
{
super.configureWindow(configurer);
configurer.setInitialSize(new Point(500, 350));
}
public void setConnectedToNetwork(Node node, boolean on)
{
if (on)
{
IAcceptor acceptor = createAcceptor(node);
node.setObject(IAcceptor.class, acceptor);
}
else
{
IAcceptor acceptor = node.getObject(IAcceptor.class);
LifecycleUtil.deactivate(acceptor);
}
}
}
/**
* @author Eike Stepper
*/
public static abstract class Repository extends Server
{
public Repository(NodeManager manager)
{
super(manager);
}
@Override
public String toString()
{
return "Normal Repositories";
}
}
/**
* @author Eike Stepper
*/
public static class NormalRepository extends Repository
{
public NormalRepository(NodeManager manager)
{
super(manager);
addProperty(new Property.Entry(this, BROWSER_PROPERTY));
}
@Override
public String toString()
{
return "Normal Repositories";
}
}
/**
* @author Eike Stepper
*/
public static class FailoverRepository extends Repository
{
private FailoverAgent agent;
public FailoverRepository(NodeManager manager)
{
super(manager);
addProperty(new Property.Selection(this, MONITOR_PROPERTY, FailoverMonitor.class));
addProperty(new Property.Entry(this, BROWSER_PROPERTY));
}
@Override
protected IRepository createRepository(Node node, IStore store, Map<String, String> props)
{
String monitorName = node.getSetting(MONITOR_PROPERTY);
Node monitorNode = getManager().getNode(monitorName);
if (monitorNode == null)
{
throw new IllegalStateException("Monitor not found: " + monitorName);
}
final String monitorAddress = "localhost:" + monitorNode.getSetting(PORT_PROPERTY);
ISynchronizableRepository repository = CDOServerUtil.createFailoverParticipant(REPOSITORY_NAME, store, props);
agent = new FailoverAgent()
{
@Override
protected IRepositorySynchronizer createRepositorySynchronizer()
{
IRepositorySynchronizer synchronizer = super.createRepositorySynchronizer();
synchronizer.addListener(ThrowableEventAdapter.ToPrintStream.CONSOLE);
return synchronizer;
}
@Override
protected CDONet4jSessionConfiguration createSessionConfiguration(String connectorDescription,
String repositoryName)
{
IConnector connector = Net4jUtil.getConnector(IPluginContainer.INSTANCE, "tcp", connectorDescription);
CDONet4jSessionConfiguration configuration = CDONet4jUtil.createNet4jSessionConfiguration();
configuration.setConnector(connector);
configuration.setRepositoryName(repositoryName);
configuration.setRevisionManager(CDORevisionUtil.createRevisionManager(CDORevisionCache.NOOP));
return configuration;
}
};
agent.setMonitorConnector(Net4jUtil.getConnector(IPluginContainer.INSTANCE, "tcp", monitorAddress));
agent.setConnectorDescription("localhost:" + node.getSetting(PORT_PROPERTY));
agent.setRepository(repository);
agent.setGroup(monitorNode.getName());
agent.setRate(1500L);
agent.setTimeout(3000L);
return repository;
}
@Override
protected void activateRepository(IRepository repository)
{
agent.activate();
}
@Override
public String toString()
{
return "Failover Repositories";
}
}
/**
* @author Eike Stepper
*/
public static class FailoverMonitor extends Server
{
public FailoverMonitor(NodeManager manager)
{
super(manager);
}
@Override
public void start(Node node)
{
super.start(node);
org.eclipse.emf.cdo.server.net4j.FailoverMonitor monitor = (org.eclipse.emf.cdo.server.net4j.FailoverMonitor)IPluginContainer.INSTANCE
.getElement(org.eclipse.emf.cdo.server.net4j.FailoverMonitor.PRODUCT_GROUP,
org.eclipse.emf.cdo.server.net4j.FailoverMonitor.Factory.TYPE, node.getName());
node.setObject(org.eclipse.emf.cdo.server.net4j.FailoverMonitor.class, monitor);
}
@Override
public void stop(Node node)
{
org.eclipse.emf.cdo.server.net4j.FailoverMonitor monitor = node
.getObject(org.eclipse.emf.cdo.server.net4j.FailoverMonitor.class);
LifecycleUtil.deactivate(monitor);
super.stop(node);
}
@Override
protected IRepository createRepository(Node node)
{
return null;
}
@Override
public String toString()
{
return "Failover Monitors";
}
}
}