| /* |
| * Copyright (c) 2010-2012, 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: |
| * Victor Roldan Betancort - initial API and implementation |
| */ |
| package org.eclipse.emf.cdo.server.internal.db4o; |
| |
| import org.eclipse.emf.cdo.common.id.CDOID; |
| import org.eclipse.emf.cdo.common.id.CDOIDUtil; |
| import org.eclipse.emf.cdo.server.ISession; |
| import org.eclipse.emf.cdo.server.IStore; |
| 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.db4o.IDB4OIdentifiableObject; |
| import org.eclipse.emf.cdo.server.db4o.IDB4OStore; |
| import org.eclipse.emf.cdo.spi.server.LongIDStore; |
| import org.eclipse.emf.cdo.spi.server.StoreAccessorPool; |
| |
| import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; |
| import org.eclipse.net4j.util.lifecycle.LifecycleUtil; |
| |
| import com.db4o.Db4o; |
| import com.db4o.ObjectContainer; |
| import com.db4o.ObjectServer; |
| import com.db4o.ObjectSet; |
| import com.db4o.config.Configuration; |
| import com.db4o.constraints.UniqueFieldValueConstraint; |
| import com.db4o.query.Query; |
| import com.db4o.reflect.jdk.JdkReflector; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * @author Victor Roldan Betancort |
| */ |
| public class DB4OStore extends LongIDStore implements IDB4OStore |
| { |
| private static final String ID_ATTRIBUTE = "id"; |
| |
| private transient String storeLocation; |
| |
| private transient int port; |
| |
| private transient ObjectServer server; |
| |
| private transient Configuration serverConfiguration; |
| |
| private ServerInfo serverInfo; |
| |
| private DB4ODurableLockingManager durableLockingManager = new DB4ODurableLockingManager(); |
| |
| @ExcludeFromDump |
| private transient final StoreAccessorPool readerPool = new StoreAccessorPool(this, null); |
| |
| @ExcludeFromDump |
| private transient final StoreAccessorPool writerPool = new StoreAccessorPool(this, null); |
| |
| public DB4OStore(String storeLocation, int port) |
| { |
| super(IDB4OStore.TYPE, set(ChangeFormat.REVISION), set(RevisionTemporality.NONE, RevisionTemporality.AUDITING), |
| set(RevisionParallelism.NONE, RevisionParallelism.BRANCHING)); |
| |
| // setRevisionTemporality(RevisionTemporality.AUDITING); |
| // setRevisionParallelism(RevisionParallelism.BRANCHING); |
| |
| this.storeLocation = storeLocation; |
| this.port = port; |
| } |
| |
| public DB4OStore(String storeLocation, int port, Configuration serverConfiguration) |
| { |
| this(storeLocation, port); |
| this.serverConfiguration = serverConfiguration; |
| } |
| |
| public String getStoreLocation() |
| { |
| return storeLocation; |
| } |
| |
| public int getPort() |
| { |
| return port; |
| } |
| |
| public long getCreationTime() |
| { |
| return getServerInfo().getCreationTime(); |
| } |
| |
| public void setCreationTime(long creationTime) |
| { |
| getServerInfo().setCreationTime(creationTime); |
| } |
| |
| public boolean isFirstStart() |
| { |
| return getServerInfo().isFirstTime(); |
| } |
| |
| public DB4ODurableLockingManager getDurableLockingManager() |
| { |
| return durableLockingManager; |
| } |
| |
| public Map<String, String> getPersistentProperties(Set<String> names) |
| { |
| if (names == null || names.isEmpty()) |
| { |
| return new HashMap<String, String>(getServerInfo().getProperties()); |
| } |
| |
| Map<String, String> result = new HashMap<String, String>(); |
| for (String key : names) |
| { |
| String value = getServerInfo().getProperties().get(key); |
| if (value != null) |
| { |
| result.put(key, value); |
| } |
| } |
| |
| return result; |
| } |
| |
| public void setPersistentProperties(Map<String, String> properties) |
| { |
| ServerInfo serverInfo = getServerInfo(); |
| serverInfo.getProperties().putAll(properties); |
| commitServerInfo(null); |
| } |
| |
| public void removePersistentProperties(Set<String> names) |
| { |
| ServerInfo serverInfo = getServerInfo(); |
| Map<String, String> properties = serverInfo.getProperties(); |
| for (String key : names) |
| { |
| properties.remove(key); |
| } |
| |
| commitServerInfo(null); |
| } |
| |
| // @Override |
| // public CDOID getNextCDOID(LongIDStoreAccessor accessor, CDORevision revision) |
| // { |
| // ObjectContainer objectContainer = ((DB4OStoreAccessor)accessor).getObjectContainer(); |
| // ExtObjectContainer ext = objectContainer.ext(); |
| // ext.store(revision); |
| // |
| // long id = ext.getID(revision); |
| // return CDOIDUtil.createLong(id); |
| // } |
| |
| public ObjectContainer openClient() |
| { |
| return server.openClient(); |
| } |
| |
| @Override |
| protected void doActivate() throws Exception |
| { |
| super.doActivate(); |
| initObjectServer(); |
| initServerInfo(); |
| setLastCommitTime(getServerInfo().getLastCommitTime()); |
| setLastObjectID(fetchLastObjectID()); |
| LifecycleUtil.activate(durableLockingManager); |
| } |
| |
| private long fetchLastObjectID() |
| { |
| ObjectContainer container = openClient(); |
| |
| try |
| { |
| Query query = container.query(); |
| query.constrain(DB4ORevision.class); |
| query.descend("id").orderDescending(); |
| ObjectSet<?> results = query.execute(); |
| int size = results.size(); |
| if (size > 0) |
| { |
| DB4ORevision rev = (DB4ORevision)results.next(); |
| return rev.getID(); |
| } |
| return 0; |
| } |
| finally |
| { |
| closeClient(container); |
| } |
| } |
| |
| @SuppressWarnings("deprecation") |
| protected void initObjectServer() |
| { |
| Configuration configuration = serverConfiguration; |
| if (configuration == null) |
| { |
| configuration = createServerConfiguration(); |
| } |
| { |
| File file = new File(getStoreLocation()); |
| if (!file.exists()) |
| { |
| try |
| { |
| file.createNewFile(); |
| } |
| catch (IOException ex) |
| { |
| throw new RuntimeException(ex); |
| } |
| } |
| } |
| |
| server = Db4o.openServer(configuration, getStoreLocation(), getPort()); |
| } |
| |
| protected void tearDownObjectServer() |
| { |
| server.close(); |
| server = null; |
| } |
| |
| private ServerInfo getServerInfo() |
| { |
| if (serverInfo == null) |
| { |
| initServerInfo(); |
| } |
| |
| return serverInfo; |
| } |
| |
| private void initServerInfo() |
| { |
| ObjectContainer container = openClient(); |
| |
| try |
| { |
| serverInfo = getServerInfoFromDatabase(container); |
| |
| if (serverInfo == null) |
| { |
| serverInfo = new ServerInfo(); |
| serverInfo.setFirstTime(true); |
| serverInfo.setCreationTime(System.currentTimeMillis()); |
| commitServerInfo(container); |
| } |
| else |
| { |
| if (serverInfo.isFirstTime()) |
| { |
| serverInfo.setFirstTime(false); |
| commitServerInfo(container); |
| } |
| } |
| } |
| finally |
| { |
| closeClient(container); |
| } |
| } |
| |
| private ServerInfo getServerInfoFromDatabase(ObjectContainer container) |
| { |
| ObjectSet<ServerInfo> infos = container.query(ServerInfo.class); |
| if (infos.size() > 1) |
| { |
| throw new IllegalStateException("ServeInfo is stored in container more than once"); |
| } |
| |
| if (infos.size() == 1) |
| { |
| return infos.get(0); |
| } |
| |
| return null; |
| } |
| |
| protected void closeClient(ObjectContainer container) |
| { |
| container.close(); |
| } |
| |
| private void commitServerInfo(ObjectContainer container) |
| { |
| ObjectContainer usedContainer = container != null ? container : openClient(); |
| |
| try |
| { |
| ServerInfo storedInfo = getServerInfoFromDatabase(usedContainer); |
| if (storedInfo != null && storedInfo != serverInfo) |
| { |
| storedInfo.setCreationTime(serverInfo.getCreationTime()); |
| storedInfo.setFirstTime(serverInfo.isFirstTime()); |
| storedInfo.setLastCommitTime(serverInfo.getLastCommitTime()); |
| storedInfo.setProperties(serverInfo.getProperties()); |
| serverInfo = storedInfo; |
| } |
| |
| usedContainer.store(serverInfo); |
| usedContainer.commit(); |
| } |
| finally |
| { |
| if (usedContainer != container) |
| { |
| closeClient(usedContainer); |
| } |
| } |
| } |
| |
| @Override |
| protected void doDeactivate() throws Exception |
| { |
| ObjectContainer container = openClient(); |
| |
| try |
| { |
| getServerInfo().setLastCommitTime(getLastCommitTime()); |
| commitServerInfo(container); |
| } |
| finally |
| { |
| closeClient(container); |
| } |
| |
| LifecycleUtil.deactivate(durableLockingManager); |
| tearDownObjectServer(); |
| |
| super.doDeactivate(); |
| } |
| |
| protected Configuration createServerConfiguration() |
| { |
| @SuppressWarnings("deprecation") |
| Configuration config = Db4o.newConfiguration(); |
| config.reflectWith(new JdkReflector(getClass().getClassLoader())); |
| |
| config.objectClass(DB4ORevision.class).objectField("id").indexed(true); |
| config.add(new UniqueFieldValueConstraint(DB4ORevision.class, "id")); |
| |
| config.objectClass(DB4OPackageUnit.class).objectField("id").indexed(true); |
| config.add(new UniqueFieldValueConstraint(DB4OPackageUnit.class, "id")); |
| |
| config.objectClass(DB4OIdentifiableObject.class).objectField("id").indexed(true); |
| config.add(new UniqueFieldValueConstraint(DB4OIdentifiableObject.class, "id")); |
| |
| config.objectClass(DB4OCommitInfo.class).objectField("timeStamp").indexed(true); |
| |
| config.objectClass(DB4OLockArea.class).objectField("id").indexed(true); |
| config.add(new UniqueFieldValueConstraint(DB4OLockArea.class, "id")); |
| config.objectClass(DB4OLockArea.class).cascadeOnUpdate(true); |
| config.objectClass(DB4OLockArea.class).cascadeOnDelete(true); |
| |
| return config; |
| } |
| |
| @Override |
| protected IStoreAccessor createReader(ISession session) |
| { |
| return new DB4OStoreAccessor(this, session); |
| } |
| |
| @Override |
| protected IStoreAccessor createWriter(ITransaction transaction) |
| { |
| return new DB4OStoreAccessor(this, transaction); |
| } |
| |
| @Override |
| protected StoreAccessorPool getReaderPool(ISession session, boolean forReleasing) |
| { |
| return readerPool; |
| } |
| |
| @Override |
| protected StoreAccessorPool getWriterPool(IView view, boolean forReleasing) |
| { |
| return writerPool; |
| } |
| |
| public static DB4ORevision getRevision(ObjectContainer container, CDOID id) |
| { |
| Query query = container.query(); |
| query.constrain(DB4ORevision.class); |
| query.descend(ID_ATTRIBUTE).constrain(CDOIDUtil.getLong(id)); |
| |
| ObjectSet<?> revisions = query.execute(); |
| if (revisions.isEmpty()) |
| { |
| return null; |
| } |
| |
| return (DB4ORevision)revisions.get(0); |
| } |
| |
| public static <T> List<T> getElementsOfType(ObjectContainer container, Class<T> clazz) |
| { |
| ObjectSet<T> elements = container.query(clazz); |
| return elements; |
| } |
| |
| public static IDB4OIdentifiableObject getIdentifiableObject(ObjectContainer container, String id) |
| { |
| Query query = container.query(); |
| query.constrain(IDB4OIdentifiableObject.class); |
| query.descend(ID_ATTRIBUTE).constrain(id); |
| |
| ObjectSet<?> revisions = query.execute(); |
| if (revisions.isEmpty()) |
| { |
| return null; |
| } |
| |
| return (IDB4OIdentifiableObject)revisions.get(0); |
| } |
| |
| public static void removeRevision(ObjectContainer container, CDOID id) |
| { |
| DB4ORevision revision = getRevision(container, id); |
| if (revision != null) |
| { |
| container.delete(revision); |
| } |
| } |
| |
| /** |
| * Carries {@link IStore}-related information. |
| * |
| * @author Victor Roldan Betancort |
| */ |
| private static final class ServerInfo |
| { |
| private boolean isFirstTime; |
| |
| private long creationTime; |
| |
| private long lastCommitTime; |
| |
| private Map<String, String> properties = new HashMap<String, String>(); |
| |
| public boolean isFirstTime() |
| { |
| return isFirstTime; |
| } |
| |
| public void setFirstTime(boolean isFirstTime) |
| { |
| this.isFirstTime = isFirstTime; |
| } |
| |
| public void setCreationTime(long creationTime) |
| { |
| this.creationTime = creationTime; |
| } |
| |
| public long getCreationTime() |
| { |
| return creationTime; |
| } |
| |
| public void setProperties(Map<String, String> properties) |
| { |
| this.properties = properties; |
| } |
| |
| public Map<String, String> getProperties() |
| { |
| return properties; |
| } |
| |
| public long getLastCommitTime() |
| { |
| return lastCommitTime; |
| } |
| |
| public void setLastCommitTime(long lastCommitTime) |
| { |
| this.lastCommitTime = lastCommitTime; |
| } |
| } |
| } |