/*
* Copyright 2009-2016 Tilmann Zaeschke. All rights reserved.
*
* This file is part of ZooDB.
*
* ZooDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZooDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZooDB. If not, see <http://www.gnu.org/licenses/>.
*
* See the README and COPYING files for further information.
*/
package org.zoodb.test.jdo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import javax.jdo.PersistenceManager;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.zoodb.api.impl.ZooPC;
import org.zoodb.jdo.ZooJdoHelper;
import org.zoodb.jdo.ZooJdoProperties;
import org.zoodb.schema.ZooClass;
import org.zoodb.schema.ZooField;
import org.zoodb.schema.ZooHandle;
import org.zoodb.schema.ZooSchema;
import org.zoodb.test.testutil.TestTools;
public class Test_039_SchemaEvolBug {
private static ZooJdoProperties props;
private URI uri;
private Date date = new Date(12345678);
public Test_039_SchemaEvolBug() throws URISyntaxException {
uri = new URI("http://www.zoodb.org");
}
@BeforeClass
public static void beforeClass() {
props = new ZooJdoProperties(TestTools.getDbName());
props.setZooAutoCreateSchema(true);
}
@Before
public void before() {
TestTools.closePM();
TestTools.removeDb();
TestTools.createDb();
}
@Test
public void testIssue66() throws URISyntaxException {
//populate
Object[] oids = init(false);
//evolve
PersistenceManager pm = TestTools.openPM();
pm.currentTransaction().begin();
ZooSchema zs = ZooJdoHelper.schema(pm);
ZooClass sFile = zs.getClass(FilePCv1.class.getName());
sFile.rename(FilePCv2.class.getName());
sFile.addField("originalFileName", String.class);
ZooClass sAsset = zs.getClass(AssetPCv1.class.getName());
sAsset.addField("file", sFile, 0);
sAsset.addField("sourceFile", sFile, 0);
ZooField zf1 = sAsset.getField("storagePath");
ZooField zf2 = sAsset.getField("mimeType");
ZooField zf3 = sAsset.getField("fileName");
//evolve
Iterator<ZooHandle> assetHandleIterator = sAsset.getHandleIterator(false);
while (assetHandleIterator.hasNext()) {
final ZooHandle assetHandle = assetHandleIterator.next();
// final FilePCv2 file = new FilePCv2(
// id,
// (String) assetHandle.getValue("s1"),
// (String) assetHandle.getValue("s2"),
// (String) assetHandle.getValue("s3"));
ZooHandle file = sFile.newInstance();
file.setValue("storagePath", assetHandle.getValue("storagePath"));
file.setValue("mimeType", assetHandle.getValue("mimeType"));
file.setValue("originalFileName", assetHandle.getValue("fileName"));
assetHandle.setValue("file", file);
assetHandle.setValue("sourceFile", null);
}
//delete fields
zf1.remove();
zf2.remove();
zf3.remove();
pm.currentTransaction().commit();
pm.currentTransaction().begin();
sFile = zs.getClass(AssetPCv1.class.getName());
sFile.rename(AssetPCv2.class.getName());
pm.currentTransaction().commit();
TestTools.closePM();
//check evolved data
pm = TestTools.openPM();
pm.currentTransaction().begin();
AssetPCv2 a2 = (AssetPCv2) pm.getObjectById(oids[0]);
assertEquals("myS1", a2.getFile().storagePath());
assertEquals("myS2", a2.getFile().mimeType());
assertEquals("myS3", a2.getFile().originalFileName());
//TODO
assertEquals(uri, a2.uri());
assertEquals(date, a2.date());
assertEquals(55, a2.fileArray().length);
pm.currentTransaction().commit();
TestTools.closePM();
}
private Object[] init(boolean createFile) {
TestTools.createDb();
TestTools.defineSchema(FilePCv1.class, AssetPCv1.class, IdPC.class);
PersistenceManager pm = TestTools.openPM();
pm.currentTransaction().begin();
Object[] oids = new Object[10];
UserPC[] users = new UserPC[2];
users[0] = new UserPC(333+0, "user"+0);
users[1] = new UserPC(333+1, "user"+1);
for (int i = 0; i < oids.length; i++) {
AssetPCv1 a1 = new AssetPCv1(234, users[i%2], uri, date, 55);
if (createFile) {
a1.setFile(new FilePCv1(222+i, "sp" + i, "mt" + i));
}
pm.makePersistent(a1);
oids[i] = pm.getObjectId(a1);
}
pm.currentTransaction().commit();
TestTools.closePM();
return oids;
}
private Object[] initProjectBranch() {
TestTools.defineSchema(ProjectBranchPCv1.class);
PersistenceManager pm = TestTools.openPM();
pm.currentTransaction().begin();
Object[] oids = new Object[10];
UserPC[] users = new UserPC[2];
users[0] = new UserPC(333+0, "userPB"+0);
users[1] = new UserPC(333+1, "userPB"+1);
for (int i = 0; i < oids.length; i++) {
ProjectBranchPCv1 a1 = new ProjectBranchPCv1(234, "PB"+i, users[i%2]);
pm.makePersistent(a1);
oids[i] = pm.getObjectId(a1);
}
pm.currentTransaction().commit();
TestTools.closePM();
return oids;
}
@Test
public void testIssue66NoReflection() {
//populate
Object[] oids = init(false);
//evolve
PersistenceManager pm = TestTools.openPM();
pm.currentTransaction().begin();
ZooSchema zs1 = ZooJdoHelper.schema(pm);
ZooClass sFile1 = zs1.getClass(FilePCv1.class.getName());
sFile1.rename(FilePCv2.class.getName());
sFile1.addField("originalFileName", String.class);
//TODO remove
// pm.currentTransaction().commit();
// TestTools.closePM();
// pm = TestTools.openPM();
// pm.currentTransaction().begin();
ZooSchema zs = ZooJdoHelper.schema(pm);
ZooClass sFile = zs.getClass(FilePCv2.class.getName());
ZooClass sAsset = zs.getClass(AssetPCv1.class.getName());
sAsset.addField("file", sFile, 0);
sAsset.addField("sourceFile", sFile, 0);
ZooField zf1 = sAsset.getField("storagePath");
ZooField zf2 = sAsset.getField("mimeType");
ZooField zf3 = sAsset.getField("fileName");
//evolve
Iterator<ZooHandle> assetHandleIterator = sAsset.getHandleIterator(false);
while (assetHandleIterator.hasNext()) {
final ZooHandle assetHandle = assetHandleIterator.next();
final FilePCv2 file = new FilePCv2(
123,
(String) assetHandle.getValue("storagePath"),
(String) assetHandle.getValue("mimeType"),
(String) assetHandle.getValue("fileName"));
// ZooHandle file = sFile.newInstance();
// file.setValue("storagePath", assetHandle.getValue("s1"));
// file.setValue("mimeType", assetHandle.getValue("s2"));
// file.setValue("originalFileName", assetHandle.getValue("s3"));
//
// //TODO fix
//the following can be used to prevent an NPE for empty context....
// pm.makePersistent(file);
//TODO use field handle
assetHandle.setValue("file", file);
assetHandle.setValue("sourceFile", null);
}
//delete fields
zf1.remove();
zf2.remove();
zf3.remove();
pm.currentTransaction().commit();
pm.currentTransaction().begin();
sFile = zs.getClass(AssetPCv1.class.getName());
sFile.rename(AssetPCv2.class.getName());
pm.currentTransaction().commit();
TestTools.closePM();
//check evolved data
pm = TestTools.openPM();
pm.currentTransaction().begin();
AssetPCv2 a2 = (AssetPCv2) pm.getObjectById(oids[0]);
assertEquals("myS1", a2.getFile().storagePath());
assertEquals("myS2", a2.getFile().mimeType());
assertEquals("myS3", a2.getFile().originalFileName());
//TODO
//assertEquals(uri, a2.uri());
assertEquals(date, a2.date());
assertEquals(55, a2.fileArray().length);
pm.currentTransaction().commit();
TestTools.closePM();
}
@Test
public void testFull() {
//populate
init(true);
PersistenceManager pm = TestTools.openPM();
applyInternal(pm);
pm.currentTransaction().commit();
TestTools.closePM();
pm = TestTools.openPM();
pm.currentTransaction().begin();
int n = 0;
@SuppressWarnings("unchecked")
Collection<AssetPCv2> c = (Collection<AssetPCv2>) pm.newQuery(AssetPCv2.class).execute();
for (AssetPCv2 a: c) {
assertNotNull(a.getFile());
assertNotNull(a.getFile().originalFileName());
n++;
}
assertEquals(10, n);
pm.currentTransaction().rollback();
TestTools.closePM();
}
@Test
public void testFullWithProjectBranch() {
//populate
init(true);
initProjectBranch();
ZooJdoProperties p = TestTools.getProps();
p.setZooAutoCreateSchema(true);
PersistenceManager pm = TestTools.openPM(p);
applyInternal(pm);
ZooSchema schema = ZooJdoHelper.schema(pm);
ZooClass pbClass = schema.getClass(ProjectBranchPCv1.class.getName());
pbClass.rename(ProjectBranchPCv2.class.getName());
//pbClass.addField("bgImage", BackgroundImagePCv2.class);
//Iterator<ZooHandle> hi = pbClass.getHandleIterator(true);
//while (hi.hasNext()) {
// //this was an attempt to enforce evolution of objects. It resulted in
// //an NPE in the Deserializer when accessing the class-map with cls=null.
// hi.next();
//}
//schema.addClass(BackgroundImagePCv2.class);
pm.currentTransaction().commit();
TestTools.closePM();
pm = TestTools.openPM();
pm.currentTransaction().begin();
int n = 0;
@SuppressWarnings("unchecked")
Collection<ProjectBranchPCv2> cPB = (Collection<ProjectBranchPCv2>)
pm.newQuery(ProjectBranchPCv2.class).execute();
for (ProjectBranchPCv2 a: cPB) {
assertNotNull(a.getName());
assertNull(a.getBackgroundImage());
n++;
}
assertEquals(10, n);
n = 0;
@SuppressWarnings("unchecked")
Collection<AssetPCv2> c = (Collection<AssetPCv2>) pm.newQuery(AssetPCv2.class).execute();
for (AssetPCv2 a: c) {
assertNotNull(a.getFile());
assertNotNull(a.getFile().originalFileName());
n++;
}
assertEquals(10, n);
pm.currentTransaction().rollback();
TestTools.closePM();
}
private void applyInternal(PersistenceManager pm) {
final String fileFieldName = "file";
final String sourceFileFieldName = "sourceFile";
final String storagePathFieldName = "storagePath";
final String mimeTypeFieldName = "mimeType";
final String storagePathFieldNameF = "storagePath";
final String mimeTypeFieldNameF = "mimeType";
final String fileNameFieldName = "fileName";
final String originalFileNameFieldName = "originalFileName";
final String idFieldName = "id";
pm.currentTransaction().begin();
final ZooSchema schema = ZooJdoHelper.schema(pm);
// rename the ThumbnailPC class to FilePC
// ThumbnailPC.class no longer exists in the code base, so we reference it by name string.
//Evolve0to1.logger.info("Renaming ThumbnailPC to FilePC");
final ZooClass filePCclass = schema.getClass(FilePCv1.class.getName());
filePCclass.rename(FilePCv2.class.getName());
// add field originalFileName to FilePC
//Evolve0to1.logger.info("Adding field to FilePC");
filePCclass.addField(originalFileNameFieldName, String.class);
// add fields of type FilePC to AssetPC: file, sourceFile
//Evolve0to1.logger.info("Adding fields to AssetPC");
final ZooClass assetPCclass = schema.getClass(AssetPCv1.class.getName());
assetPCclass.addField(fileFieldName, FilePCv2.class);
assetPCclass.addField(sourceFileFieldName, FilePCv2.class);
// get id generator
//Evolve0to1.logger.info("Fetching IdGenerator");
//IdGenerator.init(pm);
//final IdGenerator idGenerator = IdGenerator.instance();
long idGen = 123456;
//Evolve0to1.logger.info("Fetching classes and fields");
// get IdPC class and fields
final ZooClass idPCclass = schema.getClass(IdPC.class);
final ZooField idPCidField = idPCclass.getField(idFieldName);
final ZooField idPCidentifeeField = idPCclass.getField("identifee");
// get AssetPC fields
final ZooField assetPCfileField = assetPCclass.getField(fileFieldName);
final ZooField assetPCsourcefileField = assetPCclass.getField(sourceFileFieldName);
// get FilePC fields
final ZooField filePCidField = filePCclass.getField(idFieldName);
final ZooField filePCstoragepathField = filePCclass.getField(storagePathFieldName);
final ZooField filePCmimetypeField = filePCclass.getField(mimeTypeFieldName);
final ZooField filePCoriginalfilenameField = filePCclass.getField(originalFileNameFieldName);
// populate the FilePC attributes of AssetPC
//Evolve0to1.logger.info("Populating new fields in AssetPC with FilePC instances");
final Iterator<ZooHandle> assetHandleIterator = assetPCclass.getHandleIterator(false);
while (assetHandleIterator.hasNext()) {
final long id = idGen++;
final ZooHandle assetHandle = assetHandleIterator.next();
// final FilePC file = new FilePC(
// id,
// (String) assetHandle.getValue(storagePathFieldName),
// (String) assetHandle.getValue(mimeTypeFieldName),
// (String) assetHandle.getValue(fileNameFieldName));
// final FilePC sourceFile = null;
final ZooHandle file = filePCclass.newInstance();
filePCidField.setValue(file, id);
filePCstoragepathField.setValue(file, assetHandle.getValue(storagePathFieldNameF));
filePCmimetypeField.setValue(file, assetHandle.getValue(mimeTypeFieldNameF));
filePCoriginalfilenameField.setValue(file, assetHandle.getValue(fileNameFieldName));
final ZooHandle idPC = idPCclass.newInstance();
idPCidField.setValue(idPC, id);
idPCidentifeeField.setValue(idPC, file);
assetPCfileField.setValue(assetHandle, file);
assetPCsourcefileField.setValue(assetHandle, null);
}
// remove fields from AssetPC: storagePath, mimeType, fileName
//Evolve0to1.logger.info("Removing fields from AssetPC");
assetPCclass.getField(storagePathFieldNameF).remove();
assetPCclass.getField(mimeTypeFieldNameF).remove();
assetPCclass.getField(fileNameFieldName).remove();
assetPCclass.rename(AssetPCv2.class.getName());
//Evolve0to1.logger.info("Done!");
}
// @Test
// public void testOrig() {
// //renameOrigToTestClasses();
// PersistenceManager pm = TestTools.openPM("IdeaGarden-Backend.db");
// applyInternal(pm);
// pm.currentTransaction().rollback();
// TestTools.closePM();
// }
private void renameOrigToTestClasses() {
PersistenceManager pm = TestTools.openPM("IdeaGarden-Backend.db");
pm.currentTransaction().begin();
ZooSchema schema = ZooJdoHelper.schema(pm);
schema.getClass("eu.ideagarden.backend.persistent.ThumbnailPC").rename(FilePCv1.class.getName());
schema.getClass("eu.ideagarden.backend.persistent.AssetPC").rename(AssetPCv1.class.getName());
schema.getClass("eu.ideagarden.backend.persistent.UserPC").rename(UserPC.class.getName());
schema.getClass("eu.ideagarden.backend.persistent.IdPC").rename(IdPC.class.getName());
schema.getClass("eu.ideagarden.backend.persistent.AbstractPC").rename(AbstractPC.class.getName());
schema.getClass("eu.ideagarden.backend.persistent.AbstractIdentifiedPC").rename(AbstractIdentifiedPC.class.getName());
pm.currentTransaction().commit();
TestTools.closePM();
}
}
abstract class AbstractPC extends ZooPC {
protected AbstractPC() {
// default constructor for ZooDB
}
}
abstract class AbstractIdentifiedPC extends AbstractPC {
private long id;
protected AbstractIdentifiedPC() {
// default constructor for ZooDB
}
protected AbstractIdentifiedPC(final long id) {
this.id = id;
}
public long getId() {
this.zooActivateRead();
return this.id;
}
}
@SuppressWarnings("unused")
class AssetPCv1 extends AbstractIdentifiedPC {
private URI origin;
private Date importDate;
// private FilePCv1 file;
// private FilePCv1 sourceFile;
private String storagePath, mimeType, fileName; //-> new instance of 'file'.
private FilePCv1[] thumbnails;
private FilePCv1 selectedThumbnail;
private boolean onlyFirstThumbGenerated;
private UserPC creatingUser;
private UserPC thumbnailSettingUser;
private AssetPCv1(){
// hidden default constructor for ZooDB.
}
public void setFile(FilePCv1 file) {
selectedThumbnail = file;
}
public AssetPCv1(final long id, UserPC creatingUser, final URI request, Date date, int i) {
super(id);
this.origin = request;
this.creatingUser = creatingUser;
this.onlyFirstThumbGenerated = true;
this.importDate = date;
this.thumbnails = new FilePCv1[i];
this.storagePath = "myS1";
this.mimeType = "myS2";
this.fileName = "myS3";
}
}
@SuppressWarnings("unused")
class AssetPCv2 extends AbstractIdentifiedPC {
private URI origin;
private Date importDate;
private FilePCv2 file;
private FilePCv2 sourceFile;
private FilePCv2[] thumbnails;
private FilePCv2 selectedThumbnail;
private boolean onlyFirstThumbGenerated;
private UserPC creatingUser;
private UserPC thumbnailSettingUser;
private AssetPCv2(){
// hidden default constructor for ZooDB.
}
public FilePCv2[] fileArray() {
return thumbnails;
}
public Date date() {
return importDate;
}
public URI uri() {
return origin;
}
public FilePCv2 getFile() {
return file;
}
public AssetPCv2(final long id, UserPC creatingUser, final URI request, Date date, int i) {
super(id);
this.origin = request;
this.creatingUser = creatingUser;
this.onlyFirstThumbGenerated = true;
this.thumbnails = new FilePCv2[i];
this.importDate = date;
}
}
class FilePCv2 extends AbstractIdentifiedPC {
private String storagePath;
private String mimeType;
private String originalFileName;
@SuppressWarnings("unused")
private FilePCv2() {
// hidden default constructor for ZooDB.
}
public String originalFileName() {
zooActivateRead();
return originalFileName;
}
public String mimeType() {
zooActivateRead();
return mimeType;
}
public String storagePath() {
zooActivateRead();
return storagePath;
}
public FilePCv2(final long id) {
super(id);
}
public FilePCv2(final long id, final String storagePath, final String mimeType, final String originalFileName) {
this(id);
this.storagePath = storagePath;
this.mimeType = mimeType;
this.originalFileName = originalFileName;
}
}
@SuppressWarnings("unused")
class FilePCv1 extends AbstractIdentifiedPC {
private String storagePath;
private String mimeType;
//private String originalFileName;
private FilePCv1() {
// hidden default constructor for ZooDB.
}
public FilePCv1(final long id) {
super(id);
}
public FilePCv1(final long id, final String storagePath, final String mimeType) {
this(id);
this.storagePath = storagePath;
this.mimeType = mimeType;
//this.originalFileName = originalFileName;
}
}
class IdPC extends AbstractIdentifiedPC {
private AbstractIdentifiedPC identifee;
@SuppressWarnings("unused")
private IdPC() {
// hidden default constructor for ZooDB
}
public IdPC(final long id) {
super(id);
}
public void setIdentfee(final AbstractIdentifiedPC identifee) {
this.zooActivateWrite();
this.identifee = identifee;
}
public AbstractIdentifiedPC getIdentifee() {
this.zooActivateRead();
return this.identifee;
}
public void removeIdentifee() {
this.zooActivateWrite();
this.identifee = null;
}
}
class UserPC extends AbstractIdentifiedPC {
private String name;
@SuppressWarnings("unused")
private UserPC(){
// hidden default constructor for ZooDB.
}
public UserPC(final long id, final String name) {
super(id);
this.name = name;
}
public String getName() {
this.zooActivateRead();
return this.name;
}
public void setName(final String name) {
this.zooActivateWrite();
this.name = name;
}
}
class BackgroundImagePCv2 extends AbstractPC {
private int i1;
private int i2;
private int coordX, coordY;
}
class ProjectBranchPCv1 extends AbstractIdentifiedPC {
private String name;
private UserPC creator;
private Date creationDate;
private Date lastUpdateDate;
// private ProjectSnapshotPC initialState;
// private ProjectBranchPC sourceBranch;
// private Map<Long, ProjectSnapshotPC> snapshots;
// private ProjectSnapshotPC currentState;
// private ProjectSnapshotPC baseSnapshot;
protected ProjectBranchPCv1() {
// hidden default constructor for ZooDB
}
public ProjectBranchPCv1(final long id, final String name, final UserPC creator) {
//final IdPC currentStateId) {
//, final ProjectSnapshotPC initialState, final ProjectBranchPC sourceBranch) {
super(id);
this.name = name;
this.creator = creator;
this.creationDate = Calendar.getInstance().getTime();
this.lastUpdateDate = this.creationDate;
// this.snapshots = new HashMap<Long, ProjectSnapshotPC>();
// this.currentState = new ProjectSnapshotPC(currentStateId.getId(), creator, "current state", null);
// currentStateId.setIdentfee(this.currentState);
// this.initialState = initialState;
// this.sourceBranch = sourceBranch;
}
public String getName() {
this.zooActivateRead();
return this.name;
}
public UserPC getCreator() {
this.zooActivateRead();
return this.creator;
}
public Date getCreationDate() {
this.zooActivateRead();
return this.creationDate;
}
public Date getLastUpdateDate() {
this.zooActivateRead();
return this.lastUpdateDate;
}
/**
* Sets lastUdate date to now.
*/
public void setLastUpdateDate() {
this.zooActivateWrite();
this.lastUpdateDate = Calendar.getInstance().getTime();
}
}
class ProjectBranchPCv2 extends AbstractIdentifiedPC {
private String name;
private UserPC creator;
private Date creationDate;
private Date lastUpdateDate;
// private ProjectSnapshotPC initialState;
// private ProjectBranchPC sourceBranch;
// private Map<Long, ProjectSnapshotPC> snapshots;
// private ProjectSnapshotPC currentState;
// private ProjectSnapshotPC baseSnapshot;
private BackgroundImagePCv2 bgImage;
protected ProjectBranchPCv2() {
// hidden default constructor for ZooDB
}
public ProjectBranchPCv2(final long id, final String name, final UserPC creator) {
super(id);
this.name = name;
this.creator = creator;
this.creationDate = Calendar.getInstance().getTime();
this.lastUpdateDate = this.creationDate;
}
public BackgroundImagePCv2 getBackgroundImage() {
zooActivateRead();
return bgImage;
}
public String getName() {
this.zooActivateRead();
return this.name;
}
public UserPC getCreator() {
this.zooActivateRead();
return this.creator;
}
public Date getCreationDate() {
this.zooActivateRead();
return this.creationDate;
}
public Date getLastUpdateDate() {
this.zooActivateRead();
return this.lastUpdateDate;
}
/**
* Sets lastUdate date to now.
*/
public void setLastUpdateDate() {
this.zooActivateWrite();
this.lastUpdateDate = Calendar.getInstance().getTime();
}
// public ProjectSnapshotPC getInitialState() {
// this.zooActivateRead();
// return this.initialState;
// }
//
//
// public Map<Long, ProjectSnapshotPC> getSnapshots() {
// this.zooActivateWrite();
// return this.snapshots;
// }
//
//
// public ProjectSnapshotPC getCurrentState() {
// this.zooActivateWrite();
// return this.currentState;
// }
//
//
// public ProjectBranchPC getSourceBranch() {
// this.zooActivateRead();
// return this.sourceBranch;
// }
//
//
// public ProjectSnapshotPC getBaseSnapshot() {
// this.zooActivateRead();
// return this.baseSnapshot;
// }
//
//
// public void setBaseSnapshot(final ProjectSnapshotPC baseSnapshot) {
// this.zooActivateWrite();
// this.baseSnapshot = baseSnapshot;
// }
//
//
// @Override
// public ProjectBranchPC copy(final IdentityHashMap<AbstractPC, AbstractPC> copiedObjects) {
// if (copiedObjects.containsKey(this)) {
// return (ProjectBranchPC) copiedObjects.get(this);
// }
//
// final ProjectBranchPC copy = new ProjectBranchPC();
// copiedObjects.put(this, copy);
// this.copyInternal(copy, copiedObjects);
// return copy;
// }
//
// @Override
// protected void copyInternal(final AbstractPC abstractCopy, final IdentityHashMap<AbstractPC, AbstractPC> copiedObjects) {
// final ProjectBranchPC copy = (ProjectBranchPC) abstractCopy;
// this.zooActivateRead();
// copy.name = this.name;
// copy.creationDate = this.creationDate;
// copy.lastUpdateDate = this.lastUpdateDate;
// copy.creator = this.creator.copy(copiedObjects);
// if (this.baseSnapshot != null) {
// copy.baseSnapshot = this.baseSnapshot.copy(copiedObjects);
// }
// copy.currentState = this.currentState.copy(copiedObjects);
// if (this.initialState != null) {
// copy.initialState = this.initialState.copy(copiedObjects);
// }
// copy.snapshots = new HashMap<Long, ProjectSnapshotPC>();
// for (final Entry<Long, ProjectSnapshotPC> entry : this.snapshots.entrySet()) {
// copy.snapshots.put(entry.getKey(), entry.getValue().copy(copiedObjects));
// }
// if (this.sourceBranch != null) {
// copy.sourceBranch = this.sourceBranch.copy(copiedObjects);
// }
// super.copyInternal(copy, copiedObjects);
// }
}