blob: dddedc3755b6731a8c111e598102ba4489eac83f [file] [log] [blame]
/**
* Copyright (c) 2004 - 2010 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:
* Simon McDuff - initial API and implementation
* Simon McDuff - http://bugs.eclipse.org/233273
* Eike Stepper - maintenance
*/
package org.eclipse.emf.cdo.internal.server.mem;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.model.CDOModelConstants;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.server.IMEMStore;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.ITransaction;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.server.StoreThreadLocal;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.server.LongIDStore;
import org.eclipse.emf.cdo.spi.server.StoreAccessorPool;
import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.emf.ecore.EStructuralFeature;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @author Simon McDuff
*/
public class MEMStore extends LongIDStore implements IMEMStore
{
public static final String TYPE = "mem"; //$NON-NLS-1$
private long creationTime;
private Map<CDOID, List<InternalCDORevision>> revisions = new HashMap<CDOID, List<InternalCDORevision>>();
private int listLimit;
/**
* @param listLimit
* See {@link #setListLimit(int)}.
* @since 2.0
*/
public MEMStore(int listLimit)
{
super(TYPE, set(ChangeFormat.REVISION, ChangeFormat.DELTA), set(RevisionTemporality.NONE,
RevisionTemporality.AUDITING), set(RevisionParallelism.NONE));
setRevisionTemporality(RevisionTemporality.AUDITING);
this.listLimit = listLimit;
}
public MEMStore()
{
this(UNLIMITED);
}
/**
* @since 2.0
*/
public int getListLimit()
{
return listLimit;
}
/**
* @since 2.0
*/
public synchronized void setListLimit(int listLimit)
{
if (listLimit != UNLIMITED && this.listLimit != listLimit)
{
for (List<InternalCDORevision> list : revisions.values())
{
enforceListLimit(list);
}
}
this.listLimit = listLimit;
}
/**
* @since 2.0
*/
public synchronized List<InternalCDORevision> getCurrentRevisions()
{
ArrayList<InternalCDORevision> simpleRevisions = new ArrayList<InternalCDORevision>();
Iterator<List<InternalCDORevision>> itr = revisions.values().iterator();
while (itr.hasNext())
{
List<InternalCDORevision> list = itr.next();
InternalCDORevision revision = list.get(list.size() - 1);
simpleRevisions.add(revision);
}
return simpleRevisions;
}
public synchronized InternalCDORevision getRevision(CDOID id)
{
List<InternalCDORevision> list = revisions.get(id);
if (list != null)
{
return list.get(list.size() - 1);
}
return null;
}
public synchronized InternalCDORevision getRevisionByVersion(CDOID id, int version)
{
if (getRepository().isSupportingAudits())
{
List<InternalCDORevision> list = revisions.get(id);
if (list != null)
{
return getRevisionByVersion(list, version);
}
return null;
}
throw new UnsupportedOperationException();
}
/**
* @since 2.0
*/
public synchronized InternalCDORevision getRevisionByTime(CDOID id, long timeStamp)
{
if (getRepository().isSupportingAudits())
{
List<InternalCDORevision> list = revisions.get(id);
if (list != null)
{
return getRevisionByTime(list, timeStamp);
}
return null;
}
throw new UnsupportedOperationException();
}
public synchronized void addRevision(InternalCDORevision revision)
{
CDOID id = revision.getID();
int version = revision.getVersion();
List<InternalCDORevision> list = revisions.get(id);
if (list == null)
{
list = new ArrayList<InternalCDORevision>();
revisions.put(id, list);
}
InternalCDORevision rev = getRevisionByVersion(list, version);
if (rev != null)
{
throw new IllegalStateException("Concurrent modification of revision " + rev); //$NON-NLS-1$
}
rev = getRevisionByVersion(list, version - 1);
if (rev != null)
{
rev.setRevised(revision.getCreated() - 1);
}
if (revision.isResource())
{
EStructuralFeature feature = revision.getEClass().getEStructuralFeature(
CDOModelConstants.RESOURCE_NODE_NAME_ATTRIBUTE);
CDOID revisionFolder = (CDOID)revision.data().getContainerID();
String revisionName = (String)revision.data().get(feature, 0);
IStoreAccessor accessor = StoreThreadLocal.getAccessor();
CDOID resourceID = accessor.readResourceID(revisionFolder, revisionName, revision.getCreated());
if (!CDOIDUtil.isNull(resourceID))
{
throw new IllegalStateException("Duplicate resource: " + revisionName + " (folderID=" + revisionFolder + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
list.add(revision);
if (listLimit != UNLIMITED)
{
enforceListLimit(list);
}
}
/**
* @since 2.0
*/
public synchronized boolean rollbackRevision(InternalCDORevision revision)
{
CDOID id = revision.getID();
List<InternalCDORevision> list = revisions.get(id);
if (list == null)
{
return false;
}
int version = revision.getVersion();
for (Iterator<InternalCDORevision> it = list.iterator(); it.hasNext();)
{
InternalCDORevision rev = it.next();
if (rev.getVersion() == version)
{
it.remove();
return true;
}
else if (rev.getVersion() == version - 1)
{
rev.setRevised(CDORevision.UNSPECIFIED_DATE);
}
}
return false;
}
/**
* @since 2.0
*/
public synchronized void removeID(CDOID id)
{
revisions.remove(id);
}
/**
* @since 2.0
*/
public synchronized void queryResources(IStoreAccessor.QueryResourcesContext context)
{
CDOID folderID = context.getFolderID();
String name = context.getName();
boolean exactMatch = context.exactMatch();
for (List<InternalCDORevision> list : revisions.values())
{
if (!list.isEmpty())
{
InternalCDORevision revision = list.get(0);
if (revision.isResourceNode())
{
revision = getRevisionByTime(list, context.getTimeStamp());
if (revision != null)
{
CDOID revisionFolder = (CDOID)revision.data().getContainerID();
if (CDOIDUtil.equals(revisionFolder, folderID))
{
EStructuralFeature feature = revision.getEClass().getEStructuralFeature(
CDOModelConstants.RESOURCE_NODE_NAME_ATTRIBUTE);
String revisionName = (String)revision.data().get(feature, 0);
boolean match = exactMatch || revisionName == null || name == null ? ObjectUtil
.equals(revisionName, name) : revisionName.startsWith(name);
if (match)
{
if (!context.addResource(revision.getID()))
{
// No more results allowed
break;
}
}
}
}
}
}
}
}
@Override
public MEMStoreAccessor createReader(ISession session)
{
return new MEMStoreAccessor(this, session);
}
/**
* @since 2.0
*/
@Override
public MEMStoreAccessor createWriter(ITransaction transaction)
{
return new MEMStoreAccessor(this, transaction);
}
/**
* @since 2.0
*/
public long getCreationTime()
{
return creationTime;
}
public boolean isFirstTime()
{
return true;
}
/**
* @since 2.0
*/
@Override
protected void doActivate() throws Exception
{
super.doActivate();
creationTime = System.currentTimeMillis();
}
@Override
protected void doDeactivate() throws Exception
{
revisions.clear();
super.doDeactivate();
}
@Override
protected StoreAccessorPool getReaderPool(ISession session, boolean forReleasing)
{
// Pooling of store accessors not supported
return null;
}
@Override
protected StoreAccessorPool getWriterPool(IView view, boolean forReleasing)
{
// Pooling of store accessors not supported
return null;
}
private InternalCDORevision getRevisionByVersion(List<InternalCDORevision> list, int version)
{
for (InternalCDORevision revision : list)
{
if (revision.getVersion() == version)
{
return revision;
}
}
return null;
}
private InternalCDORevision getRevisionByTime(List<InternalCDORevision> list, long timeStamp)
{
for (InternalCDORevision revision : list)
{
if (timeStamp == CDORevision.UNSPECIFIED_DATE)
{
if (revision.isCurrent())
{
return revision;
}
}
else
{
if (revision.isValid(timeStamp))
{
return revision;
}
}
}
return null;
}
private void enforceListLimit(List<InternalCDORevision> list)
{
while (list.size() > listLimit)
{
list.remove(0);
}
}
}