From 6b9cd11be4b9ff4dc0f31ff0f23eaef6b4375ac2 Mon Sep 17 00:00:00 2001 From: Yevhenii Voevodin Date: Fri, 22 Jul 2016 18:39:01 +0300 Subject: [PATCH] CHE-1797: Add JPA based SnapshotDao implementation --- .../che/api/core/model/machine/Snapshot.java | 6 - .../api/machine/shared/dto/SnapshotDto.java | 4 - .../che/api/machine/server/DtoConverter.java | 1 - .../api/machine/server/MachineManager.java | 30 +-- .../api/machine/server/MachineService.java | 6 +- .../machine/server/jpa/JpaSnapshotDao.java | 135 +++++++++++ .../server/model/impl/SnapshotImpl.java | 157 +++++++++---- .../api/machine/server/spi/SnapshotDao.java | 6 +- .../machine/server/MachineManagerTest.java | 1 - .../api/machine/server/jpa/JpaTckModule.java | 5 + .../server/spi/tck/SnapshotDaoTest.java | 220 ++++++++++++++++++ .../test/resources/META-INF/persistence.xml | 1 + .../api/workspace/server/DtoConverter.java | 1 - .../workspace/server/WorkspaceManager.java | 4 +- .../workspace/server/WorkspaceService.java | 2 +- .../server/model/impl/WorkspaceImpl.java | 12 + .../server/WorkspaceManagerTest.java | 8 +- .../server/WorkspaceServiceTest.java | 2 +- .../test/resources/META-INF/persistence.xml | 1 + .../che/api/local/LocalSnapshotDaoImpl.java | 32 ++- .../api/local/LocalRecipeTckRepository.java | 39 ---- .../che/api/local/LocalSnapshotDaoTest.java | 1 - .../api/local/LocalStackTcKRepository.java | 39 ---- .../eclipse/che/api/local/LocalTckModule.java | 80 +++++-- ...epository.java => LocalTckRepository.java} | 27 ++- .../che/api/local/LocalUserTckRepository.java | 38 --- .../local/LocalWorkspaceTckRepository.java | 39 ---- 27 files changed, 615 insertions(+), 282 deletions(-) create mode 100644 wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java create mode 100644 wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java delete mode 100644 wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalRecipeTckRepository.java delete mode 100644 wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalStackTcKRepository.java rename wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/{LocalProfileTckRepository.java => LocalTckRepository.java} (54%) delete mode 100644 wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalUserTckRepository.java delete mode 100644 wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalWorkspaceTckRepository.java diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/Snapshot.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/Snapshot.java index fe3ab10fed88..f87bacf11cb5 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/Snapshot.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/Snapshot.java @@ -28,12 +28,6 @@ public interface Snapshot { */ String getType(); - /** - * Snapshot namespace, which allows snapshot to be - * related to the certain workspace machine. - */ - String getNamespace(); - /** * Creation date of the snapshot */ diff --git a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/SnapshotDto.java b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/SnapshotDto.java index 7e2677bf0c81..a6c2ee4e4ec7 100644 --- a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/SnapshotDto.java +++ b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/SnapshotDto.java @@ -26,10 +26,6 @@ public interface SnapshotDto extends Snapshot, Hyperlinks { SnapshotDto withId(String id); - void setNamespace(String owner); - - SnapshotDto withNamespace(String namespace); - void setType(String type); SnapshotDto withType(String type); diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/DtoConverter.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/DtoConverter.java index 7afd64ee21f4..9d9bcb0e6157 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/DtoConverter.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/DtoConverter.java @@ -131,7 +131,6 @@ public static SnapshotDto asDto(Snapshot snapshot) { .withCreationDate(snapshot.getCreationDate()) .withDev(snapshot.isDev()) .withId(snapshot.getId()) - .withNamespace(snapshot.getNamespace()) .withWorkspaceId(snapshot.getWorkspaceId()) .withLinks(null); } diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineManager.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineManager.java index 9d0373ab4acd..8324cbc9240d 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineManager.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineManager.java @@ -492,13 +492,12 @@ public MachineImpl getDevMachine(String workspaceId) throws NotFoundException, M * @throws MachineException * if other error occur */ - public SnapshotImpl save(String machineId, String namespace, String description) + public SnapshotImpl save(String machineId, String description) throws NotFoundException, MachineException { final Instance machine = getInstance(machineId); final SnapshotImpl snapshot = SnapshotImpl.builder() .generateId() .setType(machine.getConfig().getType()) - .setNamespace(namespace) .setWorkspaceId(machine.getWorkspaceId()) .setDescription(description) .setDev(machine.getConfig().isDev()) @@ -521,8 +520,6 @@ public SnapshotImpl save(String machineId, String namespace, String description) * * @param machineId * id of machine for saving - * @param namespace - * snapshot namespace (e.g. owner) * @param description * optional description that should help to understand purpose of new snapshot in future * @return {@link SnapshotImpl} that will be stored in background @@ -533,14 +530,13 @@ public SnapshotImpl save(String machineId, String namespace, String description) * @throws MachineException * if other error occur */ - public SnapshotImpl saveSync(String machineId, String namespace, String description) throws MachineException, - SnapshotException, - NotFoundException { + public SnapshotImpl saveSync(String machineId, String description) throws MachineException, + SnapshotException, + NotFoundException { final Instance machine = getInstance(machineId); final SnapshotImpl snapshot = SnapshotImpl.builder() .generateId() .setType(machine.getConfig().getType()) - .setNamespace(namespace) .setWorkspaceId(machine.getWorkspaceId()) .setDescription(description) .setDev(machine.getConfig().isDev()) @@ -569,16 +565,14 @@ public SnapshotImpl getSnapshot(String snapshotId) throws NotFoundException, Sna /** * Gets list of Snapshots by project. * - * @param owner - * id of owner of machine * @param workspaceId * workspace binding * @return list of Snapshots * @throws SnapshotException * if error occur */ - public List getSnapshots(String owner, String workspaceId) throws SnapshotException { - return snapshotDao.findSnapshots(owner, workspaceId); + public List getSnapshots(String workspaceId) throws SnapshotException { + return snapshotDao.findSnapshots(workspaceId); } /** @@ -601,17 +595,15 @@ public void removeSnapshot(String snapshotId) throws NotFoundException, Snapshot } /** - * Removes Snapshots by owner, workspace and project. + * Removes Snapshots workspace. * - * @param owner - * owner of required snapshots * @param workspaceId * workspace binding * @throws SnapshotException * error occur */ - public void removeSnapshots(String owner, String workspaceId) throws SnapshotException { - for (SnapshotImpl snapshot : snapshotDao.findSnapshots(owner, workspaceId)) { + public void removeSnapshots(String workspaceId) throws SnapshotException { + for (SnapshotImpl snapshot : snapshotDao.findSnapshots(workspaceId)) { try { removeSnapshot(snapshot.getId()); } catch (NotFoundException ignored) { @@ -824,7 +816,7 @@ private SnapshotImpl doSaveMachine(SnapshotImpl snapshot, Instance machine) thro machine.getId()); snapshotWithKey = new SnapshotImpl(snapshot); - snapshotWithKey.setMachineSourceImpl(machine.saveToSnapshot(machine.getOwner())); + snapshotWithKey.setMachineSource(new MachineSourceImpl(machine.saveToSnapshot(machine.getOwner()))); try { SnapshotImpl oldSnapshot = snapshotDao.getSnapshot(snapshot.getWorkspaceId(), @@ -833,7 +825,7 @@ private SnapshotImpl doSaveMachine(SnapshotImpl snapshot, Instance machine) thro snapshotDao.removeSnapshot(oldSnapshot.getId()); machineInstanceProviders.getProvider(oldSnapshot.getType()).removeInstanceSnapshot(oldSnapshot.getMachineSource()); } catch (NotFoundException ignored) { - //DO nothing if we has no snapshots or when provider not found + //DO nothing if we has no snapshots or when provider not found } catch (SnapshotException se) { LOG.error("Failed to delete snapshot: {}, because {}", snapshot, diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineService.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineService.java index f6a35745f49c..be9f13111e45 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineService.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/MachineService.java @@ -32,7 +32,6 @@ import org.eclipse.che.api.machine.shared.dto.MachineProcessDto; import org.eclipse.che.api.machine.shared.dto.NewSnapshotDescriptor; import org.eclipse.che.api.machine.shared.dto.SnapshotDto; -import org.eclipse.che.commons.env.EnvironmentContext; import javax.inject.Inject; import javax.servlet.http.HttpServletResponse; @@ -146,7 +145,7 @@ public List getSnapshots(@ApiParam(value = "Workspace ID", required requiredNotNull(workspaceId, "Parameter workspace"); - final List snapshots = machineManager.getSnapshots(EnvironmentContext.getCurrent().getSubject().getUserId(), workspaceId); + final List snapshots = machineManager.getSnapshots(workspaceId); return snapshots.stream() .map(DtoConverter::asDto) @@ -175,9 +174,6 @@ public SnapshotDto saveSnapshot(@ApiParam(value = "Machine ID") requiredNotNull(newSnapshotDescriptor, "Snapshot description"); return linksInjector.injectLinks(DtoConverter.asDto(machineManager.save(machineId, - EnvironmentContext.getCurrent() - .getSubject() - .getUserId(), newSnapshotDescriptor.getDescription())), getServiceContext()); } diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java new file mode 100644 index 000000000000..ac286bdb9648 --- /dev/null +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * 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: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.machine.server.jpa; + +import com.google.inject.persist.Transactional; + +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException; +import org.eclipse.che.api.machine.server.exception.SnapshotException; +import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; +import org.eclipse.che.api.machine.server.spi.SnapshotDao; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import java.util.List; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +/** + * JPA based {@link SnapshotDao} implementation. + * + * @author Yevhenii Voevodin + */ +@Singleton +public class JpaSnapshotDao implements SnapshotDao { + + @Inject + private Provider managerProvider; + + @Override + @Transactional + public SnapshotImpl getSnapshot(String snapshotId) throws NotFoundException, SnapshotException { + requireNonNull(snapshotId, "Required non-null snapshotId"); + try { + final SnapshotImpl snapshot = managerProvider.get().find(SnapshotImpl.class, snapshotId); + if (snapshot == null) { + throw new NotFoundException(format("Snapshot with id '%s' doesn't exist", snapshotId)); + } + return snapshot; + } catch (RuntimeException x) { + throw new SnapshotException(x.getLocalizedMessage(), x); + } + } + + @Override + @Transactional + public SnapshotImpl getSnapshot(String workspaceId, String envName, String machineName) throws NotFoundException, SnapshotException { + requireNonNull(workspaceId, "Required non-null workspace id"); + requireNonNull(envName, "Required non-null environment name"); + requireNonNull(machineName, "Required non-null machine name"); + try { + return managerProvider.get() + .createNamedQuery("Snapshot.getByMachine", SnapshotImpl.class) + .setParameter("workspaceId", workspaceId) + .setParameter("envName", envName) + .setParameter("machineName", machineName) + .getSingleResult(); + } catch (NoResultException x) { + throw new NotFoundException(format("Snapshot for machine '%s:%s:%s' doesn't exist", + workspaceId, + envName, + machineName)); + } catch (RuntimeException x) { + throw new SnapshotException(x.getLocalizedMessage(), x); + } + } + + @Override + @Transactional + public List findSnapshots(String workspaceId) throws SnapshotException { + requireNonNull(workspaceId, "Required non-null workspace id"); + try { + return managerProvider.get() + .createNamedQuery("Snapshot.findSnapshots", SnapshotImpl.class) + .setParameter("workspaceId", workspaceId) + .getResultList(); + } catch (RuntimeException x) { + throw new SnapshotException(x.getLocalizedMessage(), x); + } + } + + @Override + public void saveSnapshot(SnapshotImpl snapshot) throws SnapshotException { + requireNonNull(snapshot, "Required non-null snapshot"); + try { + doSave(snapshot); + } catch (DuplicateKeyException x) { + throw new SnapshotException(format("Snapshot with id '%s' or for machine '%s:%s:%s' already exists", + snapshot.getId(), + snapshot.getWorkspaceId(), + snapshot.getEnvName(), + snapshot.getMachineName())); + } catch (RuntimeException x) { + throw new SnapshotException(x.getLocalizedMessage(), x); + } + } + + @Override + public void removeSnapshot(String snapshotId) throws NotFoundException, SnapshotException { + requireNonNull(snapshotId, "Required non-null snapshot id"); + try { + doRemove(snapshotId); + } catch (RuntimeException x) { + throw new SnapshotException(x.getLocalizedMessage(), x); + } + } + + @Transactional + protected void doSave(SnapshotImpl snapshot) { + managerProvider.get().persist(snapshot); + } + + @Transactional + protected void doRemove(String snapshotId) throws NotFoundException { + final EntityManager manager = managerProvider.get(); + final SnapshotImpl snapshot = manager.find(SnapshotImpl.class, snapshotId); + if (snapshot == null) { + throw new NotFoundException(format("Snapshot with id '%s' doesn't exist", snapshotId)); + } + manager.remove(snapshot); + } +} diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java index 1dd1603a2ca4..e55161a39ae2 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java @@ -13,40 +13,91 @@ import org.eclipse.che.api.core.model.machine.MachineConfig; import org.eclipse.che.api.core.model.machine.MachineSource; import org.eclipse.che.api.core.model.machine.Snapshot; +import org.eclipse.che.api.machine.server.spi.Instance; import org.eclipse.che.commons.lang.NameGenerator; +import javax.persistence.Basic; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Index; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; import java.util.Objects; -import static java.util.Objects.requireNonNull; - /** - * Saved state of {@link org.eclipse.che.api.machine.server.spi.Instance}. + * Saved state of {@link Instance}. * * @author Yevhenii Voevodin */ +@Entity(name = "Snapshot") +@NamedQueries( + { + @NamedQuery(name = "Snapshot.getByMachine", + query = "SELECT snapshot " + + "FROM Snapshot snapshot " + + "WHERE snapshot.workspaceId = :workspaceId" + + " AND snapshot.envName = :envName" + + " AND snapshot.machineName = :machineName"), + @NamedQuery(name = "Snapshot.findSnapshots", + query = "SELECT snapshot " + + "FROM Snapshot snapshot " + + "WHERE snapshot.workspaceId = :workspaceId") + } +) +@Table(indexes = @Index(columnList = "workspaceId, envName, machineName", unique = true)) public class SnapshotImpl implements Snapshot { public static SnapshotBuilder builder() { return new SnapshotBuilder(); } - private final String workspaceId; - private final String machineName; - private final String envName; - private final String id; - private final String type; - private final String namespace; - private final boolean isDev; - private final long creationDate; + @Id + private String id; + + @Basic + private String workspaceId; + + @Basic + private String machineName; + + @Basic + private String envName; + + @Basic + private String type; - private String description; + @Basic + private boolean isDev; + + @Basic + private long creationDate; + + @Basic + private String description; + + @Embedded private MachineSourceImpl machineSource; + public SnapshotImpl() {} + public SnapshotImpl(Snapshot snapshot) { this(snapshot.getId(), snapshot.getType(), null, - snapshot.getNamespace(), + snapshot.getCreationDate(), + snapshot.getWorkspaceId(), + snapshot.getDescription(), + snapshot.isDev(), + snapshot.getMachineName(), + snapshot.getEnvName()); + } + + public SnapshotImpl(SnapshotImpl snapshot) { + this(snapshot.getId(), + snapshot.getType(), + snapshot.getMachineSource(), snapshot.getCreationDate(), snapshot.getWorkspaceId(), snapshot.getDescription(), @@ -58,19 +109,17 @@ public SnapshotImpl(Snapshot snapshot) { public SnapshotImpl(String id, String type, MachineSource machineSource, - String namespace, long creationDate, String workspaceId, String description, boolean isDev, String machineName, String envName) { - this.id = requireNonNull(id, "Required non-null snapshot id"); - this.type = requireNonNull(type, "Required non-null snapshot type"); - this.namespace = requireNonNull(namespace, "Required non-null snapshot namespace"); - this.workspaceId = requireNonNull(workspaceId, "Required non-null workspace id for snapshot"); - this.machineName = requireNonNull(machineName, "Required non-null snapshot machine name"); - this.envName = requireNonNull(envName, "Required non-null environment name for snapshot"); + this.id = id; + this.type = type; + this.workspaceId = workspaceId; + this.machineName = machineName; + this.envName = envName; this.machineSource = machineSource != null ? new MachineSourceImpl(machineSource) : null; this.description = description; this.isDev = isDev; @@ -82,18 +131,25 @@ public String getId() { return id; } + public void setId(String id) { + this.id = id; + } + @Override public String getType() { return type; } + public void setType(String type) { + this.type = type; + } + public MachineSourceImpl getMachineSource() { return machineSource; } - @Override - public String getNamespace() { - return namespace; + public void setMachineSource(MachineSourceImpl machineSource) { + this.machineSource = machineSource; } @Override @@ -101,37 +157,53 @@ public long getCreationDate() { return creationDate; } + public void setCreationDate(long creationDate) { + this.creationDate = creationDate; + } + @Override public String getWorkspaceId() { return workspaceId; } + public void setWorkspaceId(String workspaceId) { + this.workspaceId = workspaceId; + } + @Override public String getMachineName() { return machineName; } + public void setMachineName(String machineName) { + this.machineName = machineName; + } + @Override public String getEnvName() { return envName; } + public void setEnvName(String envName) { + this.envName = envName; + } + @Override public String getDescription() { return description; } + public void setDescription(String description) { + this.description = description; + } + @Override public boolean isDev() { return this.isDev; } - public void setMachineSourceImpl(MachineSource machineSource) { - this.machineSource = machineSource != null ? new MachineSourceImpl(machineSource) : null; - } - - public void setDescription(String description) { - this.description = description; + public void setDev(boolean dev) { + isDev = dev; } @Override @@ -148,7 +220,6 @@ public boolean equals(Object o) { && Objects.equals(id, snapshot.id) && Objects.equals(type, snapshot.type) && Objects.equals(machineSource, snapshot.machineSource) - && Objects.equals(namespace, snapshot.namespace) && Objects.equals(workspaceId, snapshot.workspaceId) && Objects.equals(description, snapshot.description) && Objects.equals(machineName, snapshot.machineName) @@ -163,7 +234,6 @@ public int hashCode() { hash = hash * 31 + Objects.hashCode(id); hash = hash * 31 + Objects.hashCode(type); hash = hash * 31 + Objects.hashCode(machineSource); - hash = hash * 31 + Objects.hashCode(namespace); hash = hash * 31 + Objects.hashCode(workspaceId); hash = hash * 31 + Objects.hashCode(description); hash = hash * 31 + Objects.hashCode(machineName); @@ -177,7 +247,6 @@ public String toString() { "id='" + id + '\'' + ", type='" + type + '\'' + ", machineSource=" + machineSource + - ", namespace='" + namespace + '\'' + ", creationDate=" + creationDate + ", isDev=" + isDev + ", description='" + description + '\'' + @@ -192,16 +261,15 @@ public String toString() { */ public static class SnapshotBuilder { - private String workspaceId; - private String machineName; - private String envName; - private String id; - private String type; - private String namespace; - private String description; + private String workspaceId; + private String machineName; + private String envName; + private String id; + private String type; + private String description; private MachineSource machineSource; - private boolean isDev; - private long creationDate; + private boolean isDev; + private long creationDate; public SnapshotBuilder fromConfig(MachineConfig machineConfig) { machineName = machineConfig.getName(); @@ -239,11 +307,6 @@ public SnapshotBuilder setType(String type) { return this; } - public SnapshotBuilder setNamespace(String namespace) { - this.namespace = namespace; - return this; - } - public SnapshotBuilder setDescription(String description) { this.description = description; return this; @@ -270,7 +333,7 @@ public SnapshotBuilder useCurrentCreationDate() { } public SnapshotImpl build() { - return new SnapshotImpl(id, type, machineSource, namespace, creationDate, workspaceId, description, isDev, machineName, envName); + return new SnapshotImpl(id, type, machineSource, creationDate, workspaceId, description, isDev, machineName, envName); } } } diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java index 4b289e236e61..4c65c312682f 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java @@ -65,17 +65,15 @@ public interface SnapshotDao { void saveSnapshot(SnapshotImpl snapshot) throws SnapshotException; /** - * Find snapshots by namespaces, workspace, project + * Find snapshots by workspace. * - * @param namespace - * snapshot namespace(e.g. owner). * @param workspaceId * workspace specified in desired snapshot, optional * @return list of snapshot that satisfy provided queries, or empty list if no desired snapshots found * @throws SnapshotException * if error occurs */ - List findSnapshots(String namespace, String workspaceId) throws SnapshotException; + List findSnapshots(String workspaceId) throws SnapshotException; /** * Remove snapshot by id diff --git a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/MachineManagerTest.java b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/MachineManagerTest.java index 2f32de364298..02b23622a2ec 100644 --- a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/MachineManagerTest.java +++ b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/MachineManagerTest.java @@ -337,7 +337,6 @@ private SnapshotImpl createSnapshot() { .fromConfig(createMachineConfig()) .setWorkspaceId(WS_ID) .setEnvName(ENVIRONMENT_NAME) - .setNamespace(NAMESPACE) .setMachineSource(new MachineSourceImpl("snapshot").setLocation("location")) .setDev(true) .build(); diff --git a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java index 3b15f5e118af..c9f5313dc0e6 100644 --- a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java +++ b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/jpa/JpaTckModule.java @@ -19,7 +19,10 @@ import org.eclipse.che.api.machine.server.recipe.RecipeImpl; import org.eclipse.che.api.machine.server.spi.RecipeDao; import org.eclipse.che.api.user.server.model.impl.UserImpl; +import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; +import org.eclipse.che.api.machine.server.spi.SnapshotDao; import org.eclipse.che.commons.test.tck.TckModule; +import org.eclipse.che.commons.test.tck.repository.JpaTckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; @@ -39,8 +42,10 @@ protected void configure() { bind(JpaInitializer.class).asEagerSingleton(); bind(new TypeLiteral>() {}).to(RecipeJpaTckRepository.class); + bind(new TypeLiteral>() {}).toInstance(new JpaTckRepository<>(SnapshotImpl.class)); bind(RecipeDao.class).to(JpaRecipeDao.class); + bind(SnapshotDao.class).to(JpaSnapshotDao.class); } @Transactional diff --git a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java new file mode 100644 index 000000000000..2b1913051633 --- /dev/null +++ b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java @@ -0,0 +1,220 @@ +/******************************************************************************* + * Copyright (c) 2012-2016 Codenvy, S.A. + * 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: + * Codenvy, S.A. - initial API and implementation + *******************************************************************************/ +package org.eclipse.che.api.machine.server.spi.tck; + +import com.google.inject.Inject; + +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.machine.server.exception.SnapshotException; +import org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl; +import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; +import org.eclipse.che.api.machine.server.spi.SnapshotDao; +import org.eclipse.che.commons.test.tck.TckModuleFactory; +import org.eclipse.che.commons.test.tck.repository.TckRepository; +import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.HashSet; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +/** + * Tests {@link SnapshotDao} contract. + * + * @author Yevhenii Voevodin + */ +@Guice(moduleFactory = TckModuleFactory.class) +@Test(suiteName = SnapshotDaoTest.SUITE_NAME) +public class SnapshotDaoTest { + + public static final String SUITE_NAME = "SnapshotDaoTest"; + + private static final int SNAPSHOTS_SIZE = 6; + + private SnapshotImpl[] snapshots; + + @Inject + private SnapshotDao snapshotDao; + + @Inject + private TckRepository snaphotRepo; + + @BeforeMethod + private void createSnapshots() throws TckRepositoryException { + snapshots = new SnapshotImpl[SNAPSHOTS_SIZE]; + for (int i = 0; i < SNAPSHOTS_SIZE; i++) { + snapshots[i] = createSnapshot("snapshot-" + i, + "workspace-" + i / 3, // 3 snapshot share the same workspace id + "environment-" + i / 2, // 2 snapshots share the same env name + "machine-" + i); + } + snaphotRepo.createAll(asList(snapshots)); + } + + @AfterMethod + private void removeSnapshots() throws TckRepositoryException { + snaphotRepo.removeAll(); + } + + @Test + public void shouldGetSnapshotById() throws Exception { + final SnapshotImpl snapshot = snapshots[0]; + + assertEquals(snapshotDao.getSnapshot(snapshot.getId()), snapshot); + } + + @Test(expectedExceptions = NotFoundException.class) + public void shouldThrowNotFoundExceptionWhenGettingNonExistingSnapshot() throws Exception { + snapshotDao.getSnapshot("non-existing-snapshot"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void shouldThrowNpeWhenGettingSnapshotByNullId() throws Exception { + snapshotDao.getSnapshot(null); + } + + @Test + public void shouldGetSnapshotByWorkspaceEnvironmentAndMachineName() throws Exception { + final SnapshotImpl snapshot = snapshots[0]; + + assertEquals(snapshotDao.getSnapshot(snapshot.getWorkspaceId(), + snapshot.getEnvName(), + snapshot.getMachineName()), snapshot); + } + + @Test(expectedExceptions = NotFoundException.class, dataProvider = "missingSnapshots") + public void shouldThrowNotFoundExceptionWhenSnapshotMissing(String wsId, String envName, String machineName) throws Exception { + snapshotDao.getSnapshot(wsId, envName, machineName); + } + + @Test(expectedExceptions = NullPointerException.class, dataProvider = "nullParameterVariations") + public void shouldThrowNpeWhenAnyOfGetSnapshotParametersIsNull(String wsId, String envName, String machineName) throws Exception { + snapshotDao.getSnapshot(wsId, envName, machineName); + } + + @Test + public void shouldFindSnapshotsByWorkspaceAndNamespace() throws Exception { + final SnapshotImpl snapshot = snapshots[0]; + + final List found = snapshotDao.findSnapshots(snapshot.getWorkspaceId()); + + assertEquals(new HashSet<>(found), new HashSet<>(asList(snapshots[0], snapshots[1], snapshots[2]))); + } + + @Test(expectedExceptions = NullPointerException.class) + public void shouldThrowNpeWhenSearchingSnapshotsByNullWorkspaceId() throws Exception { + snapshotDao.findSnapshots(null); + } + + @Test(dependsOnMethods = "shouldGetSnapshotById") + public void shouldSaveSnapshot() throws Exception { + final SnapshotImpl newSnapshot = createSnapshot("new-snapshot", + "workspace-id", + "env-name", + "machine-name"); + + snapshotDao.saveSnapshot(newSnapshot); + + assertEquals(snapshotDao.getSnapshot(newSnapshot.getId()), new SnapshotImpl(newSnapshot)); + } + + @Test(expectedExceptions = SnapshotException.class) + public void shouldNotSaveSnapshotWithReservedId() throws Exception { + final SnapshotImpl snapshot = snapshots[0]; + snapshot.setWorkspaceId("new-workspace"); + snapshot.setEnvName("new-env"); + snapshot.setMachineName("new-machine"); + + snapshotDao.saveSnapshot(snapshot); + } + + @Test(expectedExceptions = SnapshotException.class) + public void shouldNotSaveSnapshotForMachineIfSnapshotForSuchMachineAlreadyExists() throws Exception { + final SnapshotImpl snapshot = snapshots[0]; + snapshot.setId("new-id"); + + snapshotDao.saveSnapshot(snapshot); + } + + @Test(expectedExceptions = NullPointerException.class) + public void shouldThrowNpeWhenSavingNull() throws Exception { + snapshotDao.saveSnapshot(null); + } + + @Test(expectedExceptions = NotFoundException.class, + dependsOnMethods = "shouldThrowNotFoundExceptionWhenGettingNonExistingSnapshot") + public void shouldRemoveSnapshot() throws Exception { + final SnapshotImpl snapshot = snapshots[0]; + + try { + snapshotDao.removeSnapshot(snapshot.getId()); + } catch (NotFoundException x) { + fail("Should remove snapshot"); + } + + snapshotDao.getSnapshot(snapshot.getId()); + } + + @Test(expectedExceptions = NotFoundException.class) + public void shouldThrowNotFoundExceptionWhenRemovingNonExistingSnapshot() throws Exception { + snapshotDao.removeSnapshot("non-existing-id"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void shouldThrowNpeWhenRemovingNull() throws Exception { + snapshotDao.removeSnapshot(null); + } + + @DataProvider(name = "missingSnapshots") + public Object[][] missingSnapshots() { + final SnapshotImpl snapshot = snapshots[0]; + return new Object[][] { + {"non-existing-workspace-id", snapshot.getEnvName(), snapshot.getMachineName()}, + {snapshot.getWorkspaceId(), "non-existing-env", snapshot.getMachineName()}, + {snapshot.getWorkspaceId(), snapshot.getEnvName(), "non-existing-machine-name"} + }; + } + + @DataProvider(name = "nullParameterVariations") + public Object[][] nullParameterVariations() { + final SnapshotImpl snapshot = snapshots[0]; + return new Object[][] { + {null, snapshot.getEnvName(), snapshot.getMachineName()}, + {snapshot.getWorkspaceId(), null, snapshot.getMachineName()}, + {snapshot.getWorkspaceId(), snapshot.getEnvName(), null} + }; + } + + private static SnapshotImpl createSnapshot(String id, + String workspaceId, + String envName, + String machineName) { + return SnapshotImpl.builder() + .setId(id) + .setType(id + "type") + .setMachineSource(new MachineSourceImpl(id + "source-type", + id + "source-location", + id + "source-content")) + .setCreationDate(System.currentTimeMillis()) + .setDev(true) + .setWorkspaceId(workspaceId) + .setEnvName(envName) + .setMachineName(machineName) + .build(); + } +} diff --git a/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml b/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml index b5b8a2393d66..767dcc00fc4c 100644 --- a/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/che-core-api-machine/src/test/resources/META-INF/persistence.xml @@ -16,6 +16,7 @@ org.eclipse.persistence.jpa.PersistenceProvider org.eclipse.che.api.machine.server.recipe.RecipeImpl + org.eclipse.che.api.machine.server.model.impl.SnapshotImpl org.eclipse.che.api.machine.server.model.impl.AclEntryImpl org.eclipse.che.api.user.server.model.impl.UserImpl true diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java index 6d1cb6391b37..0f28c5d006f8 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java @@ -179,7 +179,6 @@ public static SnapshotDto asDto(Snapshot snapshot) { .withCreationDate(snapshot.getCreationDate()) .withDescription(snapshot.getDescription()) .withDev(snapshot.isDev()) - .withNamespace(snapshot.getNamespace()) .withType(snapshot.getType()) .withWorkspaceId(snapshot.getWorkspaceId()) .withEnvName(snapshot.getEnvName()) diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index 9bf1ae44cd47..6c694a9c89bb 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -510,7 +510,7 @@ public List getSnapshot(String workspaceId) throws ServerException requireNonNull(workspaceId, "Required non-null workspace id"); // check if workspace exists final WorkspaceImpl workspace = workspaceDao.get(workspaceId); - return machineManager.getSnapshots(workspace.getNamespace(), workspaceId); + return machineManager.getSnapshots(workspaceId); } /** Asynchronously starts given workspace. */ @@ -625,7 +625,7 @@ boolean createSnapshotSync(WorkspaceRuntimeImpl runtime, String namespace, Strin String devMachineSnapshotFailMessage = null; for (MachineImpl machine : runtime.getMachines()) { try { - machineManager.saveSync(machine.getId(), namespace, runtime.getActiveEnv()); + machineManager.saveSync(machine.getId(), runtime.getActiveEnv()); } catch (ApiException apiEx) { if (machine.getConfig().isDev()) { devMachineSnapshotFailMessage = apiEx.getLocalizedMessage(); diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index cdcace6b0720..a62b6ff27756 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -239,7 +239,7 @@ public void delete(@ApiParam("The workspace id") @PathParam("id") String id) thr ConflictException, ForbiddenException { if (!workspaceManager.getSnapshot(id).isEmpty()) { - machineManager.removeSnapshots(workspaceManager.getWorkspace(id).getNamespace(), id); + machineManager.removeSnapshots(id); } workspaceManager.removeWorkspace(id); } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java index ea02bb624db9..6151674f867c 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java @@ -14,6 +14,7 @@ import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; +import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.commons.lang.NameGenerator; import javax.persistence.Basic; @@ -21,14 +22,18 @@ import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.Id; +import javax.persistence.JoinColumn; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -76,6 +81,13 @@ public static WorkspaceImplBuilder builder() { @Basic private boolean isTemporary; + // This mapping is present here just for generation of the constraint between + // snapshots and workspace, it's impossible to do so on snapshot side + // as workspace and machine are different modules and cyclic reference will appear + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "workspaceId", insertable = false, updatable = false) + private List snapshots; + @Transient private WorkspaceStatus status = STOPPED; diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java index 3b58e0939dd1..b9342f34a1ed 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java @@ -346,7 +346,7 @@ public void shouldBeAbleToStartWorkspaceById() throws Exception { public void shouldRecoverWorkspaceIfAutoRestoreAttributeIsSetAndSnapshotExists() throws Exception { final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); workspace.getAttributes().put(AUTO_RESTORE_FROM_SNAPSHOT, "true"); - when(machineManager.getSnapshots(any(), any())).thenReturn(singletonList(mock(SnapshotImpl.class))); + when(machineManager.getSnapshots( any())).thenReturn(singletonList(mock(SnapshotImpl.class))); when(workspaceDao.get(workspace.getId())).thenReturn(workspace); when(runtimes.get(any())).thenThrow(new NotFoundException("")); @@ -516,7 +516,7 @@ public void shouldStopWorkspaceEventIfSnapshotCreationFailed() throws Exception final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); when(runtimes.get(any())).thenReturn(descriptor); // force createSnapshotSync to return true - when(machineManager.saveSync(anyString(), anyString(), anyString())).thenThrow(new MachineException("test")); + when(machineManager.saveSync(anyString(), anyString())).thenThrow(new MachineException("test")); workspaceManager.stopWorkspace(workspace.getId()); @@ -555,7 +555,7 @@ public void shouldBeAbleToGetSnapshots() throws Exception { final String wsId = "workspace123"; final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE, "account"); when(workspaceDao.get(wsId)).thenReturn(workspace); - when(machineManager.getSnapshots(NAMESPACE, wsId)).thenReturn(singletonList(any())); + when(machineManager.getSnapshots(wsId)).thenReturn(singletonList(any())); final List snapshots = workspaceManager.getSnapshot("workspace123"); @@ -590,7 +590,7 @@ public void shouldStartWorkspaceFromSnapshotUsingDefaultValueForAutoRestore() th false, true)); final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); - when(machineManager.getSnapshots(any(), any())).thenReturn(singletonList(mock(SnapshotImpl.class))); + when(machineManager.getSnapshots(any())).thenReturn(singletonList(mock(SnapshotImpl.class))); when(workspaceDao.get(workspace.getId())).thenReturn(workspace); when(runtimes.get(any())).thenThrow(new NotFoundException("")); diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java index adaf0724b7e7..328985dce0f4 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java @@ -295,7 +295,7 @@ public void shouldDeleteWorkspace() throws Exception { .delete(SECURE_PATH + "/workspace/" + workspace.getId()); assertEquals(response.getStatusCode(), 204); - verify(machineManager).removeSnapshots(NAMESPACE, workspace.getId()); + verify(machineManager).removeSnapshots(workspace.getId()); verify(wsManager).removeWorkspace(workspace.getId()); } diff --git a/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml b/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml index ce38425a6c63..02047740fc10 100644 --- a/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml +++ b/wsmaster/che-core-api-workspace/src/test/resources/META-INF/persistence.xml @@ -25,6 +25,7 @@ org.eclipse.che.api.machine.server.model.impl.MachineConfigImpl org.eclipse.che.api.machine.server.model.impl.CommandImpl org.eclipse.che.api.machine.server.model.impl.AclEntryImpl + org.eclipse.che.api.machine.server.model.impl.SnapshotImpl org.eclipse.che.api.user.server.model.impl.UserImpl true diff --git a/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java b/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java index 968464013149..94710a88b576 100644 --- a/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java +++ b/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.api.local; +import com.google.common.annotations.VisibleForTesting; import com.google.common.reflect.TypeToken; import org.eclipse.che.api.core.NotFoundException; @@ -29,11 +30,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import static java.lang.String.format; import static java.util.Collections.singletonMap; +import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; /** @@ -44,8 +45,10 @@ @Singleton public class LocalSnapshotDaoImpl implements SnapshotDao { - private final Map snapshots; - private final LocalStorage snapshotStorage; + @VisibleForTesting + final Map snapshots; + + private final LocalStorage snapshotStorage; @Inject public LocalSnapshotDaoImpl(LocalStorageFactory storageFactory) throws IOException { @@ -56,6 +59,9 @@ public LocalSnapshotDaoImpl(LocalStorageFactory storageFactory) throws IOExcepti @Override public synchronized SnapshotImpl getSnapshot(String workspaceId, String envName, String machineName) throws NotFoundException, SnapshotException { + requireNonNull(workspaceId, "Required non-null workspace id"); + requireNonNull(envName, "Required non-null environment name"); + requireNonNull(machineName, "Required non-null machine name"); final Optional snapshotOpt = doGetSnapshot(workspaceId, envName, machineName); if (!snapshotOpt.isPresent()) { throw new NotFoundException(format("Snapshot with workspace id '%s', environment name '%s', machine name %s doesn't exist", @@ -66,6 +72,7 @@ public synchronized SnapshotImpl getSnapshot(String workspaceId, String envName, @Override public synchronized SnapshotImpl getSnapshot(String snapshotId) throws NotFoundException, SnapshotException { + requireNonNull(snapshotId, "Required non-null snapshot id"); final SnapshotImpl snapshot = snapshots.get(snapshotId); if (snapshot == null) { throw new NotFoundException("Snapshot with id '" + snapshotId + "' doesn't exist"); @@ -75,24 +82,35 @@ public synchronized SnapshotImpl getSnapshot(String snapshotId) throws NotFoundE @Override public synchronized void saveSnapshot(SnapshotImpl snapshot) throws SnapshotException { - Objects.requireNonNull(snapshot, "Required non-null snapshot"); + requireNonNull(snapshot, "Required non-null snapshot"); + if (snapshots.containsKey(snapshot.getWorkspaceId())) { + throw new SnapshotException(format("Snapshot with id '%s' already exists", snapshot.getId())); + } final Optional opt = doGetSnapshot(snapshot.getWorkspaceId(), snapshot.getEnvName(), snapshot.getMachineName()); if (opt.isPresent()) { - snapshots.remove(opt.get().getId()); + throw new SnapshotException(format("Snapshot for machine '%s:%s:%s' already exists", + snapshot.getWorkspaceId(), + snapshot.getEnvName(), + snapshot.getMachineName())); } snapshots.put(snapshot.getId(), snapshot); } @Override - public synchronized List findSnapshots(String namespace, String workspaceId) throws SnapshotException { + public synchronized List findSnapshots(String workspaceId) throws SnapshotException { + requireNonNull(workspaceId, "Required non-null workspace id"); return snapshots.values() .stream() - .filter(snapshot -> snapshot.getNamespace().equals(namespace) && snapshot.getWorkspaceId().equals(workspaceId)) + .filter(snapshot -> snapshot.getWorkspaceId().equals(workspaceId)) .collect(toList()); } @Override public synchronized void removeSnapshot(String snapshotId) throws NotFoundException, SnapshotException { + requireNonNull(snapshotId, "Required non-null snapshot id"); + if (!snapshots.containsKey(snapshotId)) { + throw new NotFoundException(format("Snapshot with id '%s' doesn't exist", snapshotId)); + } snapshots.remove(snapshotId); } diff --git a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalRecipeTckRepository.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalRecipeTckRepository.java deleted file mode 100644 index 5d64fecdc9ce..000000000000 --- a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalRecipeTckRepository.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * 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: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.local; - -import org.eclipse.che.api.machine.server.recipe.RecipeImpl; -import org.eclipse.che.commons.test.tck.repository.TckRepository; -import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; - -import javax.inject.Inject; -import java.util.Collection; - -/** - * @author Anton Korneta - */ -public class LocalRecipeTckRepository implements TckRepository { - - @Inject - private LocalRecipeDaoImpl recipeDao; - - @Override - public void createAll(Collection recipes) throws TckRepositoryException { - for (RecipeImpl recipe : recipes) { - recipeDao.recipes.put(recipe.getId(), new RecipeImpl(recipe)); - } - } - - @Override - public void removeAll() throws TckRepositoryException { - recipeDao.recipes.clear(); - } -} diff --git a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalSnapshotDaoTest.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalSnapshotDaoTest.java index 3c04c4c99d80..7a29ebd30412 100644 --- a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalSnapshotDaoTest.java +++ b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalSnapshotDaoTest.java @@ -84,7 +84,6 @@ private SnapshotImpl createSnapshot() { .generateId() .setType("docker") .setMachineSource(machineSource) - .setNamespace("user123") .setWorkspaceId("workspace123") .setMachineName("machine123") .setEnvName("env123") diff --git a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalStackTcKRepository.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalStackTcKRepository.java deleted file mode 100644 index e14bf289267e..000000000000 --- a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalStackTcKRepository.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * 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: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.local; - -import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl; -import org.eclipse.che.commons.test.tck.repository.TckRepository; -import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; - -import javax.inject.Inject; -import java.util.Collection; - -/** - * @author Yevhenii Voevodin - */ -public class LocalStackTcKRepository implements TckRepository { - - @Inject - private LocalStackDaoImpl stackDao; - - @Override - public void createAll(Collection entities) throws TckRepositoryException { - for (StackImpl stack : entities) { - stackDao.stacks.put(stack.getId(), new StackImpl(stack)); - } - } - - @Override - public void removeAll() throws TckRepositoryException { - stackDao.stacks.clear(); - } -} diff --git a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalTckModule.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalTckModule.java index 0f9af0c236a0..5c31636fbf24 100644 --- a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalTckModule.java +++ b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalTckModule.java @@ -10,14 +10,17 @@ *******************************************************************************/ package org.eclipse.che.api.local; +import com.google.inject.Inject; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; import org.eclipse.che.api.local.storage.LocalStorage; import org.eclipse.che.api.local.storage.LocalStorageFactory; import org.eclipse.che.api.local.storage.stack.StackLocalStorage; +import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.recipe.RecipeImpl; import org.eclipse.che.api.machine.server.spi.RecipeDao; +import org.eclipse.che.api.machine.server.spi.SnapshotDao; import org.eclipse.che.api.user.server.model.impl.ProfileImpl; import org.eclipse.che.api.user.server.model.impl.UserImpl; import org.eclipse.che.api.user.server.spi.PreferenceDao; @@ -67,19 +70,68 @@ public void configure() { bind(new TypeLiteral>() {}).annotatedWith(Names.named("codenvy.local.infrastructure.users")).toInstance(emptySet()); - bind(new TypeLiteral>() {}).to(LocalUserTckRepository.class).in(Singleton.class); - bind(new TypeLiteral>() {}).to(LocalProfileTckRepository.class).in(Singleton.class); - bind(new TypeLiteral>() {}).to(LocalRecipeTckRepository.class).in(Singleton.class); - bind(new TypeLiteral>() {}).to(LocalWorkspaceTckRepository.class).in(Singleton.class); - bind(new TypeLiteral>>>() {}).to(LocalPreferenceTckRepository.class) - .in(Singleton.class); - bind(new TypeLiteral>(){}).to(LocalStackTcKRepository.class).in(Singleton.class); - - bind(UserDao.class).to(LocalUserDaoImpl.class).in(Singleton.class); - bind(ProfileDao.class).to(LocalProfileDaoImpl.class).in(Singleton.class); - bind(RecipeDao.class).to(LocalRecipeDaoImpl.class).in(Singleton.class); - bind(WorkspaceDao.class).to(LocalWorkspaceDaoImpl.class).in(Singleton.class); - bind(PreferenceDao.class).to(LocalPreferenceDaoImpl.class).in(Singleton.class); - bind(StackDao.class).to(LocalStackDaoImpl.class).in(Singleton.class); + bind(new TypeLiteral>() {}).to(LocalUserTckRepository.class); + bind(new TypeLiteral>() {}).to(LocalProfileTckRepository.class); + bind(new TypeLiteral>() {}).to(LocalRecipeTckRepository.class); + bind(new TypeLiteral>() {}).to(LocalWorkspaceTckRepository.class); + bind(new TypeLiteral>>>() {}).to(LocalPreferenceTckRepository.class); + bind(new TypeLiteral>() {}).to(LocalStackTckRepository.class); + bind(new TypeLiteral>() {}).to(SnapshotTckRepository.class); + + bind(UserDao.class).to(LocalUserDaoImpl.class); + bind(ProfileDao.class).to(LocalProfileDaoImpl.class); + bind(RecipeDao.class).to(LocalRecipeDaoImpl.class); + bind(WorkspaceDao.class).to(LocalWorkspaceDaoImpl.class); + bind(PreferenceDao.class).to(LocalPreferenceDaoImpl.class); + bind(StackDao.class).to(LocalStackDaoImpl.class); + bind(SnapshotDao.class).to(LocalSnapshotDaoImpl.class); + } + + @Singleton + private static class SnapshotTckRepository extends LocalTckRepository { + @Inject + public SnapshotTckRepository(LocalSnapshotDaoImpl snapshotDao) { + super(snapshotDao.snapshots, SnapshotImpl::getId); + } + } + + @Singleton + private static class LocalUserTckRepository extends LocalTckRepository { + @Inject + public LocalUserTckRepository(LocalUserDaoImpl userDao) { + super(userDao.users, UserImpl::getId); + } + } + + @Singleton + private static class LocalProfileTckRepository extends LocalTckRepository { + @Inject + public LocalProfileTckRepository(LocalProfileDaoImpl profileDao) { + super(profileDao.profiles, ProfileImpl::getUserId); + } + } + + @Singleton + private static class LocalRecipeTckRepository extends LocalTckRepository { + @Inject + public LocalRecipeTckRepository(LocalRecipeDaoImpl recipeDao) { + super(recipeDao.recipes, RecipeImpl::getId); + } + } + + @Singleton + private static class LocalWorkspaceTckRepository extends LocalTckRepository { + @Inject + public LocalWorkspaceTckRepository(LocalWorkspaceDaoImpl workspaceDao) { + super(workspaceDao.workspaces, WorkspaceImpl::getId); + } + } + + @Singleton + private static class LocalStackTckRepository extends LocalTckRepository { + @Inject + public LocalStackTckRepository(LocalStackDaoImpl stackDao) { + super(stackDao.stacks, StackImpl::getId); + } } } diff --git a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalProfileTckRepository.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalTckRepository.java similarity index 54% rename from wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalProfileTckRepository.java rename to wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalTckRepository.java index 86f9b38d8030..d78d95bba8b1 100644 --- a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalProfileTckRepository.java +++ b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalTckRepository.java @@ -10,30 +10,39 @@ *******************************************************************************/ package org.eclipse.che.api.local; -import org.eclipse.che.api.user.server.model.impl.ProfileImpl; import org.eclipse.che.commons.test.tck.repository.TckRepository; import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; -import javax.inject.Inject; import java.util.Collection; +import java.util.Map; +import java.util.function.Function; /** + * Simplifies implementation of TckRepository for local data access objects. + * + * @param + * the type of the repository * @author Yevhenii Voevodin */ -public class LocalProfileTckRepository implements TckRepository { +public class LocalTckRepository implements TckRepository { + + private final Map storage; + private final Function keyMapper; - @Inject - private LocalProfileDaoImpl profileDao; + public LocalTckRepository(Map storage, Function keyMapper) { + this.storage = storage; + this.keyMapper = keyMapper; + } @Override - public void createAll(Collection profiles) throws TckRepositoryException { - for (ProfileImpl profile : profiles) { - profileDao.profiles.put(profile.getUserId(), new ProfileImpl(profile)); + public void createAll(Collection entities) throws TckRepositoryException { + for (T entity : entities) { + storage.put(keyMapper.apply(entity), entity); } } @Override public void removeAll() throws TckRepositoryException { - profileDao.profiles.clear(); + storage.clear(); } } diff --git a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalUserTckRepository.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalUserTckRepository.java deleted file mode 100644 index 0159e543b37b..000000000000 --- a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalUserTckRepository.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * 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: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.local; - -import org.eclipse.che.api.user.server.model.impl.UserImpl; -import org.eclipse.che.commons.test.tck.repository.TckRepository; - -import javax.inject.Inject; -import java.util.Collection; - -/** - * @author Yevhenii Voevodin - */ -public class LocalUserTckRepository implements TckRepository { - - @Inject - private LocalUserDaoImpl userDao; - - @Override - public void createAll(Collection entities) { - for (UserImpl user : entities) { - userDao.users.put(user.getId(), new UserImpl(user)); - } - } - - @Override - public void removeAll() { - userDao.users.clear(); - } -} diff --git a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalWorkspaceTckRepository.java b/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalWorkspaceTckRepository.java deleted file mode 100644 index ff3d8880ee8e..000000000000 --- a/wsmaster/wsmaster-local/src/test/java/org/eclipse/che/api/local/LocalWorkspaceTckRepository.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2016 Codenvy, S.A. - * 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: - * Codenvy, S.A. - initial API and implementation - *******************************************************************************/ -package org.eclipse.che.api.local; - -import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; -import org.eclipse.che.commons.test.tck.repository.TckRepository; -import org.eclipse.che.commons.test.tck.repository.TckRepositoryException; - -import javax.inject.Inject; -import java.util.Collection; - -/** - * @author Yevhenii Voevodin - */ -public class LocalWorkspaceTckRepository implements TckRepository { - - @Inject - private LocalWorkspaceDaoImpl workspaceDao; - - @Override - public void createAll(Collection entities) throws TckRepositoryException { - for (WorkspaceImpl workspace : entities) { - workspaceDao.workspaces.put(workspace.getId(), new WorkspaceImpl(workspace)); - } - } - - @Override - public void removeAll() throws TckRepositoryException { - workspaceDao.workspaces.clear(); - } -}