blob: 54396e397c8ba276911de26d52db31b8e49bf106 [file] [log] [blame]
/*
* Copyright (c) 2007-2013, 2015-2017, 2019, 2020 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;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
import org.eclipse.emf.cdo.common.revision.CDORevisionProvider;
import org.eclipse.emf.cdo.internal.server.Repository;
import org.eclipse.emf.cdo.internal.server.ServerCDOView;
import org.eclipse.emf.cdo.internal.server.ServerCDOView.ServerCDOSession;
import org.eclipse.emf.cdo.internal.server.SessionManager;
import org.eclipse.emf.cdo.internal.server.bundle.OM;
import org.eclipse.emf.cdo.internal.server.syncing.FailoverParticipant;
import org.eclipse.emf.cdo.internal.server.syncing.OfflineClone;
import org.eclipse.emf.cdo.internal.server.syncing.RepositorySynchronizer;
import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.emf.cdo.session.CDOSessionConfigurationFactory;
import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
import org.eclipse.emf.cdo.spi.common.revision.ManagedRevisionProvider;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.emf.cdo.spi.server.InternalRepositorySynchronizer;
import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.emf.cdo.spi.server.InternalStore;
import org.eclipse.emf.cdo.spi.server.RepositoryFactory;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.OMPlatform;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* Various static methods that may help with CDO {@link IRepository repositories} and server-side {@link CDOView views}.
*
* @author Eike Stepper
*/
public final class CDOServerUtil
{
private CDOServerUtil()
{
}
/**
* @since 4.2
*/
public static CDOView openView(ISession session, CDOBranchPoint branchPoint, CDORevisionProvider revisionProvider)
{
return new ServerCDOView((InternalSession)session, branchPoint, revisionProvider);
}
/**
* @since 4.2
*/
public static CDOView openView(ISession session, CDOBranchPoint branchPoint)
{
CDORevisionManager revisionManager = session.getManager().getRepository().getRevisionManager();
CDORevisionProvider revisionProvider = new ManagedRevisionProvider(revisionManager, branchPoint);
return openView(session, branchPoint, revisionProvider);
}
/**
* @since 4.2
*/
public static CDOView openView(IView view)
{
ISession session = view.getSession();
CDOBranchPoint branchPoint = CDOBranchUtil.copyBranchPoint(view);
return openView(session, branchPoint, view);
}
/**
* @since 4.2
*/
public static CDOView openView(IStoreAccessor.CommitContext commitContext)
{
ISession session = commitContext.getTransaction().getSession();
CDOBranchPoint branchPoint = commitContext.getBranchPoint();
return openView(session, branchPoint, commitContext);
}
/**
* @since 4.0
* @deprecated As of 4.2 the legacy mode is always enabled, use {@link #openView(ISession, CDOBranchPoint, CDORevisionProvider)}.
*/
@Deprecated
public static CDOView openView(ISession session, CDOBranchPoint branchPoint, boolean legacyModeEnabled, CDORevisionProvider revisionProvider)
{
return openView(session, branchPoint, revisionProvider);
}
/**
* @since 4.0
* @deprecated As of 4.2 the legacy mode is always enabled, use {@link #openView(ISession, CDOBranchPoint)}.
*/
@Deprecated
public static CDOView openView(ISession session, CDOBranchPoint branchPoint, boolean legacyModeEnabled)
{
return openView(session, branchPoint);
}
/**
* @since 4.0
* @deprecated As of 4.2 the legacy mode is always enabled, use {@link #openView(IView)}.
*/
@Deprecated
public static CDOView openView(IView view, boolean legacyModeEnabled)
{
return openView(view);
}
/**
* @since 4.0
* @deprecated As of 4.2 the legacy mode is always enabled, use {@link #openView(IStoreAccessor.CommitContext)}.
*/
@Deprecated
public static CDOView openView(IStoreAccessor.CommitContext commitContext, boolean legacyModeEnabled)
{
return openView(commitContext);
}
/**
* @since 4.13
*/
public static ITransaction getServerTransaction(CDOTransaction transaction)
{
IView serverView = getServerView(transaction);
if (serverView instanceof ITransaction)
{
return (ITransaction)serverView;
}
return null;
}
/**
* @since 4.13
*/
public static IView getServerView(CDOView view)
{
if (view instanceof ServerCDOView)
{
CDORevisionProvider revisionProvider = ((ServerCDOView)view).getRevisionProvider();
if (revisionProvider instanceof IView)
{
return (IView)revisionProvider;
}
}
ISession session = getServerSession(view);
if (session != null)
{
return session.getView(view.getViewID());
}
return null;
}
/**
* @since 4.11
*/
public static ISession getServerSession(CDOView view)
{
if (view instanceof ServerCDOView)
{
return ((ServerCDOView)view).getServerSession();
}
return getServerSession(view.getSession());
}
/**
* @since 4.13
*/
public static ISession getServerSession(CDOSession session)
{
if (session instanceof ServerCDOSession)
{
return ((ServerCDOSession)session).getInternalSession();
}
IRepository repository = getRepository(session);
if (repository != null)
{
return repository.getSessionManager().getSession(session.getSessionID());
}
return null;
}
/**
* @since 3.0
*/
public static ISessionManager createSessionManager()
{
return new SessionManager();
}
public static IRepository createRepository(String name, IStore store, Map<String, String> props)
{
Repository repository = new Repository.Default();
initRepository(repository, name, store, props);
return repository;
}
/**
* @since 3.0
*/
public static IRepositorySynchronizer createRepositorySynchronizer(CDOSessionConfigurationFactory remoteSessionConfigurationFactory)
{
RepositorySynchronizer synchronizer = new RepositorySynchronizer();
synchronizer.setRemoteSessionConfigurationFactory(remoteSessionConfigurationFactory);
return synchronizer;
}
/**
* @since 3.0
*/
public static ISynchronizableRepository createOfflineClone(String name, IStore store, Map<String, String> props, IRepositorySynchronizer synchronizer)
{
OfflineClone repository = new OfflineClone();
initRepository(repository, name, store, props);
repository.setSynchronizer((InternalRepositorySynchronizer)synchronizer);
return repository;
}
/**
* @since 4.0
*/
public static ISynchronizableRepository createFailoverParticipant(String name, IStore store, Map<String, String> props, IRepositorySynchronizer synchronizer,
boolean master, boolean allowBackupCommits)
{
FailoverParticipant repository = new FailoverParticipant();
initRepository(repository, name, store, props);
if (synchronizer != null)
{
repository.setSynchronizer((InternalRepositorySynchronizer)synchronizer);
repository.setType(master ? CDOCommonRepository.Type.MASTER : CDOCommonRepository.Type.BACKUP);
}
return repository;
}
/**
* @since 3.0
*/
public static ISynchronizableRepository createFailoverParticipant(String name, IStore store, Map<String, String> props, IRepositorySynchronizer synchronizer,
boolean master)
{
return createFailoverParticipant(name, store, props, synchronizer, master, false);
}
/**
* @since 4.0
*/
public static ISynchronizableRepository createFailoverParticipant(String name, IStore store, Map<String, String> props, IRepositorySynchronizer synchronizer)
{
return createFailoverParticipant(name, store, props, synchronizer, false);
}
/**
* @since 4.0
*/
public static ISynchronizableRepository createFailoverParticipant(String name, IStore store, Map<String, String> props)
{
return createFailoverParticipant(name, store, props, null);
}
private static void initRepository(Repository repository, String name, IStore store, Map<String, String> props)
{
repository.setName(name);
repository.setStore((InternalStore)store);
repository.setProperties(props);
}
public static void addRepository(IManagedContainer container, IRepository repository)
{
InternalRepository internal = (InternalRepository)repository;
if (internal.getContainer() == null && container != IPluginContainer.INSTANCE)
{
internal.setContainer(container);
}
String productGroup = RepositoryFactory.PRODUCT_GROUP;
String type = RepositoryFactory.TYPE;
String name = repository.getName();
container.putElement(productGroup, type, name, repository);
LifecycleUtil.activate(repository);
}
public static IRepository getRepository(IManagedContainer container, String name)
{
return RepositoryFactory.get(container, name);
}
/**
* @since 4.13
*/
public static IRepository getRepository(String uuid)
{
return Repository.get(uuid);
}
/**
* @since 4.13
*/
public static IRepository getRepository(CDOSession session)
{
String uuid = session.getRepositoryInfo().getUUID();
return getRepository(uuid);
}
public static Element getRepositoryConfig(String repositoryName) throws ParserConfigurationException, SAXException, IOException
{
File configFile = OMPlatform.INSTANCE.getConfigFile("cdo-server.xml"); //$NON-NLS-1$
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(configFile);
NodeList elements = document.getElementsByTagName("repository"); //$NON-NLS-1$
for (int i = 0; i < elements.getLength(); i++)
{
Node node = elements.item(i);
if (node instanceof Element)
{
Element element = (Element)node;
String name = element.getAttribute("name"); //$NON-NLS-1$
if (ObjectUtil.equals(name, repositoryName))
{
return element;
}
}
}
throw new IllegalStateException("Repository config not found: " + repositoryName); //$NON-NLS-1$
}
/**
* @since 4.13
*/
public static void run(ISession context, Runnable runnable)
{
StoreThreadLocal.wrap(context, runnable).run();
}
/**
* @since 4.13
*/
public static void run(CDOSession context, Runnable runnable)
{
ISession serverSession = getServerSession(context);
run(serverSession, runnable);
}
/**
* @since 4.13
*/
public static <T> T call(ISession context, Callable<T> callable) throws Exception
{
return StoreThreadLocal.wrap(context, callable).call();
}
/**
* @since 4.13
*/
public static <T> T call(CDOSession context, Callable<T> callable) throws Exception
{
ISession serverSession = getServerSession(context);
return call(serverSession, callable);
}
/**
* An abstract {@link IRepository.ReadAccessHandler read-access handler} that grants or denies access to single
* {@link CDORevision revisions}.
*
* @author Eike Stepper
* @since 2.0
*/
public static abstract class RepositoryReadAccessValidator implements IRepository.ReadAccessHandler
{
public RepositoryReadAccessValidator()
{
}
@Override
public void handleRevisionsBeforeSending(ISession session, CDORevision[] revisions, List<CDORevision> additionalRevisions) throws RuntimeException
{
List<String> violations = new ArrayList<>();
for (CDORevision revision : revisions)
{
String violation = validate(session, revision);
if (violation != null)
{
violations.add(violation);
}
}
if (!violations.isEmpty())
{
throwException(session, violations);
}
for (Iterator<CDORevision> it = additionalRevisions.iterator(); it.hasNext();)
{
CDORevision revision = it.next();
String violation = validate(session, revision);
if (violation != null)
{
OM.LOG.info("Revision can not be delivered to " + session + ": " + violation); //$NON-NLS-1$ //$NON-NLS-2$
it.remove();
}
}
}
protected void throwException(ISession session, List<String> violations) throws RuntimeException
{
StringBuilder builder = new StringBuilder();
builder.append("Revisions can not be delivered to "); //$NON-NLS-1$
builder.append(session);
builder.append(":"); //$NON-NLS-1$
for (String violation : violations)
{
builder.append("\n- "); //$NON-NLS-1$
builder.append(violation);
}
throwException(builder.toString());
}
protected void throwException(String message) throws RuntimeException
{
throw new IllegalStateException(message);
}
protected abstract String validate(ISession session, CDORevision revision);
}
}