From 23bbe08893d6cb08a3a4d4ef4257d0bfb8a43b4d Mon Sep 17 00:00:00 2001 From: Bruk Ori Date: Wed, 11 Sep 2024 11:41:38 +0300 Subject: [PATCH] [#12] Extend method logic Signed-off-by: Ori Bruk --- .../java/info/frostfs/sdk/FrostFSClient.java | 17 +- .../info/frostfs/sdk/enums/WaitExpects.java | 6 + .../sdk/exceptions/ResponseException.java | 16 + .../sdk/exceptions/TimeoutException.java | 6 + .../frostfs/sdk/jdo/ClientEnvironment.java | 8 +- .../info/frostfs/sdk/jdo/ClientSettings.java | 48 +- .../main/java/info/frostfs/sdk/jdo/ECDsa.java | 4 +- .../info/frostfs/sdk/jdo/NetworkSettings.java | 34 +- .../frostfs/sdk/jdo/PutObjectParameters.java | 60 ++- .../info/frostfs/sdk/jdo/PutObjectResult.java | 21 + .../info/frostfs/sdk/jdo/WaitParameters.java | 34 ++ .../frostfs/sdk/services/ObjectClient.java | 4 +- .../frostfs/sdk/services/SessionClient.java | 2 +- .../frostfs/sdk/services/SessionTools.java | 9 + .../services/impl/ContainerClientImpl.java | 197 +++++-- .../sdk/services/impl/NetmapClientImpl.java | 17 +- .../sdk/services/impl/ObjectClientImpl.java | 485 +++++++++++------- .../sdk/services/impl/ObjectToolsImpl.java | 97 ++-- .../sdk/services/impl/SessionClientImpl.java | 23 +- .../sdk/services/impl/SessionToolsImpl.java | 27 + ...bjectReader.java => ObjectReaderImpl.java} | 5 +- .../services/impl/rwhelper/ObjectWriter.java | 4 +- .../info/frostfs/sdk/tools/GrpcClient.java | 15 +- .../info/frostfs/sdk/tools/MessageHelper.java | 18 - .../frostfs/sdk/tools/RequestConstructor.java | 117 ++++- .../info/frostfs/sdk/tools/RequestSigner.java | 9 +- .../java/info/frostfs/sdk/tools/Verifier.java | 10 +- .../info/frostfs/sdk/utils/MessageHelper.java | 30 ++ .../frostfs/sdk/utils/ValidatorUtils.java | 42 ++ .../java/info/frostfs/sdk/utils/WaitUtil.java | 12 + .../java/info/frostfs/sdk/ArrayHelper.java | 8 +- .../frostfs/sdk/constants/FilterConst.java | 49 ++ .../java/info/frostfs/sdk/dto/CheckSum.java | 25 + .../info/frostfs/sdk/dto/SessionToken.java | 19 - .../frostfs/sdk/dto/container/Container.java | 2 +- .../sdk/dto/netmap/NetmapSnapshot.java | 3 +- .../info/frostfs/sdk/dto/netmap/NodeInfo.java | 6 +- .../frostfs/sdk/dto/{ => netmap}/Version.java | 2 +- .../frostfs/sdk/dto/object/LinkObject.java | 6 +- .../frostfs/sdk/dto/object/ObjectFilter.java | 118 ++++- .../frostfs/sdk/dto/object/ObjectFrostFS.java | 15 +- .../frostfs/sdk/dto/object/ObjectHeader.java | 32 +- .../frostfs/sdk/dto/object/ObjectReader.java | 5 + .../frostfs/sdk/dto/{ => object}/OwnerId.java | 7 +- .../frostfs/sdk/dto/{ => object}/Split.java | 15 +- .../frostfs/sdk/dto/{ => object}/SplitId.java | 6 +- .../sdk/dto/{ => response}/MetaHeader.java | 4 +- .../ResponseStatus.java} | 8 +- .../sdk/dto/{ => response}/Signature.java | 2 +- .../frostfs/sdk/dto/session/SessionToken.java | 13 + .../frostfs/sdk/mappers/MetaHeaderMapper.java | 24 - .../mappers/container/ContainerMapper.java | 2 +- .../sdk/mappers/netmap/NodeInfoMapper.java | 1 - .../mappers/{ => netmap}/VersionMapper.java | 4 +- .../mappers/object/ObjectFilterMapper.java | 4 +- .../mappers/object/ObjectHeaderMapper.java | 19 +- .../mappers/{ => object}/OwnerIdMapper.java | 4 +- .../mappers/response/MetaHeaderMapper.java | 33 ++ .../ResponseStatusMapper.java} | 14 +- .../{ => response}/SignatureMapper.java | 4 +- .../mappers/{ => session}/SessionMapper.java | 2 +- .../sdk/mappers/MetaHeaderMapperTest.java | 33 -- .../{ => netmap}/VersionMapperTest.java | 4 +- .../object/ObjectFilterMapperTest.java | 4 +- .../object/ObjectHeaderMapperTest.java | 11 +- .../{ => object}/OwnerIdMapperTest.java | 4 +- .../response/MetaHeaderMapperTest.java | 57 ++ .../ResponseStatusMapperTest.java} | 10 +- .../{ => response}/SignatureMapperTest.java | 4 +- .../{ => session}/SessionMapperTest.java | 2 +- 70 files changed, 1375 insertions(+), 587 deletions(-) create mode 100644 client/src/main/java/info/frostfs/sdk/enums/WaitExpects.java create mode 100644 client/src/main/java/info/frostfs/sdk/exceptions/ResponseException.java create mode 100644 client/src/main/java/info/frostfs/sdk/exceptions/TimeoutException.java create mode 100644 client/src/main/java/info/frostfs/sdk/jdo/PutObjectResult.java create mode 100644 client/src/main/java/info/frostfs/sdk/jdo/WaitParameters.java create mode 100644 client/src/main/java/info/frostfs/sdk/services/SessionTools.java create mode 100644 client/src/main/java/info/frostfs/sdk/services/impl/SessionToolsImpl.java rename client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/{ObjectReader.java => ObjectReaderImpl.java} (89%) delete mode 100644 client/src/main/java/info/frostfs/sdk/tools/MessageHelper.java create mode 100644 client/src/main/java/info/frostfs/sdk/utils/MessageHelper.java create mode 100644 client/src/main/java/info/frostfs/sdk/utils/ValidatorUtils.java create mode 100644 client/src/main/java/info/frostfs/sdk/utils/WaitUtil.java create mode 100644 models/src/main/java/info/frostfs/sdk/constants/FilterConst.java create mode 100644 models/src/main/java/info/frostfs/sdk/dto/CheckSum.java delete mode 100644 models/src/main/java/info/frostfs/sdk/dto/SessionToken.java rename models/src/main/java/info/frostfs/sdk/dto/{ => netmap}/Version.java (95%) create mode 100644 models/src/main/java/info/frostfs/sdk/dto/object/ObjectReader.java rename models/src/main/java/info/frostfs/sdk/dto/{ => object}/OwnerId.java (85%) rename models/src/main/java/info/frostfs/sdk/dto/{ => object}/Split.java (78%) rename models/src/main/java/info/frostfs/sdk/dto/{ => object}/SplitId.java (83%) rename models/src/main/java/info/frostfs/sdk/dto/{ => response}/MetaHeader.java (94%) rename models/src/main/java/info/frostfs/sdk/dto/{Status.java => response/ResponseStatus.java} (83%) rename models/src/main/java/info/frostfs/sdk/dto/{ => response}/Signature.java (93%) create mode 100644 models/src/main/java/info/frostfs/sdk/dto/session/SessionToken.java delete mode 100644 models/src/main/java/info/frostfs/sdk/mappers/MetaHeaderMapper.java rename models/src/main/java/info/frostfs/sdk/mappers/{ => netmap}/VersionMapper.java (88%) rename models/src/main/java/info/frostfs/sdk/mappers/{ => object}/OwnerIdMapper.java (84%) create mode 100644 models/src/main/java/info/frostfs/sdk/mappers/response/MetaHeaderMapper.java rename models/src/main/java/info/frostfs/sdk/mappers/{StatusMapper.java => response/ResponseStatusMapper.java} (58%) rename models/src/main/java/info/frostfs/sdk/mappers/{ => response}/SignatureMapper.java (91%) rename models/src/main/java/info/frostfs/sdk/mappers/{ => session}/SessionMapper.java (96%) delete mode 100644 models/src/test/java/info/frostfs/sdk/mappers/MetaHeaderMapperTest.java rename models/src/test/java/info/frostfs/sdk/mappers/{ => netmap}/VersionMapperTest.java (93%) rename models/src/test/java/info/frostfs/sdk/mappers/{ => object}/OwnerIdMapperTest.java (92%) create mode 100644 models/src/test/java/info/frostfs/sdk/mappers/response/MetaHeaderMapperTest.java rename models/src/test/java/info/frostfs/sdk/mappers/{StatusMapperTest.java => response/ResponseStatusMapperTest.java} (80%) rename models/src/test/java/info/frostfs/sdk/mappers/{ => response}/SignatureMapperTest.java (95%) rename models/src/test/java/info/frostfs/sdk/mappers/{ => session}/SessionMapperTest.java (97%) diff --git a/client/src/main/java/info/frostfs/sdk/FrostFSClient.java b/client/src/main/java/info/frostfs/sdk/FrostFSClient.java index 48fdcc5..a373559 100644 --- a/client/src/main/java/info/frostfs/sdk/FrostFSClient.java +++ b/client/src/main/java/info/frostfs/sdk/FrostFSClient.java @@ -1,16 +1,16 @@ package info.frostfs.sdk; import frostfs.session.Types; -import info.frostfs.sdk.dto.SessionToken; -import info.frostfs.sdk.dto.Version; import info.frostfs.sdk.dto.container.Container; import info.frostfs.sdk.dto.container.ContainerId; import info.frostfs.sdk.dto.netmap.NetmapSnapshot; import info.frostfs.sdk.dto.netmap.NodeInfo; +import info.frostfs.sdk.dto.netmap.Version; import info.frostfs.sdk.dto.object.ObjectFilter; import info.frostfs.sdk.dto.object.ObjectFrostFS; import info.frostfs.sdk.dto.object.ObjectHeader; import info.frostfs.sdk.dto.object.ObjectId; +import info.frostfs.sdk.dto.session.SessionToken; import info.frostfs.sdk.jdo.ClientEnvironment; import info.frostfs.sdk.jdo.ClientSettings; import info.frostfs.sdk.jdo.NetworkSettings; @@ -23,6 +23,7 @@ import java.util.List; import static info.frostfs.sdk.tools.GrpcClient.initGrpcChannel; import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClient, SessionClient, ToolsClient { private static final String ERROR_CLIENT_OPTIONS_INIT = "Options must be initialized."; @@ -39,9 +40,8 @@ public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClien throw new IllegalArgumentException(ERROR_CLIENT_OPTIONS_INIT); } - clientSettings.validate(); - - Channel channel = initGrpcChannel(clientSettings.getHost(), clientSettings.getCreds()); + Channel channel = nonNull(clientSettings.getChannel()) ? clientSettings.getChannel() + : initGrpcChannel(clientSettings.getHost(), clientSettings.getCredentials()); ClientEnvironment clientEnvironment = new ClientEnvironment(clientSettings.getKey(), channel, new Version(), this); @@ -98,13 +98,18 @@ public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClien return objectClientImpl.putObject(parameters); } + @Override + public ObjectId putSingleObject(ObjectFrostFS objectFrostFS) { + return objectClientImpl.putSingleObject(objectFrostFS); + } + @Override public void deleteObject(ContainerId containerId, ObjectId objectId) { objectClientImpl.deleteObject(containerId, objectId); } @Override - public Iterable searchObjects(ContainerId cid, ObjectFilter... filters) { + public Iterable searchObjects(ContainerId cid, ObjectFilter... filters) { return objectClientImpl.searchObjects(cid, filters); } diff --git a/client/src/main/java/info/frostfs/sdk/enums/WaitExpects.java b/client/src/main/java/info/frostfs/sdk/enums/WaitExpects.java new file mode 100644 index 0000000..82e4d0a --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/enums/WaitExpects.java @@ -0,0 +1,6 @@ +package info.frostfs.sdk.enums; + +public enum WaitExpects { + EXISTS, + REMOVED +} diff --git a/client/src/main/java/info/frostfs/sdk/exceptions/ResponseException.java b/client/src/main/java/info/frostfs/sdk/exceptions/ResponseException.java new file mode 100644 index 0000000..1367bd1 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/exceptions/ResponseException.java @@ -0,0 +1,16 @@ +package info.frostfs.sdk.exceptions; + +import info.frostfs.sdk.dto.response.ResponseStatus; + +public class ResponseException extends RuntimeException { + private final ResponseStatus status; + + public ResponseException(ResponseStatus status) { + super(status.toString()); + this.status = status; + } + + public ResponseStatus getStatus() { + return status; + } +} diff --git a/client/src/main/java/info/frostfs/sdk/exceptions/TimeoutException.java b/client/src/main/java/info/frostfs/sdk/exceptions/TimeoutException.java new file mode 100644 index 0000000..b619ddd --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/exceptions/TimeoutException.java @@ -0,0 +1,6 @@ +package info.frostfs.sdk.exceptions; + +public class TimeoutException extends RuntimeException { + public TimeoutException() { + } +} diff --git a/client/src/main/java/info/frostfs/sdk/jdo/ClientEnvironment.java b/client/src/main/java/info/frostfs/sdk/jdo/ClientEnvironment.java index 6e17947..22bc8cd 100644 --- a/client/src/main/java/info/frostfs/sdk/jdo/ClientEnvironment.java +++ b/client/src/main/java/info/frostfs/sdk/jdo/ClientEnvironment.java @@ -1,14 +1,16 @@ package info.frostfs.sdk.jdo; import info.frostfs.sdk.FrostFSClient; -import info.frostfs.sdk.dto.OwnerId; -import info.frostfs.sdk.dto.Version; +import info.frostfs.sdk.dto.netmap.Version; +import info.frostfs.sdk.dto.object.OwnerId; import io.grpc.Channel; import org.apache.commons.lang3.StringUtils; import static java.util.Objects.isNull; public class ClientEnvironment { + private static final String ERROR_MESSAGE = "One of the input attributes is missing"; + private final OwnerId ownerId; private final Version version; private final ECDsa key; @@ -18,7 +20,7 @@ public class ClientEnvironment { public ClientEnvironment(String wif, Channel channel, Version version, FrostFSClient frostFSClient) { if (StringUtils.isEmpty(wif) || isNull(channel) || isNull(version) || isNull(frostFSClient)) { - throw new IllegalArgumentException("One of the input attributes is missing"); + throw new IllegalArgumentException(ERROR_MESSAGE); } this.key = new ECDsa(wif); diff --git a/client/src/main/java/info/frostfs/sdk/jdo/ClientSettings.java b/client/src/main/java/info/frostfs/sdk/jdo/ClientSettings.java index 5f7bd32..a4962a0 100644 --- a/client/src/main/java/info/frostfs/sdk/jdo/ClientSettings.java +++ b/client/src/main/java/info/frostfs/sdk/jdo/ClientSettings.java @@ -1,14 +1,20 @@ package info.frostfs.sdk.jdo; +import io.grpc.Channel; import io.grpc.ChannelCredentials; import org.apache.commons.lang3.StringUtils; -public class ClientSettings { - private static final String ERROR_TEMPLATE = "%s is required parameter."; +import static java.util.Objects.isNull; - public String key; - public String host; - public ChannelCredentials creds; +public class ClientSettings { + private static final String ERROR_TEMPLATE = "%s required parameter."; + private static final String KEY_NAME = "Key"; + private static final String HOST_AND_CHANNEL_NAME = "Host or Channel"; + + private final String key; + private String host; + private ChannelCredentials credentials; + private Channel channel; public ClientSettings(String key, String host) { this.key = key; @@ -16,46 +22,44 @@ public class ClientSettings { validate(); } - public ClientSettings(String key, String host, ChannelCredentials creds) { + public ClientSettings(String key, String host, ChannelCredentials credentials) { this.key = key; this.host = host; - this.creds = creds; + this.credentials = credentials; validate(); } - public ChannelCredentials getCreds() { - return creds; + public ClientSettings(String key, Channel channel) { + this.key = key; + this.channel = channel; + validate(); } - public void setCreds(ChannelCredentials creds) { - this.creds = creds; + public Channel getChannel() { + return channel; + } + + public ChannelCredentials getCredentials() { + return credentials; } public String getHost() { return host; } - public void setHost(String host) { - this.host = host; - } - public String getKey() { return key; } - public void setKey(String key) { - this.key = key; - } - public void validate() { StringBuilder errorMessage = new StringBuilder(); if (StringUtils.isEmpty(key)) { - errorMessage.append(String.format(ERROR_TEMPLATE, "Key")).append(System.lineSeparator()); + errorMessage.append(String.format(ERROR_TEMPLATE, KEY_NAME)).append(System.lineSeparator()); } - if (StringUtils.isEmpty(host)) { - errorMessage.append(String.format(ERROR_TEMPLATE, "Host")).append(System.lineSeparator()); + if (StringUtils.isEmpty(host) && isNull(channel)) { + errorMessage.append(String.format(ERROR_TEMPLATE, HOST_AND_CHANNEL_NAME)).append(System.lineSeparator()); } if (errorMessage.length() != 0) { diff --git a/client/src/main/java/info/frostfs/sdk/jdo/ECDsa.java b/client/src/main/java/info/frostfs/sdk/jdo/ECDsa.java index d328c10..8e86d7c 100644 --- a/client/src/main/java/info/frostfs/sdk/jdo/ECDsa.java +++ b/client/src/main/java/info/frostfs/sdk/jdo/ECDsa.java @@ -7,13 +7,15 @@ import java.security.PrivateKey; import static info.frostfs.sdk.KeyExtension.*; public class ECDsa { + private static final String ERROR_MESSAGE = "WIF is invalid"; + private final byte[] publicKeyByte; private final byte[] privateKeyByte; private final PrivateKey privateKey; public ECDsa(String wif) { if (StringUtils.isEmpty(wif)) { - throw new IllegalArgumentException("Wif is invalid"); + throw new IllegalArgumentException(ERROR_MESSAGE); } this.privateKeyByte = getPrivateKeyFromWIF(wif); diff --git a/client/src/main/java/info/frostfs/sdk/jdo/NetworkSettings.java b/client/src/main/java/info/frostfs/sdk/jdo/NetworkSettings.java index 1ed01a6..daf9981 100644 --- a/client/src/main/java/info/frostfs/sdk/jdo/NetworkSettings.java +++ b/client/src/main/java/info/frostfs/sdk/jdo/NetworkSettings.java @@ -5,21 +5,21 @@ import java.util.Map; public class NetworkSettings { - public Long auditFee; - public Long basicIncomeRate; - public Long containerFee; - public Long containerAliasFee; - public Long innerRingCandidateFee; - public Long withdrawFee; - public Long epochDuration; - public Long iRCandidateFee; - public Long maxObjectSize; - public Long maxECDataCount; - public Long maxECParityCount; - public Long withdrawalFee; - public Boolean homomorphicHashingDisabled; - public Boolean maintenanceModeAllowed; - public Map unnamedSettings = new HashMap<>(); + private Long auditFee; + private Long basicIncomeRate; + private Long containerFee; + private Long containerAliasFee; + private Long innerRingCandidateFee; + private Long withdrawFee; + private Long epochDuration; + private Long iRCandidateFee; + private Long maxObjectSize; + private Long maxECDataCount; + private Long maxECParityCount; + private Long withdrawalFee; + private Boolean homomorphicHashingDisabled; + private Boolean maintenanceModeAllowed; + private Map unnamedSettings = new HashMap<>(); public Long getAuditFee() { return auditFee; @@ -77,11 +77,11 @@ public class NetworkSettings { this.epochDuration = epochDuration; } - public long getiRCandidateFee() { + public long getIRCandidateFee() { return iRCandidateFee; } - public void setiRCandidateFee(long iRCandidateFee) { + public void setIRCandidateFee(long iRCandidateFee) { this.iRCandidateFee = iRCandidateFee; } diff --git a/client/src/main/java/info/frostfs/sdk/jdo/PutObjectParameters.java b/client/src/main/java/info/frostfs/sdk/jdo/PutObjectParameters.java index 3c4ecdd..b091cb9 100644 --- a/client/src/main/java/info/frostfs/sdk/jdo/PutObjectParameters.java +++ b/client/src/main/java/info/frostfs/sdk/jdo/PutObjectParameters.java @@ -1,6 +1,7 @@ package info.frostfs.sdk.jdo; import info.frostfs.sdk.dto.object.ObjectHeader; +import info.frostfs.sdk.dto.session.SessionToken; import java.io.FileInputStream; @@ -8,11 +9,18 @@ import static java.util.Objects.isNull; public class PutObjectParameters { private static final String ERROR_TEMPLATE = "%s value cannot be null."; + private static final String HEADER_NAME = "Header"; + private static final String PAYLOAD_NAME = "Payload"; - public ObjectHeader header; - public FileInputStream payload; - public boolean clientCut; - public int bufferMaxSize; + private ObjectHeader header; + private FileInputStream payload; + private boolean clientCut; + private int bufferMaxSize; + private byte[] customerBuffer; + private SessionToken sessionToken; + private int maxObjectSizeCache; + private long currentStreamPosition; + private long fullLength; public PutObjectParameters(ObjectHeader header, FileInputStream payload, boolean clientCut, int bufferMaxSize) { this.header = header; @@ -30,6 +38,46 @@ public class PutObjectParameters { validate(); } + public byte[] getCustomerBuffer() { + return customerBuffer; + } + + public void setCustomerBuffer(byte[] customerBuffer) { + this.customerBuffer = customerBuffer; + } + + public SessionToken getSessionToken() { + return sessionToken; + } + + public void setSessionToken(SessionToken sessionToken) { + this.sessionToken = sessionToken; + } + + public int getMaxObjectSizeCache() { + return maxObjectSizeCache; + } + + public void setMaxObjectSizeCache(int maxObjectSizeCache) { + this.maxObjectSizeCache = maxObjectSizeCache; + } + + public long getCurrentStreamPosition() { + return currentStreamPosition; + } + + public void setCurrentStreamPosition(long currentStreamPosition) { + this.currentStreamPosition = currentStreamPosition; + } + + public long getFullLength() { + return fullLength; + } + + public void setFullLength(long fullLength) { + this.fullLength = fullLength; + } + public ObjectHeader getHeader() { return header; } @@ -66,11 +114,11 @@ public class PutObjectParameters { StringBuilder errorMessage = new StringBuilder(); if (isNull(header)) { - errorMessage.append(String.format(ERROR_TEMPLATE, "Header")).append(System.lineSeparator()); + errorMessage.append(String.format(ERROR_TEMPLATE, HEADER_NAME)).append(System.lineSeparator()); } if (isNull(payload)) { - errorMessage.append(String.format(ERROR_TEMPLATE, "Payload")).append(System.lineSeparator()); + errorMessage.append(String.format(ERROR_TEMPLATE, PAYLOAD_NAME)).append(System.lineSeparator()); } if (errorMessage.length() != 0) { diff --git a/client/src/main/java/info/frostfs/sdk/jdo/PutObjectResult.java b/client/src/main/java/info/frostfs/sdk/jdo/PutObjectResult.java new file mode 100644 index 0000000..24ee14b --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/jdo/PutObjectResult.java @@ -0,0 +1,21 @@ +package info.frostfs.sdk.jdo; + +import info.frostfs.sdk.dto.object.ObjectId; + +public class PutObjectResult { + private final ObjectId objectId; + private final int objectSize; + + public PutObjectResult(ObjectId objectId, int objectSize) { + this.objectId = objectId; + this.objectSize = objectSize; + } + + public ObjectId getObjectId() { + return objectId; + } + + public int getObjectSize() { + return objectSize; + } +} diff --git a/client/src/main/java/info/frostfs/sdk/jdo/WaitParameters.java b/client/src/main/java/info/frostfs/sdk/jdo/WaitParameters.java new file mode 100644 index 0000000..0aa8c47 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/jdo/WaitParameters.java @@ -0,0 +1,34 @@ +package info.frostfs.sdk.jdo; + +import java.time.Duration; +import java.time.LocalDateTime; + +public class WaitParameters { + private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(120); + private static final Duration DEFAULT_POLL_INTERVAL = Duration.ofSeconds(5); + + private final Duration timeout; + private final Duration pollInterval; + + public WaitParameters() { + this.timeout = DEFAULT_TIMEOUT; + this.pollInterval = DEFAULT_POLL_INTERVAL; + } + + public WaitParameters(Duration timeout, Duration pollInterval) { + this.timeout = timeout; + this.pollInterval = pollInterval; + } + + public Duration getTimeout() { + return timeout; + } + + public Duration getPollInterval() { + return pollInterval; + } + + public LocalDateTime getDeadline() { + return LocalDateTime.now().plus(timeout); + } +} diff --git a/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java b/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java index 423e938..3a38295 100644 --- a/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java +++ b/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java @@ -14,7 +14,9 @@ public interface ObjectClient { ObjectId putObject(PutObjectParameters parameters); + ObjectId putSingleObject(ObjectFrostFS objectFrostFS); + void deleteObject(ContainerId containerId, ObjectId objectId); - Iterable searchObjects(ContainerId cid, ObjectFilter... filters); + Iterable searchObjects(ContainerId cid, ObjectFilter... filters); } diff --git a/client/src/main/java/info/frostfs/sdk/services/SessionClient.java b/client/src/main/java/info/frostfs/sdk/services/SessionClient.java index 16e0da0..e9b197c 100644 --- a/client/src/main/java/info/frostfs/sdk/services/SessionClient.java +++ b/client/src/main/java/info/frostfs/sdk/services/SessionClient.java @@ -1,6 +1,6 @@ package info.frostfs.sdk.services; -import info.frostfs.sdk.dto.SessionToken; +import info.frostfs.sdk.dto.session.SessionToken; public interface SessionClient { SessionToken createSession(long expiration); diff --git a/client/src/main/java/info/frostfs/sdk/services/SessionTools.java b/client/src/main/java/info/frostfs/sdk/services/SessionTools.java new file mode 100644 index 0000000..7976592 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/services/SessionTools.java @@ -0,0 +1,9 @@ +package info.frostfs.sdk.services; + +import frostfs.session.Types; +import info.frostfs.sdk.dto.session.SessionToken; +import info.frostfs.sdk.jdo.ClientEnvironment; + +public interface SessionTools { + Types.SessionToken getOrCreateSession(SessionToken token, ClientEnvironment env); +} diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/ContainerClientImpl.java b/client/src/main/java/info/frostfs/sdk/services/impl/ContainerClientImpl.java index 5c0e7af..db7c0bf 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/ContainerClientImpl.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/ContainerClientImpl.java @@ -2,48 +2,60 @@ package info.frostfs.sdk.services.impl; import frostfs.container.ContainerServiceGrpc; import frostfs.container.Service; +import frostfs.refs.Types; import info.frostfs.sdk.dto.container.Container; import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.session.SessionToken; +import info.frostfs.sdk.enums.StatusCode; +import info.frostfs.sdk.enums.WaitExpects; +import info.frostfs.sdk.exceptions.ResponseException; +import info.frostfs.sdk.exceptions.TimeoutException; import info.frostfs.sdk.jdo.ClientEnvironment; -import info.frostfs.sdk.mappers.OwnerIdMapper; -import info.frostfs.sdk.mappers.VersionMapper; +import info.frostfs.sdk.jdo.WaitParameters; import info.frostfs.sdk.mappers.container.ContainerIdMapper; import info.frostfs.sdk.mappers.container.ContainerMapper; +import info.frostfs.sdk.mappers.netmap.VersionMapper; +import info.frostfs.sdk.mappers.object.OwnerIdMapper; import info.frostfs.sdk.services.ContainerClient; import info.frostfs.sdk.services.ContextAccessor; import info.frostfs.sdk.tools.RequestConstructor; import info.frostfs.sdk.tools.RequestSigner; import info.frostfs.sdk.tools.Verifier; +import info.frostfs.sdk.utils.WaitUtil; +import java.time.LocalDateTime; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import static java.util.Objects.isNull; public class ContainerClientImpl extends ContextAccessor implements ContainerClient { + private static final String ERROR_CONTAINER_ID_MISSING = "ContainerId is not present"; + private static final String ERROR_CONTAINER_MISSING = "Container is not present"; + private final ContainerServiceGrpc.ContainerServiceBlockingStub serviceBlockingStub; + private final SessionToolsImpl sessionTools; public ContainerClientImpl(ClientEnvironment clientEnvironment) { super(clientEnvironment); this.serviceBlockingStub = ContainerServiceGrpc.newBlockingStub(clientEnvironment.getChannel()); + this.sessionTools = new SessionToolsImpl(clientEnvironment); + } + + public frostfs.session.Types.SessionToken getOrCreateSession(SessionToken sessionToken) { + return sessionTools.getOrCreateSession(sessionToken, getContext()); } @Override public Container getContainer(ContainerId cid) { if (isNull(cid)) { - throw new IllegalArgumentException("ContainerId is not present"); + throw new IllegalArgumentException(ERROR_CONTAINER_ID_MISSING); } - var body = Service.GetRequest.Body.newBuilder() - .setContainerId(ContainerIdMapper.toGrpcMessage(cid)) - .build(); - var request = Service.GetRequest.newBuilder() - .setBody(body); + var request = createGetRequest(ContainerIdMapper.toGrpcMessage(cid), null); - RequestConstructor.addDefaultMetaHeader(request); - RequestSigner.sign(request, getContext().getKey()); - - var response = serviceBlockingStub.get(request.build()); + var response = serviceBlockingStub.get(request); Verifier.checkResponse(response); return ContainerMapper.toModel(response.getBody().getContainer()); @@ -51,16 +63,9 @@ public class ContainerClientImpl extends ContextAccessor implements ContainerCli @Override public List listContainers() { - var body = Service.ListRequest.Body.newBuilder() - .setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId())) - .build(); - var request = Service.ListRequest.newBuilder() - .setBody(body); + var request = createListRequest(null); - RequestConstructor.addDefaultMetaHeader(request); - RequestSigner.sign(request, getContext().getKey()); - - var response = serviceBlockingStub.list(request.build()); + var response = serviceBlockingStub.list(request); Verifier.checkResponse(response); @@ -72,51 +77,155 @@ public class ContainerClientImpl extends ContextAccessor implements ContainerCli @Override public ContainerId createContainer(Container container) { if (isNull(container)) { - throw new IllegalArgumentException("Container is not present"); + throw new IllegalArgumentException(ERROR_CONTAINER_MISSING); } var grpcContainer = ContainerMapper.toGrpcMessage(container); - grpcContainer = grpcContainer.toBuilder() - .setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId())) - .setVersion(VersionMapper.toGrpcMessage(getContext().getVersion())) - .build(); + var request = createPutRequest(grpcContainer, null); - var body = Service.PutRequest.Body.newBuilder() - .setContainer(grpcContainer) - .setSignature(RequestSigner.signRFC6979(getContext().getKey(), grpcContainer)) - .build(); - var request = Service.PutRequest.newBuilder() - .setBody(body); - - RequestConstructor.addDefaultMetaHeader(request); - RequestSigner.sign(request, getContext().getKey()); - - var response = serviceBlockingStub.put(request.build()); + var response = serviceBlockingStub.put(request); Verifier.checkResponse(response); + + waitForContainer(WaitExpects.EXISTS, response.getBody().getContainerId(), null); + return new ContainerId(response.getBody().getContainerId().getValue().toByteArray()); } @Override public void deleteContainer(ContainerId cid) { if (isNull(cid)) { - throw new IllegalArgumentException("ContainerId is not present"); + throw new IllegalArgumentException(ERROR_CONTAINER_ID_MISSING); } var grpcContainerId = ContainerIdMapper.toGrpcMessage(cid); + var request = createDeleteRequest(grpcContainerId, null); + var response = serviceBlockingStub.delete(request); + + Verifier.checkResponse(response); + + waitForContainer(WaitExpects.REMOVED, request.getBody().getContainerId(), null); + } + + private void waitForContainer(WaitExpects expect, Types.ContainerID id, WaitParameters waitParams) { + var request = createGetRequest(id, null); + + waitParams = isNull(waitParams) ? new WaitParameters() : waitParams; + var deadLine = waitParams.getDeadline(); + + while (true) { + try { + var response = serviceBlockingStub.get(request); + Verifier.checkResponse(response); + + if (expect == WaitExpects.EXISTS) { + break; + } + + if (LocalDateTime.now().isAfter(deadLine)) { + throw new TimeoutException(); + } + + WaitUtil.sleep(waitParams.getPollInterval().toMillis()); + } catch (ResponseException exp) { + if (LocalDateTime.now().isAfter(deadLine)) { + throw new TimeoutException(); + } + + if (exp.getStatus().getCode() != StatusCode.CONTAINER_NOT_FOUND) { + throw exp; + } + + if (expect == WaitExpects.REMOVED) { + break; + } + + WaitUtil.sleep(waitParams.getPollInterval().toMillis()); + } + } + } + + + private Service.GetRequest createGetRequest(Types.ContainerID cid, + Map xHeaders) { + var body = Service.GetRequest.Body.newBuilder() + .setContainerId(cid) + .build(); + var request = Service.GetRequest.newBuilder() + .setBody(body); + + RequestConstructor.addMetaHeader(request, xHeaders); + RequestSigner.sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.ListRequest createListRequest(Map xHeaders) { + var body = Service.ListRequest.Body.newBuilder() + .setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId())) + .build(); + var request = Service.ListRequest.newBuilder() + .setBody(body); + + RequestConstructor.addMetaHeader(request, xHeaders); + RequestSigner.sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.PutRequest createPutRequest(frostfs.container.Types.Container container, + Map xHeaders) { + container = container.toBuilder() + .setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId())) + .setVersion(VersionMapper.toGrpcMessage(getContext().getVersion())) + .build(); + + var body = Service.PutRequest.Body.newBuilder() + .setContainer(container) + .setSignature(RequestSigner.signRFC6979(getContext().getKey(), container)) + .build(); + var request = Service.PutRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createContainerTokenContext( + sessionToken, + null, + frostfs.session.Types.ContainerSessionContext.Verb.PUT, + container.getOwnerId(), + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, xHeaders, sessionToken); + RequestSigner.sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.DeleteRequest createDeleteRequest(Types.ContainerID cid, + Map xHeaders) { var body = Service.DeleteRequest.Body.newBuilder() - .setContainerId(grpcContainerId) - .setSignature(RequestSigner.signRFC6979(getContext().getKey(), grpcContainerId.getValue())) + .setContainerId(cid) + .setSignature(RequestSigner.signRFC6979(getContext().getKey(), cid.getValue())) .build(); var request = Service.DeleteRequest.newBuilder() .setBody(body); - RequestConstructor.addDefaultMetaHeader(request); + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createContainerTokenContext( + sessionToken, + null, + frostfs.session.Types.ContainerSessionContext.Verb.DELETE, + null, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, xHeaders, sessionToken); RequestSigner.sign(request, getContext().getKey()); - var response = serviceBlockingStub.delete(request.build()); - - Verifier.checkResponse(response); + return request.build(); } } diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/NetmapClientImpl.java b/client/src/main/java/info/frostfs/sdk/services/impl/NetmapClientImpl.java index 3a3d1ca..04109ad 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/NetmapClientImpl.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/NetmapClientImpl.java @@ -67,7 +67,7 @@ public class NetmapClientImpl extends ContextAccessor implements NetmapClient { settings.setEpochDuration(getLongValue(valueBytes)); break; case "InnerRingCandidateFee": - settings.setiRCandidateFee(getLongValue(valueBytes)); + settings.setIRCandidateFee(getLongValue(valueBytes)); break; case "MaxECDataCount": settings.setMaxECDataCount(getLongValue(valueBytes)); @@ -114,10 +114,9 @@ public class NetmapClientImpl extends ContextAccessor implements NetmapClient { @Override public NodeInfo getLocalNodeInfo() { - var request = Service.LocalNodeInfoRequest.newBuilder() - .setBody(Service.LocalNodeInfoRequest.Body.newBuilder().build()); + var request = Service.LocalNodeInfoRequest.newBuilder(); - RequestConstructor.addDefaultMetaHeader(request); + RequestConstructor.addMetaHeader(request); sign(request, getContext().getKey()); var response = netmapServiceClient.localNodeInfo(request.build()); @@ -127,10 +126,9 @@ public class NetmapClientImpl extends ContextAccessor implements NetmapClient { } public Service.NetworkInfoResponse getNetworkInfo() { - var request = Service.NetworkInfoRequest.newBuilder() - .setBody(Service.NetworkInfoRequest.Body.newBuilder().build()); + var request = Service.NetworkInfoRequest.newBuilder(); - RequestConstructor.addDefaultMetaHeader(request); + RequestConstructor.addMetaHeader(request); sign(request, getContext().getKey()); var response = netmapServiceClient.networkInfo(request.build()); @@ -142,10 +140,9 @@ public class NetmapClientImpl extends ContextAccessor implements NetmapClient { @Override public NetmapSnapshot getNetmapSnapshot() { - var request = Service.NetmapSnapshotRequest.newBuilder() - .setBody(Service.NetmapSnapshotRequest.Body.newBuilder().build()); + var request = Service.NetmapSnapshotRequest.newBuilder(); - RequestConstructor.addDefaultMetaHeader(request); + RequestConstructor.addMetaHeader(request); sign(request, getContext().getKey()); var response = netmapServiceClient.netmapSnapshot(request.build()); diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java b/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java index 69046d6..736189e 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java @@ -6,21 +6,22 @@ import frostfs.object.ObjectServiceGrpc; import frostfs.object.Service; import frostfs.refs.Types; import info.frostfs.sdk.constants.AppConst; -import info.frostfs.sdk.dto.Split; import info.frostfs.sdk.dto.container.ContainerId; import info.frostfs.sdk.dto.object.*; +import info.frostfs.sdk.dto.session.SessionToken; +import info.frostfs.sdk.enums.ObjectType; import info.frostfs.sdk.jdo.ClientEnvironment; import info.frostfs.sdk.jdo.PutObjectParameters; -import info.frostfs.sdk.mappers.OwnerIdMapper; -import info.frostfs.sdk.mappers.VersionMapper; +import info.frostfs.sdk.jdo.PutObjectResult; import info.frostfs.sdk.mappers.container.ContainerIdMapper; import info.frostfs.sdk.mappers.object.ObjectFilterMapper; import info.frostfs.sdk.mappers.object.ObjectFrostFSMapper; import info.frostfs.sdk.mappers.object.ObjectHeaderMapper; import info.frostfs.sdk.mappers.object.ObjectIdMapper; +import info.frostfs.sdk.mappers.session.SessionMapper; import info.frostfs.sdk.services.ContextAccessor; import info.frostfs.sdk.services.ObjectClient; -import info.frostfs.sdk.services.impl.rwhelper.ObjectReader; +import info.frostfs.sdk.services.impl.rwhelper.ObjectReaderImpl; import info.frostfs.sdk.services.impl.rwhelper.ObjectWriter; import info.frostfs.sdk.services.impl.rwhelper.SearchReader; import info.frostfs.sdk.tools.RequestConstructor; @@ -30,44 +31,42 @@ import org.apache.commons.collections4.CollectionUtils; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import static info.frostfs.sdk.Helper.getSha256; -import static info.frostfs.sdk.tools.RequestConstructor.addObjectSessionToken; import static info.frostfs.sdk.tools.RequestSigner.sign; -import static java.util.Objects.nonNull; +import static java.util.Objects.isNull; public class ObjectClientImpl extends ContextAccessor implements ObjectClient { - private static final String ERROR_PAYLOAD = "PayloadLength must be specified"; + private static final String ERROR_PARAMS_MISSING = "Params is not present"; private final ObjectServiceGrpc.ObjectServiceBlockingStub objectServiceBlockingClient; private final ObjectServiceGrpc.ObjectServiceStub objectServiceClient; private final ObjectToolsImpl objectToolsImpl; + private final SessionToolsImpl sessionTools; public ObjectClientImpl(ClientEnvironment clientEnvironment) { super(clientEnvironment); this.objectServiceBlockingClient = ObjectServiceGrpc.newBlockingStub(getContext().getChannel()); this.objectServiceClient = ObjectServiceGrpc.newStub(getContext().getChannel()); this.objectToolsImpl = new ObjectToolsImpl(clientEnvironment); + this.sessionTools = new SessionToolsImpl(clientEnvironment); + } + + public frostfs.session.Types.SessionToken getOrCreateSession(SessionToken sessionToken) { + return sessionTools.getOrCreateSession(sessionToken, getContext()); } @Override public ObjectHeader getObjectHead(ContainerId cid, ObjectId oid) { - var address = Types.Address.newBuilder() - .setContainerId(ContainerIdMapper.toGrpcMessage(cid)) - .setObjectId(ObjectIdMapper.toGrpcMessage(oid)) - .build(); - var body = Service.HeadRequest.Body.newBuilder() - .setAddress(address) - .build(); - var request = Service.HeadRequest.newBuilder() - .setBody(body); + if (isNull(cid) || isNull(oid)) { + throw new IllegalArgumentException(ERROR_PARAMS_MISSING); + } - RequestConstructor.addDefaultMetaHeader(request); - sign(request, getContext().getKey()); + var request = createHeadRequest(ContainerIdMapper.toGrpcMessage(cid), ObjectIdMapper.toGrpcMessage(oid)); + + var response = objectServiceBlockingClient.head(request); - var response = objectServiceBlockingClient.head(request.build()); Verifier.checkResponse(response); return ObjectHeaderMapper.toModel(response.getBody().getHeader().getHeader()); @@ -75,66 +74,25 @@ public class ObjectClientImpl extends ContextAccessor implements ObjectClient { @Override public ObjectFrostFS getObject(ContainerId cid, ObjectId oid) { - var sessionToken = getContext().getFrostFSClient().createSessionInternal(-1); + var request = createGetRequest(ContainerIdMapper.toGrpcMessage(cid), ObjectIdMapper.toGrpcMessage(oid)); - var address = Types.Address.newBuilder() - .setContainerId(ContainerIdMapper.toGrpcMessage(cid)) - .setObjectId(ObjectIdMapper.toGrpcMessage(oid)) - .build(); - var body = Service.GetRequest.Body.newBuilder() - .setAddress(address) - .build(); - var request = Service.GetRequest.newBuilder() - .setBody(body); - - RequestConstructor.addDefaultMetaHeader(request); - addObjectSessionToken( - request, sessionToken, ContainerIdMapper.toGrpcMessage(cid), ObjectIdMapper.toGrpcMessage(oid), - frostfs.session.Types.ObjectSessionContext.Verb.GET, getContext().getKey() - ); - sign(request, getContext().getKey()); - - var obj = getObject(request.build()); - return ObjectFrostFSMapper.toModel(obj); + return getObject(request); } - @Override public void deleteObject(ContainerId cid, ObjectId oid) { - var address = Types.Address.newBuilder() - .setContainerId(ContainerIdMapper.toGrpcMessage(cid)) - .setObjectId(ObjectIdMapper.toGrpcMessage(oid)) - .build(); - var body = Service.DeleteRequest.Body.newBuilder() - .setAddress(address) - .build(); - var request = Service.DeleteRequest.newBuilder() - .setBody(body); + var request = createDeleteRequest(ContainerIdMapper.toGrpcMessage(cid), ObjectIdMapper.toGrpcMessage(oid)); - RequestConstructor.addDefaultMetaHeader(request); - sign(request, getContext().getKey()); + var response = objectServiceBlockingClient.delete(request); - var response = objectServiceBlockingClient.delete(request.build()); Verifier.checkResponse(response); } @Override public Iterable searchObjects(ContainerId cid, ObjectFilter... filters) { - var body = Service.SearchRequest.Body.newBuilder() - .setContainerId(ContainerIdMapper.toGrpcMessage(cid)) - .setVersion(1);// TODO: clarify this param + var request = createSearchRequest(ContainerIdMapper.toGrpcMessage(cid), filters); - for (ObjectFilter filter : filters) { - body.addFilters(ObjectFilterMapper.toGrpcMessage(filter)); - } - - var request = Service.SearchRequest.newBuilder() - .setBody(body.build()); - - RequestConstructor.addDefaultMetaHeader(request); - sign(request, getContext().getKey()); - - var objectsIds = searchObjects(request.build()); + var objectsIds = searchObjects(request); return Iterables.transform(objectsIds, input -> new ObjectId(input.getValue().toByteArray())); } @@ -143,179 +101,188 @@ public class ObjectClientImpl extends ContextAccessor implements ObjectClient { public ObjectId putObject(PutObjectParameters parameters) { parameters.validate(); - return parameters.clientCut ? putClientCutObject(parameters) : putStreamObject(parameters); + if (parameters.isClientCut()) { + return putClientCutObject(parameters); + } + + if (parameters.getHeader().getPayloadLength() > 0) { + parameters.setFullLength(parameters.getHeader().getPayloadLength()); + } else { + parameters.setFullLength(getStreamSize(parameters.getPayload())); + } + + return putStreamObject(parameters).getObjectId(); } + @Override public ObjectId putSingleObject(ObjectFrostFS modelObject) { - var sessionToken = getContext().getFrostFSClient().createSessionInternal(-1); - var grpcObject = objectToolsImpl.createObject(modelObject); - var request = Service.PutSingleRequest.newBuilder() - .setBody(Service.PutSingleRequest.Body.newBuilder().setObject(grpcObject).build()); + var request = createPutSingleRequest(grpcObject); - - RequestConstructor.addDefaultMetaHeader(request); - addObjectSessionToken( - request, sessionToken, grpcObject.getHeader().getContainerId(), grpcObject.getObjectId(), - frostfs.session.Types.ObjectSessionContext.Verb.PUT, getContext().getKey() - ); - sign(request, getContext().getKey()); - - var response = objectServiceBlockingClient.putSingle(request.build()); + var response = objectServiceBlockingClient.putSingle(request); Verifier.checkResponse(response); return new ObjectId(grpcObject.getObjectId().getValue().toByteArray()); } - private frostfs.object.Types.Object getObject(Service.GetRequest request) { - var iterator = getObjectInit(request); - var obj = iterator.readHeader(); - var payload = new byte[Math.toIntExact(obj.getHeader().getPayloadLength())]; - var offset = 0; - var chunk = iterator.readChunk(); + private ObjectFrostFS getObject(Service.GetRequest request) { + var reader = getObjectInit(request); - while (nonNull(chunk)) { - System.arraycopy(chunk, 0, payload, offset, chunk.length); - offset += chunk.length; - chunk = iterator.readChunk(); - } + var grpcObject = reader.readHeader(); + var modelObject = ObjectFrostFSMapper.toModel(grpcObject); - return obj.toBuilder().setPayload(ByteString.copyFrom(payload)).build(); + modelObject.setObjectReader(reader); + + return modelObject; } - private ObjectReader getObjectInit(Service.GetRequest initRequest) { + private ObjectReaderImpl getObjectInit(Service.GetRequest initRequest) { if (initRequest.getSerializedSize() == 0) { throw new IllegalArgumentException(initRequest.getClass().getName()); } - return new ObjectReader(objectServiceBlockingClient.get(initRequest)); + return new ObjectReaderImpl(objectServiceBlockingClient.get(initRequest)); } - private ObjectId putStreamObject(PutObjectParameters parameters) { - var header = parameters.getHeader(); + private PutObjectResult putStreamObject(PutObjectParameters parameters) { + var chunkSize = parameters.getBufferMaxSize() > 0 ? parameters.getBufferMaxSize() : AppConst.OBJECT_CHUNK_SIZE; - var sessionToken = getContext().getFrostFSClient().createSessionInternal(-1); + var restBytes = parameters.getFullLength() - parameters.getCurrentStreamPosition(); - var hdr = ObjectHeaderMapper.toGrpcMessage(header); - hdr = hdr.toBuilder() - .setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId())) - .setVersion(VersionMapper.toGrpcMessage(getContext().getVersion())) - .build(); + chunkSize = (int) Math.min(restBytes, chunkSize); - var oid = Types.ObjectID.newBuilder().setValue(getSha256(hdr)).build(); + byte[] chunkBuffer = parameters.getCustomerBuffer() != null + ? parameters.getCustomerBuffer() + : new byte[chunkSize];//todo change to pool - var initRequest = Service.PutRequest.newBuilder() - .setBody( - Service.PutRequest.Body.newBuilder() - .setInit( - Service.PutRequest.Body.Init.newBuilder().setHeader(hdr).build() - ).build() - ); + var sentBytes = 0; - RequestConstructor.addDefaultMetaHeader(initRequest); - addObjectSessionToken( - initRequest, sessionToken, hdr.getContainerId(), oid, - frostfs.session.Types.ObjectSessionContext.Verb.PUT, getContext().getKey() - ); - sign(initRequest, getContext().getKey()); + // 0 means no limit from client, so server side cut is performed + var objectLimitSize = parameters.isClientCut() ? parameters.getMaxObjectSizeCache() : 0; + var stream = getUploadStream(parameters); - var writer = putObjectInit(initRequest.build()); + while (objectLimitSize == 0 || sentBytes < objectLimitSize) { + // send chunks limited to default or user's settings + var bufferSize = objectLimitSize > 0 ? Math.min(objectLimitSize - sentBytes, chunkSize) : chunkSize; - var bufferSize = parameters.getBufferMaxSize() > 0 ? parameters.getBufferMaxSize() : AppConst.OBJECT_CHUNK_SIZE; - bufferSize = (int) Math.min(getStreamSize(parameters.getPayload()), bufferSize); - bufferSize = header.getPayloadLength() > 0 ? (int) Math.min(header.getPayloadLength(), bufferSize) : bufferSize; + var bytesCount = readNBytes(parameters.getPayload(), chunkBuffer, bufferSize); - var buffer = new byte[bufferSize]; - while (true) { - var bytesCount = readNBytes(parameters.getPayload(), buffer, bufferSize); - if (bytesCount <= 0) { + if (bytesCount == 0) { break; } - var chunkRequest = Service.PutRequest.newBuilder(initRequest.build()) - .setBody( - Service.PutRequest.Body.newBuilder() - .setChunk(ByteString.copyFrom(Arrays.copyOfRange(buffer, 0, bytesCount))) - .build() - ) + sentBytes += bytesCount; + + var body = Service.PutRequest.Body.newBuilder() + .setChunk(ByteString.copyFrom(chunkBuffer, 0, bytesCount)) + .build(); + var chunkRequest = Service.PutRequest.newBuilder() + .setBody(body) .clearVerifyHeader(); + sign(chunkRequest, getContext().getKey()); - writer.write(chunkRequest.build()); + + stream.write(chunkRequest.build()); } - var response = writer.complete(); + var response = stream.complete(); Verifier.checkResponse(response); - return new ObjectId(response.getBody().getObjectId().getValue().toByteArray()); + var objectId = new ObjectId(response.getBody().getObjectId().getValue().toByteArray()); + return new PutObjectResult(objectId, sentBytes); } private ObjectId putClientCutObject(PutObjectParameters parameters) { var header = parameters.getHeader(); + var tokenRaw = getOrCreateSession(parameters.getSessionToken()); + var token = new SessionToken(SessionMapper.serialize(tokenRaw)); + parameters.setSessionToken(token); - var networkSettings = getContext().getFrostFSClient().getNetworkSettings(); - var payloadSize = getStreamSize(parameters.getPayload()); - var objectSize = (int) Math.min(payloadSize, networkSettings.getMaxObjectSize()); - var fullLength = header.getPayloadLength() == 0 ? payloadSize : header.getPayloadLength(); - if (fullLength == 0) { - throw new IllegalArgumentException(ERROR_PAYLOAD); + var fullLength = header.getPayloadLength() == 0 + ? getStreamSize(parameters.getPayload()) + : header.getPayloadLength(); + + parameters.setFullLength(fullLength); + + if (parameters.getMaxObjectSizeCache() == 0) { + var networkSettings = getContext().getFrostFSClient().getNetworkSettings(); + parameters.setMaxObjectSizeCache((int) networkSettings.getMaxObjectSize()); } - var buffer = new byte[objectSize]; - var largeObject = new LargeObject(header.getContainerId()); - var split = new Split(); + var restBytes = fullLength - parameters.getCurrentStreamPosition(); + var objectSize = restBytes > 0 + ? Math.min(parameters.getMaxObjectSizeCache(), restBytes) + : parameters.getMaxObjectSizeCache(); - ObjectId objectId; - List sentObjectIds = new ArrayList<>(); - ObjectFrostFS currentObject; + //define collection capacity + var restPart = (restBytes % objectSize) > 0 ? 1 : 0; + var objectsCount = fullLength > 0 ? (int) (restBytes / objectSize) + restPart : 0; - while (true) { - var bytesCount = readNBytes(parameters.getPayload(), buffer, objectSize); - if (CollectionUtils.isNotEmpty(sentObjectIds)) { - split.setPrevious(sentObjectIds.get(sentObjectIds.size() - 1)); - } + List sentObjectIds = new ArrayList<>(objectsCount); - largeObject.appendBlock(buffer, bytesCount); + // keep attributes for the large object + var attributes = parameters.getHeader().getAttributes(); - currentObject = new ObjectFrostFS( - header.getContainerId(), - bytesCount < objectSize ? Arrays.copyOfRange(buffer, 0, bytesCount) : buffer - ); - currentObject.setSplit(split); + Split split = new Split(); + parameters.getHeader().setSplit(split); + parameters.getHeader().setAttributes(new ArrayList<>()); - if (largeObject.getPayloadLength() == fullLength) { - break; - } + // send all parts except the last one as separate Objects + while (restBytes > (long) parameters.getMaxObjectSizeCache()) { + var previous = CollectionUtils.isNotEmpty(sentObjectIds) + ? sentObjectIds.get(sentObjectIds.size() - 1) + : null; + split.setPrevious(previous); - objectId = putSingleObject(currentObject); + var result = putStreamObject(parameters); - sentObjectIds.add(objectId); + sentObjectIds.add(result.getObjectId()); + + restBytes -= result.getObjectSize(); } - if (CollectionUtils.isEmpty(sentObjectIds)) { - currentObject.addAttributes(parameters.getHeader().getAttributes()); - return putSingleObject(currentObject); + // send the last part and create linkObject + if (CollectionUtils.isNotEmpty(sentObjectIds)) { + var largeObjectHeader = + new ObjectHeader(header.getContainerId(), ObjectType.REGULAR, attributes, fullLength, null); + + split.setParentHeader(largeObjectHeader); + + var result = putStreamObject(parameters); + + sentObjectIds.add(result.getObjectId()); + + var linkObject = new LinkObject(header.getContainerId(), split.getSplitId(), largeObjectHeader); + linkObject.addChildren(sentObjectIds); + + putSingleObject(linkObject); + + return split.getParent(); } - largeObject.addAttributes(parameters.getHeader().getAttributes()); - largeObject.calculateHash(); + // We are here if the payload is placed to one Object. It means no cut action, just simple PUT. + var singlePartResult = putStreamObject(parameters); - currentObject.setParent(largeObject); + return singlePartResult.getObjectId(); + } - objectId = putSingleObject(currentObject); + private ObjectWriter getUploadStream(PutObjectParameters parameters) { + var header = parameters.getHeader(); - sentObjectIds.add(objectId); + header.setOwnerId(getContext().getOwnerId()); + header.setVersion(getContext().getVersion()); - var linkObject = new LinkObject(header.getContainerId(), split.getSplitId(), largeObject); - linkObject.addChildren(sentObjectIds); + var grpcHeader = ObjectHeaderMapper.toGrpcMessage(header); + grpcHeader = objectToolsImpl.updateSplitValues(grpcHeader, header.getSplit()); - linkObject.getHeader().getAttributes().clear(); + var oid = Types.ObjectID.newBuilder().setValue(getSha256(grpcHeader)).build(); - putSingleObject(linkObject); + var initRequest = createInitPutRequest(oid, grpcHeader); - return objectToolsImpl.calculateObjectId(largeObject.getHeader()); + return putObjectInit(initRequest); } private ObjectWriter putObjectInit(Service.PutRequest initRequest) { @@ -333,12 +300,12 @@ public class ObjectClientImpl extends ContextAccessor implements ObjectClient { var ids = reader.read(); List result = new ArrayList<>(); - while (nonNull(ids) && !ids.isEmpty()) { + while (CollectionUtils.isNotEmpty(ids)) { result.addAll(ids); ids = reader.read(); } - return result; + return result;//todo return yield } private SearchReader getSearchReader(Service.SearchRequest initRequest) { @@ -364,4 +331,168 @@ public class ObjectClientImpl extends ContextAccessor implements ObjectClient { throw new IllegalArgumentException(exp.getMessage()); } } + + private Service.HeadRequest createHeadRequest(Types.ContainerID cid, Types.ObjectID oid) { + var address = Types.Address.newBuilder() + .setContainerId(cid) + .setObjectId(oid) + .build(); + var body = Service.HeadRequest.Body.newBuilder() + .setAddress(address) + .build(); + var request = Service.HeadRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.HEAD, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, null, sessionToken); + sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.GetRequest createGetRequest(Types.ContainerID cid, Types.ObjectID oid) { + var address = Types.Address.newBuilder() + .setContainerId(cid) + .setObjectId(oid) + .build(); + var body = Service.GetRequest.Body.newBuilder() + .setAddress(address) + .build(); + var request = Service.GetRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.GET, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, null, sessionToken); + sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.DeleteRequest createDeleteRequest(Types.ContainerID cid, Types.ObjectID oid) { + var address = Types.Address.newBuilder() + .setContainerId(cid) + .setObjectId(oid) + .build(); + var body = Service.DeleteRequest.Body.newBuilder() + .setAddress(address) + .build(); + var request = Service.DeleteRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.DELETE, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, null, sessionToken); + sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.SearchRequest createSearchRequest(Types.ContainerID cid, ObjectFilter... filters) { + var address = Types.Address.newBuilder() + .setContainerId(cid) + .build(); + + var body = Service.SearchRequest.Body.newBuilder() + .setContainerId(cid) + .setVersion(1);// TODO: clarify this param + + for (ObjectFilter filter : filters) { + body.addFilters(ObjectFilterMapper.toGrpcMessage(filter)); + } + + var request = Service.SearchRequest.newBuilder() + .setBody(body.build()); + + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.SEARCH, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, null, sessionToken); + sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.PutRequest createInitPutRequest(Types.ObjectID oid, frostfs.object.Types.Header header) { + var address = Types.Address.newBuilder() + .setContainerId(header.getContainerId()) + .setObjectId(oid) + .build(); + var init = Service.PutRequest.Body.Init.newBuilder() + .setHeader(header) + .build(); + var body = Service.PutRequest.Body.newBuilder() + .setInit(init) + .build(); + var request = Service.PutRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.PUT, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, null, sessionToken); + sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.PutSingleRequest createPutSingleRequest(frostfs.object.Types.Object grpcObject) { + var address = Types.Address.newBuilder() + .setContainerId(grpcObject.getHeader().getContainerId()) + .setObjectId(grpcObject.getObjectId()) + .build(); + var body = Service.PutSingleRequest.Body.newBuilder() + .setObject(grpcObject) + .build(); + var request = Service.PutSingleRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(null); + + sessionToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.PUT, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, null, sessionToken); + sign(request, getContext().getKey()); + + return request.build(); + } } diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/ObjectToolsImpl.java b/client/src/main/java/info/frostfs/sdk/services/impl/ObjectToolsImpl.java index 2fb3b42..9730f34 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/ObjectToolsImpl.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/ObjectToolsImpl.java @@ -5,17 +5,21 @@ import frostfs.object.Types; import info.frostfs.sdk.dto.object.ObjectFrostFS; import info.frostfs.sdk.dto.object.ObjectHeader; import info.frostfs.sdk.dto.object.ObjectId; +import info.frostfs.sdk.dto.object.Split; import info.frostfs.sdk.jdo.ClientEnvironment; -import info.frostfs.sdk.mappers.OwnerIdMapper; -import info.frostfs.sdk.mappers.VersionMapper; +import info.frostfs.sdk.mappers.netmap.VersionMapper; import info.frostfs.sdk.mappers.object.ObjectHeaderMapper; import info.frostfs.sdk.mappers.object.ObjectIdMapper; +import info.frostfs.sdk.mappers.object.OwnerIdMapper; import info.frostfs.sdk.services.ContextAccessor; import info.frostfs.sdk.services.ToolsClient; -import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.stream.Collectors; import static info.frostfs.sdk.Helper.getSha256; import static info.frostfs.sdk.tools.RequestSigner.signData; +import static java.util.Objects.isNull; import static java.util.Objects.nonNull; public class ObjectToolsImpl extends ContextAccessor implements ToolsClient { @@ -34,52 +38,29 @@ public class ObjectToolsImpl extends ContextAccessor implements ToolsClient { public ObjectId calculateObjectId(ObjectHeader header) { var grpcHeader = createHeader(header, new byte[]{}); + if (nonNull(header.getSplit())) { + grpcHeader = updateSplitValues(grpcHeader, header.getSplit()); + } + return ObjectIdMapper.toModel( frostfs.refs.Types.ObjectID.newBuilder().setValue(getSha256(grpcHeader)).build() ); } public Types.Object createObject(ObjectFrostFS objectFrostFs) { - var grpcHeaderBuilder = ObjectHeaderMapper.toGrpcMessage(objectFrostFs.getHeader()).toBuilder() - .setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId())) - .setVersion(VersionMapper.toGrpcMessage(getContext().getVersion())) - .setPayloadLength(objectFrostFs.getPayload().length) - .setPayloadHash(sha256Checksum(objectFrostFs.getPayload())); + objectFrostFs.getHeader().setOwnerId(getContext().getOwnerId()); + objectFrostFs.getHeader().setVersion(getContext().getVersion()); + objectFrostFs.getHeader().setPayloadLength(objectFrostFs.getPayload().length); + + var grpcHeader = ObjectHeaderMapper.toGrpcMessage(objectFrostFs.getHeader()).toBuilder() + .setPayloadHash(sha256Checksum(objectFrostFs.getPayload())) + .build(); var split = objectFrostFs.getHeader().getSplit(); if (nonNull(split)) { - var splitGrpc = Types.Header.Split.newBuilder() - .setSplitId( - nonNull(split.getSplitId()) - ? ByteString.copyFrom(split.getSplitId().toBinary()) - : null - ); - - ListUtils.emptyIfNull(split.getChildren()).stream() - .map(ObjectIdMapper::toGrpcMessage) - .forEach(splitGrpc::addChildren); - - - if (nonNull(split.getParentHeader())) { - var grpcParentHeader = createHeader(split.getParentHeader(), new byte[]{}); - var parent = frostfs.refs.Types.ObjectID.newBuilder().setValue(getSha256(grpcParentHeader)).build(); - var parentSig = frostfs.refs.Types.Signature.newBuilder() - .setKey(ByteString.copyFrom(getContext().getKey().getPublicKeyByte())) - .setSign(ByteString.copyFrom(signData(getContext().getKey(), parent.toByteArray()))); - - splitGrpc.setParent(parent) - .setParentHeader(grpcParentHeader) - .setParentSignature(parentSig); - - split.setParent(ObjectIdMapper.toModel(parent)); - } - if (nonNull(split.getPrevious())) { - splitGrpc.setPrevious(ObjectIdMapper.toGrpcMessage(split.getPrevious())); - } - grpcHeaderBuilder.setSplit(splitGrpc); + grpcHeader = updateSplitValues(grpcHeader, split); } - var grpcHeader = grpcHeaderBuilder.build(); var objectId = frostfs.refs.Types.ObjectID.newBuilder().setValue(getSha256(grpcHeader)).build(); var sig = frostfs.refs.Types.Signature.newBuilder() .setKey(ByteString.copyFrom(getContext().getKey().getPublicKeyByte())) @@ -92,14 +73,48 @@ public class ObjectToolsImpl extends ContextAccessor implements ToolsClient { .build(); } + public Types.Header updateSplitValues(Types.Header grpcHeader, Split split) { + if (isNull(split)) { + return grpcHeader; + } + + var grpcSplit = grpcHeader.getSplit().toBuilder() + .setSplitId(ByteString.copyFrom(split.getSplitId().toBinary())); + + if (CollectionUtils.isNotEmpty(split.getChildren())) { + var grpcChildren = split.getChildren().stream() + .map(ObjectIdMapper::toGrpcMessage) + .collect(Collectors.toList()); + grpcSplit.addAllChildren(grpcChildren); + } + + if (nonNull(split.getParentHeader())) { + var grpcParentHeader = createHeader(split.getParentHeader(), new byte[]{}); + var parentObjectId = frostfs.refs.Types.ObjectID.newBuilder().setValue(getSha256(grpcParentHeader)).build(); + var signature = frostfs.refs.Types.Signature.newBuilder() + .setKey(ByteString.copyFrom(getContext().getKey().getPublicKeyByte())) + .setSign(ByteString.copyFrom(signData(getContext().getKey(), parentObjectId.toByteArray()))) + .build(); + + + grpcSplit + .setParent(parentObjectId) + .setParentHeader(grpcParentHeader) + .setParentSignature(signature); + + split.setParent(ObjectIdMapper.toModel(parentObjectId)); + } + + grpcSplit.setPrevious(ObjectIdMapper.toGrpcMessage(split.getPrevious())).build(); + return grpcHeader.toBuilder().setSplit(grpcSplit.build()).build(); + } + private Types.Header createHeader(ObjectHeader header, byte[] payload) { var grpcHeader = ObjectHeaderMapper.toGrpcMessage(header).toBuilder() .setOwnerId(OwnerIdMapper.toGrpcMessage(getContext().getOwnerId())) .setVersion(VersionMapper.toGrpcMessage(getContext().getVersion())); - if (header.getPayloadCheckSum() != null) { - grpcHeader.setPayloadHash(sha256Checksum(header.getPayloadCheckSum())); - } else if (payload != null) { + if (payload != null) { grpcHeader.setPayloadHash(sha256Checksum(payload)); } diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/SessionClientImpl.java b/client/src/main/java/info/frostfs/sdk/services/impl/SessionClientImpl.java index 137c178..8151fc9 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/SessionClientImpl.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/SessionClientImpl.java @@ -3,13 +3,14 @@ package info.frostfs.sdk.services.impl; import frostfs.session.Service; import frostfs.session.SessionServiceGrpc; import frostfs.session.Types; -import info.frostfs.sdk.dto.SessionToken; +import info.frostfs.sdk.dto.session.SessionToken; import info.frostfs.sdk.jdo.ClientEnvironment; -import info.frostfs.sdk.mappers.OwnerIdMapper; -import info.frostfs.sdk.mappers.SessionMapper; +import info.frostfs.sdk.mappers.object.OwnerIdMapper; +import info.frostfs.sdk.mappers.session.SessionMapper; import info.frostfs.sdk.services.ContextAccessor; import info.frostfs.sdk.services.SessionClient; import info.frostfs.sdk.tools.RequestConstructor; +import info.frostfs.sdk.tools.Verifier; import static info.frostfs.sdk.tools.RequestSigner.sign; @@ -25,7 +26,7 @@ public class SessionClientImpl extends ContextAccessor implements SessionClient public SessionToken createSession(long expiration) { var sessionToken = createSessionInternal(expiration); var token = SessionMapper.serialize(sessionToken); - return new SessionToken(new byte[]{}, token); + return new SessionToken(token); } public Types.SessionToken createSessionInternal(long expiration) { @@ -36,24 +37,26 @@ public class SessionClientImpl extends ContextAccessor implements SessionClient var request = Service.CreateRequest.newBuilder() .setBody(body); - RequestConstructor.addDefaultMetaHeader(request); + RequestConstructor.addMetaHeader(request); sign(request, getContext().getKey()); return createSession(request.build()); } private Types.SessionToken createSession(Service.CreateRequest request) { - var resp = serviceBlockingStub.create(request); + var response = serviceBlockingStub.create(request); + + Verifier.checkResponse(response); var lifetime = Types.SessionToken.Body.TokenLifetime.newBuilder() .setExp(request.getBody().getExpiration()) - .setIat(resp.getMetaHeader().getEpoch()) - .setNbf(resp.getMetaHeader().getEpoch()) + .setIat(response.getMetaHeader().getEpoch()) + .setNbf(response.getMetaHeader().getEpoch()) .build(); var body = Types.SessionToken.Body.newBuilder() - .setId(resp.getBody().getId()) - .setSessionKey(resp.getBody().getSessionKey()) + .setId(response.getBody().getId()) + .setSessionKey(response.getBody().getSessionKey()) .setOwnerId(request.getBody().getOwnerId()) .setLifetime(lifetime) .build(); diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/SessionToolsImpl.java b/client/src/main/java/info/frostfs/sdk/services/impl/SessionToolsImpl.java new file mode 100644 index 0000000..e0d3a06 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/services/impl/SessionToolsImpl.java @@ -0,0 +1,27 @@ +package info.frostfs.sdk.services.impl; + +import frostfs.session.Types; +import info.frostfs.sdk.dto.session.SessionToken; +import info.frostfs.sdk.jdo.ClientEnvironment; +import info.frostfs.sdk.mappers.session.SessionMapper; +import info.frostfs.sdk.services.ContextAccessor; +import info.frostfs.sdk.services.SessionTools; + +import static java.util.Objects.isNull; + +public class SessionToolsImpl extends ContextAccessor implements SessionTools { + + public SessionToolsImpl(ClientEnvironment clientEnvironment) { + super(clientEnvironment); + } + + @Override + public Types.SessionToken getOrCreateSession(SessionToken sessionToken, ClientEnvironment env) { + if (isNull(sessionToken)) { + return env.getFrostFSClient().createSessionInternal(-1); + } + + return SessionMapper.deserializeSessionToken(sessionToken.getToken()); + } + +} diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectReader.java b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectReaderImpl.java similarity index 89% rename from client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectReader.java rename to client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectReaderImpl.java index d686921..b5f50d4 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectReader.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectReaderImpl.java @@ -2,17 +2,18 @@ package info.frostfs.sdk.services.impl.rwhelper; import frostfs.object.Service; import frostfs.object.Types; +import info.frostfs.sdk.dto.object.ObjectReader; import info.frostfs.sdk.tools.Verifier; import java.util.Iterator; -public class ObjectReader { +public class ObjectReaderImpl implements ObjectReader { public static final String ERROR_UNEXPECTED_STREAM = "unexpected end of stream"; public static final String ERROR_UNEXPECTED_MESSAGE_TYPE = "unexpected message type"; public Iterator call; - public ObjectReader(Iterator call) { + public ObjectReaderImpl(Iterator call) { this.call = call; } diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectWriter.java b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectWriter.java index 7d6271b..110df20 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectWriter.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectWriter.java @@ -2,11 +2,13 @@ package info.frostfs.sdk.services.impl.rwhelper; import frostfs.object.ObjectServiceGrpc; import frostfs.object.Service; +import info.frostfs.sdk.utils.WaitUtil; import io.grpc.stub.StreamObserver; import static java.util.Objects.isNull; public class ObjectWriter { + private static final long POLL_INTERVAL = 10; private final StreamObserver requestObserver; private final PutResponseCallback responseObserver; @@ -29,7 +31,7 @@ public class ObjectWriter { requestObserver.onCompleted(); while (isNull(responseObserver.getResponse())) { - System.out.println("Waiting response"); + WaitUtil.sleep(POLL_INTERVAL); } return responseObserver.getResponse(); diff --git a/client/src/main/java/info/frostfs/sdk/tools/GrpcClient.java b/client/src/main/java/info/frostfs/sdk/tools/GrpcClient.java index 96ef9b2..747a249 100644 --- a/client/src/main/java/info/frostfs/sdk/tools/GrpcClient.java +++ b/client/src/main/java/info/frostfs/sdk/tools/GrpcClient.java @@ -3,6 +3,7 @@ package info.frostfs.sdk.tools; import io.grpc.Channel; import io.grpc.ChannelCredentials; import io.grpc.netty.NettyChannelBuilder; +import org.apache.commons.lang3.StringUtils; import java.net.URI; import java.net.URISyntaxException; @@ -11,17 +12,23 @@ import static java.util.Objects.isNull; public class GrpcClient { private static final String ERROR_INVALID_HOST_TEMPLATE = "Host %s has invalid format. Error: %s"; + private static final String ERROR_EMPTY_HOST_MESSAGE = "Host not provided"; private GrpcClient() { } - public static Channel initGrpcChannel(String host, ChannelCredentials creds) { + public static Channel initGrpcChannel(String host, ChannelCredentials credentials) { + if (StringUtils.isBlank(host)) { + throw new IllegalArgumentException(ERROR_EMPTY_HOST_MESSAGE); + } + try { URI uri = new URI(host); - var channelBuilder = isNull(creds) ? NettyChannelBuilder.forAddress(uri.getHost(), uri.getPort()) - : NettyChannelBuilder.forAddress(uri.getHost(), uri.getPort(), creds); + var channelBuilder = isNull(credentials) + ? NettyChannelBuilder.forAddress(uri.getHost(), uri.getPort()).usePlaintext() + : NettyChannelBuilder.forAddress(uri.getHost(), uri.getPort(), credentials); - return channelBuilder.usePlaintext().build(); + return channelBuilder.build(); } catch (URISyntaxException exp) { throw new IllegalArgumentException(String.format(ERROR_INVALID_HOST_TEMPLATE, host, exp.getMessage())); } diff --git a/client/src/main/java/info/frostfs/sdk/tools/MessageHelper.java b/client/src/main/java/info/frostfs/sdk/tools/MessageHelper.java deleted file mode 100644 index cb0005f..0000000 --- a/client/src/main/java/info/frostfs/sdk/tools/MessageHelper.java +++ /dev/null @@ -1,18 +0,0 @@ -package info.frostfs.sdk.tools; - -import com.google.protobuf.Message; -import com.google.protobuf.MessageOrBuilder; - -public class MessageHelper { - - private MessageHelper() { - } - - public static Message getField(MessageOrBuilder messageOrBuilder, String fieldName) { - return (Message) messageOrBuilder.getField(messageOrBuilder.getDescriptorForType().findFieldByName(fieldName)); - } - - public static void setField(Message.Builder builder, String fieldName, Object value) { - builder.setField(builder.getDescriptorForType().findFieldByName(fieldName), value); - } -} diff --git a/client/src/main/java/info/frostfs/sdk/tools/RequestConstructor.java b/client/src/main/java/info/frostfs/sdk/tools/RequestConstructor.java index 047d146..c50c532 100644 --- a/client/src/main/java/info/frostfs/sdk/tools/RequestConstructor.java +++ b/client/src/main/java/info/frostfs/sdk/tools/RequestConstructor.java @@ -1,63 +1,130 @@ package info.frostfs.sdk.tools; +import com.google.protobuf.ByteString; import com.google.protobuf.Message; import frostfs.session.Types; -import info.frostfs.sdk.dto.MetaHeader; +import info.frostfs.sdk.dto.response.MetaHeader; import info.frostfs.sdk.jdo.ECDsa; -import info.frostfs.sdk.mappers.MetaHeaderMapper; +import info.frostfs.sdk.mappers.response.MetaHeaderMapper; +import org.apache.commons.collections4.MapUtils; + +import java.util.Map; +import java.util.stream.Collectors; import static info.frostfs.sdk.constants.FieldConst.META_HEADER_FIELD_NAME; -import static info.frostfs.sdk.tools.MessageHelper.getField; -import static info.frostfs.sdk.tools.MessageHelper.setField; import static info.frostfs.sdk.tools.RequestSigner.signMessagePart; +import static info.frostfs.sdk.utils.MessageHelper.getField; +import static info.frostfs.sdk.utils.MessageHelper.setField; import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; public class RequestConstructor { + private static final String ERROR_MESSAGE = "The message does not contain a field " + META_HEADER_FIELD_NAME; private RequestConstructor() { } - public static void addDefaultMetaHeader(Message.Builder request) { - addMetaHeader(request, null); + public static void addMetaHeader(Message.Builder request) { + addMetaHeader(request, null, null); } - public static void addMetaHeader(Message.Builder request, Types.RequestMetaHeader metaHeader) { + public static void addMetaHeader(Message.Builder request, Map xHeaders) { + addMetaHeader(request, xHeaders, null); + } + + public static void addMetaHeader(Message.Builder request, + Map xHeaders, + Types.SessionToken sessionToken) { if (isNull(request)) { return; } - if (isNull(metaHeader) || metaHeader.getSerializedSize() == 0) { - metaHeader = MetaHeaderMapper.toGrpcMessage(new MetaHeader()); - setField(request, META_HEADER_FIELD_NAME, metaHeader); + if (isNull(request.getDescriptorForType().findFieldByName(META_HEADER_FIELD_NAME))) { + throw new IllegalArgumentException(ERROR_MESSAGE); } + + if (((Types.RequestMetaHeader) getField(request, META_HEADER_FIELD_NAME)).getSerializedSize() > 0) { + return; + } + + var metaHeader = MetaHeaderMapper.toGrpcMessageBuilder(new MetaHeader()); + + if (nonNull(sessionToken) && sessionToken.getSerializedSize() > 0) { + metaHeader.setSessionToken(sessionToken); + } + + if (MapUtils.isNotEmpty(xHeaders)) { + var grpcXHeaders = xHeaders.entrySet() + .stream() + .map(e -> Types.XHeader.newBuilder().setKey(e.getKey()).setValue(e.getValue()).build()) + .collect(Collectors.toList()); + + metaHeader.addAllXHeaders(grpcXHeaders); + } + + setField(request, META_HEADER_FIELD_NAME, metaHeader.build()); } - public static void addObjectSessionToken(Message.Builder request, - Types.SessionToken sessionToken, - frostfs.refs.Types.ContainerID cid, - frostfs.refs.Types.ObjectID oid, - Types.ObjectSessionContext.Verb verb, - ECDsa key) { - if (isNull(request) || isNull(sessionToken)) { - return; + public static Types.SessionToken createObjectTokenContext(Types.SessionToken sessionToken, + frostfs.refs.Types.Address address, + Types.ObjectSessionContext.Verb verb, + ECDsa key) { + if (isNull(sessionToken) || sessionToken.getBody().getObject().getTarget().getSerializedSize() > 0) { + return sessionToken; } - var header = (Types.RequestMetaHeader) getField(request, META_HEADER_FIELD_NAME); - if (header.getSessionToken().getSerializedSize() > 0) { - return; + var target = Types.ObjectSessionContext.Target.newBuilder() + .setContainer(address.getContainerId()); + + if (address.getObjectId().getSerializedSize() > 0) { + target.addObjects(address.getObjectId()); } var ctx = Types.ObjectSessionContext.newBuilder() - .setTarget(Types.ObjectSessionContext.Target.newBuilder().setContainer(cid).addObjects(oid).build()) + .setTarget(target.build()) .setVerb(verb) .build(); + var body = sessionToken.getBody().toBuilder() + .setObject(ctx) + .setSessionKey(ByteString.copyFrom(key.getPublicKeyByte())) + .build(); - var body = sessionToken.getBody().toBuilder().setObject(ctx).build(); - sessionToken = sessionToken.toBuilder() + return sessionToken.toBuilder() .setSignature(signMessagePart(key, body)) .setBody(body) .build(); + } - setField(request, META_HEADER_FIELD_NAME, header.toBuilder().setSessionToken(sessionToken).build()); + public static Types.SessionToken createContainerTokenContext(Types.SessionToken sessionToken, + frostfs.refs.Types.ContainerID containerId, + Types.ContainerSessionContext.Verb verb, + frostfs.refs.Types.OwnerID ownerId, + ECDsa key) { + if (isNull(sessionToken) || sessionToken.getBody().getContainer().getContainerId().getSerializedSize() > 0) { + return sessionToken; + } + + var containerSession = Types.ContainerSessionContext.newBuilder().setVerb(verb); + + if (isNull(containerId) || containerId.getSerializedSize() == 0) { + containerSession.setWildcard(true); + } else { + containerSession.setContainerId(containerId); + } + + var bodyBuilder = sessionToken.getBody().toBuilder() + .setContainer(containerSession) + .setSessionKey(ByteString.copyFrom(key.getPublicKeyByte())); + + if (nonNull(ownerId) && ownerId.getSerializedSize() > 0) { + bodyBuilder.setOwnerId(ownerId); + } + + var body = bodyBuilder.build(); + + return sessionToken.toBuilder() + .setSignature(signMessagePart(key, body)) + .setBody(body) + .build(); } } diff --git a/client/src/main/java/info/frostfs/sdk/tools/RequestSigner.java b/client/src/main/java/info/frostfs/sdk/tools/RequestSigner.java index 5cd178f..9bc3cc2 100644 --- a/client/src/main/java/info/frostfs/sdk/tools/RequestSigner.java +++ b/client/src/main/java/info/frostfs/sdk/tools/RequestSigner.java @@ -5,6 +5,7 @@ import com.google.protobuf.Message; import frostfs.session.Types; import info.frostfs.sdk.constants.CryptoConst; import info.frostfs.sdk.jdo.ECDsa; +import info.frostfs.sdk.utils.MessageHelper; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.asn1.sec.SECNamedCurves; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; @@ -92,10 +93,10 @@ public class RequestSigner { } public static void sign(Message.Builder request, ECDsa key) { - var meta = MessageHelper.getField(request, META_HEADER_FIELD_NAME); - var body = MessageHelper.getField(request, BODY_FIELD_NAME); - var verify = MessageHelper.getField(request, VERIFY_HEADER_FIELD_NAME); - var verifyOrigin = MessageHelper.getField(verify, ORIGIN_FIELD_NAME); + var meta = (Message) MessageHelper.getField(request, META_HEADER_FIELD_NAME); + var body = (Message) MessageHelper.getField(request, BODY_FIELD_NAME); + var verify = (Message) MessageHelper.getField(request, VERIFY_HEADER_FIELD_NAME); + var verifyOrigin = (Message) MessageHelper.getField(verify, ORIGIN_FIELD_NAME); Message.Builder verifyBuilder; if (verify instanceof Types.RequestVerificationHeader) { diff --git a/client/src/main/java/info/frostfs/sdk/tools/Verifier.java b/client/src/main/java/info/frostfs/sdk/tools/Verifier.java index f0cd408..3af7898 100644 --- a/client/src/main/java/info/frostfs/sdk/tools/Verifier.java +++ b/client/src/main/java/info/frostfs/sdk/tools/Verifier.java @@ -3,7 +3,9 @@ package info.frostfs.sdk.tools; import com.google.protobuf.Message; import frostfs.session.Types; import info.frostfs.sdk.constants.CryptoConst; -import info.frostfs.sdk.mappers.StatusMapper; +import info.frostfs.sdk.exceptions.ResponseException; +import info.frostfs.sdk.mappers.response.ResponseStatusMapper; +import info.frostfs.sdk.utils.MessageHelper; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.asn1.sec.SECNamedCurves; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; @@ -73,14 +75,14 @@ public class Verifier { } var metaHeader = (Types.ResponseMetaHeader) MessageHelper.getField(response, META_HEADER_FIELD_NAME); - var status = StatusMapper.toModel(metaHeader.getStatus()); + var status = ResponseStatusMapper.toModel(metaHeader.getStatus()); if (!status.isSuccess()) { - throw new IllegalArgumentException(status.toString()); + throw new ResponseException(status); } } public static boolean verify(Message response) { - var body = MessageHelper.getField(response, BODY_FIELD_NAME); + var body = (Message) MessageHelper.getField(response, BODY_FIELD_NAME); var metaHeader = (Types.ResponseMetaHeader) MessageHelper.getField(response, META_HEADER_FIELD_NAME); var verifyHeader = (Types.ResponseVerificationHeader) MessageHelper.getField(response, VERIFY_HEADER_FIELD_NAME); diff --git a/client/src/main/java/info/frostfs/sdk/utils/MessageHelper.java b/client/src/main/java/info/frostfs/sdk/utils/MessageHelper.java new file mode 100644 index 0000000..703db82 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/utils/MessageHelper.java @@ -0,0 +1,30 @@ +package info.frostfs.sdk.utils; + +import com.google.protobuf.Message; +import com.google.protobuf.MessageOrBuilder; +import org.apache.commons.lang3.StringUtils; + +import static java.util.Objects.isNull; + +public class MessageHelper { + private static final String ERROR_MESSAGE = "One of the input parameters is null"; + + private MessageHelper() { + } + + public static Object getField(MessageOrBuilder messageOrBuilder, String fieldName) { + if (isNull(messageOrBuilder) || StringUtils.isBlank(fieldName)) { + throw new IllegalArgumentException(ERROR_MESSAGE); + } + + return messageOrBuilder.getField(messageOrBuilder.getDescriptorForType().findFieldByName(fieldName)); + } + + public static void setField(Message.Builder builder, String fieldName, Object value) { + if (isNull(builder) || StringUtils.isBlank(fieldName) || isNull(value)) { + throw new IllegalArgumentException(ERROR_MESSAGE); + } + + builder.setField(builder.getDescriptorForType().findFieldByName(fieldName), value); + } +} diff --git a/client/src/main/java/info/frostfs/sdk/utils/ValidatorUtils.java b/client/src/main/java/info/frostfs/sdk/utils/ValidatorUtils.java new file mode 100644 index 0000000..20d6b15 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/utils/ValidatorUtils.java @@ -0,0 +1,42 @@ +package info.frostfs.sdk.utils; + +import org.apache.commons.collections4.CollectionUtils; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidationException; +import javax.validation.Validator; +import java.util.Set; + +import static java.util.Objects.isNull; + +public class ValidatorUtils { + private static final String OBJECT_IS_NULL = "object is null"; + private static final String ERROR_PROPERTY_TEMPLATE = "property %s with value %s %s"; + + private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + + public static void validate(T object, Class... classes) { + if (isNull(object)) { + throw new ValidationException(OBJECT_IS_NULL); + } + + Set> violations = validator.validate(object, classes); + + if (CollectionUtils.isEmpty(violations)) { + return; + } + + String[] errors = (String[]) violations.stream() + .map(violation -> String.format( + ERROR_PROPERTY_TEMPLATE, + violation.getPropertyPath().toString(), + violation.getInvalidValue(), + violation.getMessage() + )) + .toArray(); + + throw new ValidationException(String.join(",", errors)); + } +} diff --git a/client/src/main/java/info/frostfs/sdk/utils/WaitUtil.java b/client/src/main/java/info/frostfs/sdk/utils/WaitUtil.java new file mode 100644 index 0000000..27e785d --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/utils/WaitUtil.java @@ -0,0 +1,12 @@ +package info.frostfs.sdk.utils; + +public class WaitUtil { + + public static void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/cryptography/src/main/java/info/frostfs/sdk/ArrayHelper.java b/cryptography/src/main/java/info/frostfs/sdk/ArrayHelper.java index b21a3f2..6ccfe65 100644 --- a/cryptography/src/main/java/info/frostfs/sdk/ArrayHelper.java +++ b/cryptography/src/main/java/info/frostfs/sdk/ArrayHelper.java @@ -13,10 +13,10 @@ public class ArrayHelper { throw new IllegalArgumentException(ERROR_MESSAGE); } - byte[] result = new byte[startArray.length + endArray.length]; + byte[] joinedArray = new byte[startArray.length + endArray.length]; - System.arraycopy(startArray, 0, result, 0, startArray.length); - System.arraycopy(endArray, 0, result, startArray.length, endArray.length); - return result; + System.arraycopy(startArray, 0, joinedArray, 0, startArray.length); + System.arraycopy(endArray, 0, joinedArray, startArray.length, endArray.length); + return joinedArray; } } diff --git a/models/src/main/java/info/frostfs/sdk/constants/FilterConst.java b/models/src/main/java/info/frostfs/sdk/constants/FilterConst.java new file mode 100644 index 0000000..5340057 --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/constants/FilterConst.java @@ -0,0 +1,49 @@ +package info.frostfs.sdk.constants; + +public class FilterConst { + + // HEADER_PREFIX is a prefix of key to object header value or property. + public static final String HEADER_PREFIX = "$Object:"; + + // FILTER_HEADER_VERSION is a filter key to "version" field of the object header. + public static final String FILTER_HEADER_VERSION = HEADER_PREFIX + "version"; + + // FILTER_HEADER_OBJECT_ID is a filter key to "object_id" field of the object. + public static final String FILTER_HEADER_OBJECT_ID = HEADER_PREFIX + "objectID"; + + // FILTER_HEADER_CONTAINER_ID is a filter key to "container_id" field of the object header. + public static final String FILTER_HEADER_CONTAINER_ID = HEADER_PREFIX + "containerID"; + + // FILTER_HEADER_OWNER_ID is a filter key to "owner_id" field of the object header. + public static final String FILTER_HEADER_OWNER_ID = HEADER_PREFIX + "ownerID"; + + // FILTER_HEADER_CREATION_EPOCH is a filter key to "creation_epoch" field of the object header. + public static final String FILTER_HEADER_CREATION_EPOCH = HEADER_PREFIX + "creationEpoch"; + + // FILTER_HEADER_PAYLOAD_LENGTH is a filter key to "payload_length" field of the object header. + public static final String FILTER_HEADER_PAYLOAD_LENGTH = HEADER_PREFIX + "payloadLength"; + + // FILTER_HEADER_PAYLOAD_HASH is a filter key to "payload_hash" field of the object header. + public static final String FILTER_HEADER_PAYLOAD_HASH = HEADER_PREFIX + "payloadHash"; + + // FILTER_HEADER_OBJECT_TYPE is a filter key to "object_type" field of the object header. + public static final String FILTER_HEADER_OBJECT_TYPE = HEADER_PREFIX + "objectType"; + + // FILTER_HEADER_HOMOMORPHIC_HASH is a filter key to "homomorphic_hash" field of the object header. + public static final String FILTER_HEADER_HOMOMORPHIC_HASH = HEADER_PREFIX + "homomorphicHash"; + + // FILTER_HEADER_PARENT is a filter key to "split.parent" field of the object header. + public static final String FILTER_HEADER_PARENT = HEADER_PREFIX + "split.parent"; + + // FILTER_HEADER_SPLIT_ID is a filter key to "split.splitID" field of the object header. + public static final String FILTER_HEADER_SPLIT_ID = HEADER_PREFIX + "split.splitID"; + + // FILTER_HEADER_EC_PARENT is a filter key to "ec.parent" field of the object header. + public static final String FILTER_HEADER_EC_PARENT = HEADER_PREFIX + "ec.parent"; + + // FILTER_HEADER_ROOT is a filter key to check if regular object is on top of split hierarchy. + public static final String FILTER_HEADER_ROOT = HEADER_PREFIX + "ROOT"; + + // FILTER_HEADER_PHY is a filter key to check if an object physically stored on a node. + public static final String FILTER_HEADER_PHY = HEADER_PREFIX + "PHY"; +} diff --git a/models/src/main/java/info/frostfs/sdk/dto/CheckSum.java b/models/src/main/java/info/frostfs/sdk/dto/CheckSum.java new file mode 100644 index 0000000..ad298c4 --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/dto/CheckSum.java @@ -0,0 +1,25 @@ +package info.frostfs.sdk.dto; + +import info.frostfs.sdk.Helper; + +public class CheckSum { + // type is always Sha256 + public byte[] hash; + + public CheckSum(byte[] content) { + this.hash = Helper.getSha256(content); + } + + public byte[] getHash() { + return hash; + } + + public void setHash(byte[] hash) { + this.hash = hash; + } + + @Override + public String toString() { + return Helper.getHexString(hash); + } +} diff --git a/models/src/main/java/info/frostfs/sdk/dto/SessionToken.java b/models/src/main/java/info/frostfs/sdk/dto/SessionToken.java deleted file mode 100644 index 2f4055b..0000000 --- a/models/src/main/java/info/frostfs/sdk/dto/SessionToken.java +++ /dev/null @@ -1,19 +0,0 @@ -package info.frostfs.sdk.dto; - -public class SessionToken { - private final byte[] id; - private final byte[] sessionKey; - - public SessionToken(byte[] id, byte[] sessionKey) { - this.id = id; - this.sessionKey = sessionKey; - } - - public byte[] getId() { - return id; - } - - public byte[] getSessionKey() { - return sessionKey; - } -} diff --git a/models/src/main/java/info/frostfs/sdk/dto/container/Container.java b/models/src/main/java/info/frostfs/sdk/dto/container/Container.java index e07c28a..174d487 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/container/Container.java +++ b/models/src/main/java/info/frostfs/sdk/dto/container/Container.java @@ -1,7 +1,7 @@ package info.frostfs.sdk.dto.container; -import info.frostfs.sdk.dto.Version; import info.frostfs.sdk.dto.netmap.PlacementPolicy; +import info.frostfs.sdk.dto.netmap.Version; import info.frostfs.sdk.enums.BasicAcl; import java.util.UUID; diff --git a/models/src/main/java/info/frostfs/sdk/dto/netmap/NetmapSnapshot.java b/models/src/main/java/info/frostfs/sdk/dto/netmap/NetmapSnapshot.java index 9c2ef2c..69670bb 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/netmap/NetmapSnapshot.java +++ b/models/src/main/java/info/frostfs/sdk/dto/netmap/NetmapSnapshot.java @@ -1,5 +1,6 @@ package info.frostfs.sdk.dto.netmap; +import java.util.Collections; import java.util.List; public class NetmapSnapshot { @@ -8,7 +9,7 @@ public class NetmapSnapshot { public NetmapSnapshot(Long epoch, List nodeInfoCollection) { this.epoch = epoch; - this.nodeInfoCollection = nodeInfoCollection; + this.nodeInfoCollection = Collections.unmodifiableList(nodeInfoCollection); } public Long getEpoch() { diff --git a/models/src/main/java/info/frostfs/sdk/dto/netmap/NodeInfo.java b/models/src/main/java/info/frostfs/sdk/dto/netmap/NodeInfo.java index 2be1b1b..75c2484 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/netmap/NodeInfo.java +++ b/models/src/main/java/info/frostfs/sdk/dto/netmap/NodeInfo.java @@ -1,8 +1,8 @@ package info.frostfs.sdk.dto.netmap; -import info.frostfs.sdk.dto.Version; import info.frostfs.sdk.enums.NodeState; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -17,8 +17,8 @@ public class NodeInfo { Map attributes, byte[] publicKey) { this.state = state; this.version = version; - this.addresses = addresses; - this.attributes = attributes; + this.addresses = Collections.unmodifiableList(addresses); + this.attributes = Collections.unmodifiableMap(attributes); this.publicKey = publicKey; } diff --git a/models/src/main/java/info/frostfs/sdk/dto/Version.java b/models/src/main/java/info/frostfs/sdk/dto/netmap/Version.java similarity index 95% rename from models/src/main/java/info/frostfs/sdk/dto/Version.java rename to models/src/main/java/info/frostfs/sdk/dto/netmap/Version.java index 0222922..7f9b54c 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/Version.java +++ b/models/src/main/java/info/frostfs/sdk/dto/netmap/Version.java @@ -1,4 +1,4 @@ -package info.frostfs.sdk.dto; +package info.frostfs.sdk.dto.netmap; import static info.frostfs.sdk.constants.AppConst.DEFAULT_MAJOR_VERSION; import static info.frostfs.sdk.constants.AppConst.DEFAULT_MINOR_VERSION; diff --git a/models/src/main/java/info/frostfs/sdk/dto/object/LinkObject.java b/models/src/main/java/info/frostfs/sdk/dto/object/LinkObject.java index d7a7091..a2ffb6f 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/object/LinkObject.java +++ b/models/src/main/java/info/frostfs/sdk/dto/object/LinkObject.java @@ -1,7 +1,5 @@ package info.frostfs.sdk.dto.object; -import info.frostfs.sdk.dto.Split; -import info.frostfs.sdk.dto.SplitId; import info.frostfs.sdk.dto.container.ContainerId; import org.apache.commons.collections4.CollectionUtils; @@ -9,10 +7,10 @@ import java.util.List; public class LinkObject extends ObjectFrostFS { - public LinkObject(ContainerId cid, SplitId splitId, LargeObject largeObject) { + public LinkObject(ContainerId cid, SplitId splitId, ObjectHeader largeObjectHeader) { super(cid, new byte[]{}); var split = new Split(splitId); - split.setParentHeader(largeObject.getHeader()); + split.setParentHeader(largeObjectHeader); this.getHeader().setSplit(split); } diff --git a/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFilter.java b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFilter.java index 1443ee2..575f5e1 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFilter.java +++ b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFilter.java @@ -1,39 +1,24 @@ package info.frostfs.sdk.dto.object; -import info.frostfs.sdk.dto.OwnerId; -import info.frostfs.sdk.dto.Version; +import info.frostfs.sdk.constants.FieldConst; +import info.frostfs.sdk.constants.FilterConst; +import info.frostfs.sdk.dto.CheckSum; +import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.netmap.Version; import info.frostfs.sdk.enums.ObjectMatchType; -public class ObjectFilter { - private static final String HEADER_PREFIX = "$Object:"; - +public abstract class ObjectFilter { private ObjectMatchType matchType; private String key; - private String value; + private T value; - public ObjectFilter(ObjectMatchType matchType, String key, String value) { + public ObjectFilter(ObjectMatchType matchType, String key, T value) { this.matchType = matchType; this.key = key; this.value = value; } - public static ObjectFilter ObjectIdFilter(ObjectMatchType matchType, ObjectId objectId) { - return new ObjectFilter(matchType, HEADER_PREFIX + "objectID", objectId.getValue()); - } - - public static ObjectFilter OwnerFilter(ObjectMatchType matchType, OwnerId ownerId) { - return new ObjectFilter(matchType, HEADER_PREFIX + "ownerID", ownerId.getValue()); - } - - public static ObjectFilter RootFilter() { - return new ObjectFilter(ObjectMatchType.UNSPECIFIED, HEADER_PREFIX + "ROOT", ""); - } - - public static ObjectFilter VersionFilter(ObjectMatchType matchType, Version version) { - return new ObjectFilter(matchType, HEADER_PREFIX + "version", version.toString()); - } - public ObjectMatchType getMatchType() { return matchType; } @@ -50,11 +35,94 @@ public class ObjectFilter { this.key = key; } - public String getValue() { + public T getValue() { return value; } - public void setValue(String value) { + public void setValue(T value) { this.value = value; } + + public String getSerializedValue() { + return value.toString(); + } + + public static class FilterByAttribute extends ObjectFilter { + public FilterByAttribute(ObjectMatchType matchType, String key, String value) { + super(matchType, key, value); + } + } + + public static class FilterByObjectId extends ObjectFilter { + public FilterByObjectId(ObjectMatchType matchType, ObjectId value) { + super(matchType, FilterConst.FILTER_HEADER_OBJECT_ID, value); + } + } + + public static class FilterByOwnerId extends ObjectFilter { + public FilterByOwnerId(ObjectMatchType matchType, OwnerId value) { + super(matchType, FilterConst.FILTER_HEADER_OWNER_ID, value); + } + } + + public static class FilterByVersion extends ObjectFilter { + public FilterByVersion(ObjectMatchType matchType, Version value) { + super(matchType, FilterConst.FILTER_HEADER_VERSION, value); + } + } + + public static class FilterByContainerId extends ObjectFilter { + public FilterByContainerId(ObjectMatchType matchType, ContainerId value) { + super(matchType, FilterConst.FILTER_HEADER_CONTAINER_ID, value); + } + } + + public static class FilterByEpoch extends ObjectFilter { + public FilterByEpoch(ObjectMatchType matchType, long value) { + super(matchType, FilterConst.FILTER_HEADER_CREATION_EPOCH, value); + } + } + + public static class FilterByPayloadLength extends ObjectFilter { + public FilterByPayloadLength(ObjectMatchType matchType, long value) { + super(matchType, FilterConst.FILTER_HEADER_PAYLOAD_LENGTH, value); + } + } + + public static class FilterByPayloadHash extends ObjectFilter { + public FilterByPayloadHash(ObjectMatchType matchType, CheckSum value) { + super(matchType, FilterConst.FILTER_HEADER_PAYLOAD_HASH, value); + } + } + + public static class FilterByParent extends ObjectFilter { + public FilterByParent(ObjectMatchType matchType, ObjectId value) { + super(matchType, FilterConst.FILTER_HEADER_PARENT, value); + } + } + + public static class FilterBySplitId extends ObjectFilter { + public FilterBySplitId(ObjectMatchType matchType, SplitId value) { + super(matchType, FilterConst.FILTER_HEADER_SPLIT_ID, value); + } + } + + + public static class FilterByECParent extends ObjectFilter { + public FilterByECParent(ObjectMatchType matchType, ObjectId value) { + super(matchType, FilterConst.FILTER_HEADER_EC_PARENT, value); + } + } + + public static class FilterByRootObject extends ObjectFilter { + public FilterByRootObject() { + super(ObjectMatchType.UNSPECIFIED, FilterConst.FILTER_HEADER_ROOT, FieldConst.EMPTY_STRING); + } + } + + public static class FilterByPhysicallyStored extends ObjectFilter { + public FilterByPhysicallyStored() { + super(ObjectMatchType.UNSPECIFIED, FilterConst.FILTER_HEADER_PHY, FieldConst.EMPTY_STRING); + } + } } diff --git a/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFrostFS.java b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFrostFS.java index af5f463..53195bd 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFrostFS.java +++ b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectFrostFS.java @@ -1,10 +1,8 @@ package info.frostfs.sdk.dto.object; -import info.frostfs.sdk.dto.Split; import info.frostfs.sdk.dto.container.ContainerId; import info.frostfs.sdk.enums.ObjectType; -import java.util.ArrayList; import java.util.List; import static java.util.Objects.isNull; @@ -13,6 +11,7 @@ public class ObjectFrostFS { private final ObjectHeader header; private ObjectId objectId; private byte[] payload; + private ObjectReader objectReader; public ObjectFrostFS(ObjectHeader header, ObjectId objectId, byte[] payload) { if (isNull(header)) { @@ -26,12 +25,20 @@ public class ObjectFrostFS { public ObjectFrostFS(ContainerId containerId, byte[] payload) { this.payload = payload; - this.header = new ObjectHeader(containerId, new ArrayList<>()); + this.header = new ObjectHeader(containerId); } public ObjectFrostFS(ContainerId containerId, byte[] payload, ObjectType objectType) { this.payload = payload; - this.header = new ObjectHeader(containerId, objectType, new ArrayList<>()); + this.header = new ObjectHeader(containerId, objectType); + } + + public ObjectReader getObjectReader() { + return objectReader; + } + + public void setObjectReader(ObjectReader objectReader) { + this.objectReader = objectReader; } public ObjectHeader getHeader() { diff --git a/models/src/main/java/info/frostfs/sdk/dto/object/ObjectHeader.java b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectHeader.java index 9cc1f47..3878736 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/object/ObjectHeader.java +++ b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectHeader.java @@ -1,12 +1,12 @@ package info.frostfs.sdk.dto.object; -import info.frostfs.sdk.dto.OwnerId; -import info.frostfs.sdk.dto.Split; -import info.frostfs.sdk.dto.Version; import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.netmap.Version; import info.frostfs.sdk.enums.ObjectType; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import static java.util.Objects.isNull; @@ -33,24 +33,18 @@ public class ObjectHeader { this.version = version; } - public ObjectHeader(ContainerId containerId, ObjectType objectType, List attributes) { - if (isNull(containerId) || isNull(objectType)) { - throw new IllegalArgumentException("ContainerId or objectType is not present"); - } - - this.attributes = attributes; - this.containerId = containerId; - this.objectType = objectType; + public ObjectHeader(ContainerId containerId, ObjectType objectType, ObjectAttribute... attributes) { + this( + containerId, + objectType, + Arrays.stream(attributes).collect(Collectors.toList()), + 0L, + null + ); } - public ObjectHeader(ContainerId containerId, List attributes) { - if (isNull(containerId)) { - throw new IllegalArgumentException("ContainerId is not present"); - } - - this.attributes = attributes; - this.containerId = containerId; - this.objectType = ObjectType.REGULAR; + public ObjectHeader(ContainerId containerId, ObjectAttribute... attributes) { + this(containerId, ObjectType.REGULAR, attributes); } public OwnerId getOwnerId() { diff --git a/models/src/main/java/info/frostfs/sdk/dto/object/ObjectReader.java b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectReader.java new file mode 100644 index 0000000..1647c3c --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/dto/object/ObjectReader.java @@ -0,0 +1,5 @@ +package info.frostfs.sdk.dto.object; + +public interface ObjectReader { + byte[] readChunk(); +} diff --git a/models/src/main/java/info/frostfs/sdk/dto/OwnerId.java b/models/src/main/java/info/frostfs/sdk/dto/object/OwnerId.java similarity index 85% rename from models/src/main/java/info/frostfs/sdk/dto/OwnerId.java rename to models/src/main/java/info/frostfs/sdk/dto/object/OwnerId.java index 1603e21..e15a5eb 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/OwnerId.java +++ b/models/src/main/java/info/frostfs/sdk/dto/object/OwnerId.java @@ -1,4 +1,4 @@ -package info.frostfs.sdk.dto; +package info.frostfs.sdk.dto.object; import info.frostfs.sdk.Base58; @@ -27,4 +27,9 @@ public class OwnerId { public byte[] toHash() { return Base58.decode(value); } + + @Override + public String toString() { + return value; + } } diff --git a/models/src/main/java/info/frostfs/sdk/dto/Split.java b/models/src/main/java/info/frostfs/sdk/dto/object/Split.java similarity index 78% rename from models/src/main/java/info/frostfs/sdk/dto/Split.java rename to models/src/main/java/info/frostfs/sdk/dto/object/Split.java index 642ed58..93836d2 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/Split.java +++ b/models/src/main/java/info/frostfs/sdk/dto/object/Split.java @@ -1,7 +1,7 @@ -package info.frostfs.sdk.dto; +package info.frostfs.sdk.dto.object; -import info.frostfs.sdk.dto.object.ObjectHeader; -import info.frostfs.sdk.dto.object.ObjectId; +import frostfs.refs.Types; +import info.frostfs.sdk.dto.response.Signature; import java.util.ArrayList; import java.util.List; @@ -15,6 +15,7 @@ public class Split { private ObjectId previous; private Signature parentSignature; private ObjectHeader parentHeader; + private Types.Signature parentSignatureGrpc; public Split() { this(new SplitId()); @@ -68,4 +69,12 @@ public class Split { public List getChildren() { return children; } + + public Types.Signature getParentSignatureGrpc() { + return parentSignatureGrpc; + } + + public void setParentSignatureGrpc(Types.Signature parentSignatureGrpc) { + this.parentSignatureGrpc = parentSignatureGrpc; + } } diff --git a/models/src/main/java/info/frostfs/sdk/dto/SplitId.java b/models/src/main/java/info/frostfs/sdk/dto/object/SplitId.java similarity index 83% rename from models/src/main/java/info/frostfs/sdk/dto/SplitId.java rename to models/src/main/java/info/frostfs/sdk/dto/object/SplitId.java index 29ed2d0..994d184 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/SplitId.java +++ b/models/src/main/java/info/frostfs/sdk/dto/object/SplitId.java @@ -1,4 +1,4 @@ -package info.frostfs.sdk.dto; +package info.frostfs.sdk.dto.object; import java.util.UUID; @@ -21,8 +21,8 @@ public class SplitId { this.id = asUuid(binary); } - public SplitId(String str) { - this.id = UUID.fromString(str); + public SplitId(String string) { + this.id = UUID.fromString(string); } @Override diff --git a/models/src/main/java/info/frostfs/sdk/dto/MetaHeader.java b/models/src/main/java/info/frostfs/sdk/dto/response/MetaHeader.java similarity index 94% rename from models/src/main/java/info/frostfs/sdk/dto/MetaHeader.java rename to models/src/main/java/info/frostfs/sdk/dto/response/MetaHeader.java index 9d6735e..9a1faff 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/MetaHeader.java +++ b/models/src/main/java/info/frostfs/sdk/dto/response/MetaHeader.java @@ -1,4 +1,6 @@ -package info.frostfs.sdk.dto; +package info.frostfs.sdk.dto.response; + +import info.frostfs.sdk.dto.netmap.Version; import static info.frostfs.sdk.constants.AppConst.DEFAULT_MAJOR_VERSION; import static info.frostfs.sdk.constants.AppConst.DEFAULT_MINOR_VERSION; diff --git a/models/src/main/java/info/frostfs/sdk/dto/Status.java b/models/src/main/java/info/frostfs/sdk/dto/response/ResponseStatus.java similarity index 83% rename from models/src/main/java/info/frostfs/sdk/dto/Status.java rename to models/src/main/java/info/frostfs/sdk/dto/response/ResponseStatus.java index e1075b5..66e7031 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/Status.java +++ b/models/src/main/java/info/frostfs/sdk/dto/response/ResponseStatus.java @@ -1,20 +1,20 @@ -package info.frostfs.sdk.dto; +package info.frostfs.sdk.dto.response; import info.frostfs.sdk.enums.StatusCode; import static info.frostfs.sdk.constants.FieldConst.EMPTY_STRING; import static java.util.Objects.isNull; -public class Status { +public class ResponseStatus { private StatusCode code; private String message; - public Status(StatusCode code, String message) { + public ResponseStatus(StatusCode code, String message) { this.code = code; this.message = isNull(message) ? EMPTY_STRING : message; } - public Status(StatusCode code) { + public ResponseStatus(StatusCode code) { this.code = code; this.message = EMPTY_STRING; } diff --git a/models/src/main/java/info/frostfs/sdk/dto/Signature.java b/models/src/main/java/info/frostfs/sdk/dto/response/Signature.java similarity index 93% rename from models/src/main/java/info/frostfs/sdk/dto/Signature.java rename to models/src/main/java/info/frostfs/sdk/dto/response/Signature.java index 5b2b85d..65d6ce8 100644 --- a/models/src/main/java/info/frostfs/sdk/dto/Signature.java +++ b/models/src/main/java/info/frostfs/sdk/dto/response/Signature.java @@ -1,4 +1,4 @@ -package info.frostfs.sdk.dto; +package info.frostfs.sdk.dto.response; import info.frostfs.sdk.enums.SignatureScheme; diff --git a/models/src/main/java/info/frostfs/sdk/dto/session/SessionToken.java b/models/src/main/java/info/frostfs/sdk/dto/session/SessionToken.java new file mode 100644 index 0000000..2c4ae83 --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/dto/session/SessionToken.java @@ -0,0 +1,13 @@ +package info.frostfs.sdk.dto.session; + +public class SessionToken { + private final byte[] token; + + public SessionToken(byte[] token) { + this.token = token; + } + + public byte[] getToken() { + return token; + } +} diff --git a/models/src/main/java/info/frostfs/sdk/mappers/MetaHeaderMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/MetaHeaderMapper.java deleted file mode 100644 index 0b90453..0000000 --- a/models/src/main/java/info/frostfs/sdk/mappers/MetaHeaderMapper.java +++ /dev/null @@ -1,24 +0,0 @@ -package info.frostfs.sdk.mappers; - -import frostfs.session.Types; -import info.frostfs.sdk.dto.MetaHeader; - -import static java.util.Objects.isNull; - -public class MetaHeaderMapper { - - private MetaHeaderMapper() { - } - - public static Types.RequestMetaHeader toGrpcMessage(MetaHeader metaHeader) { - if (isNull(metaHeader)) { - return null; - } - - return Types.RequestMetaHeader.newBuilder() - .setVersion(VersionMapper.toGrpcMessage(metaHeader.getVersion())) - .setEpoch(metaHeader.getEpoch()) - .setTtl(metaHeader.getTtl()) - .build(); - } -} diff --git a/models/src/main/java/info/frostfs/sdk/mappers/container/ContainerMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/container/ContainerMapper.java index c02bfcb..e874859 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/container/ContainerMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/container/ContainerMapper.java @@ -4,8 +4,8 @@ import com.google.protobuf.ByteString; import frostfs.container.Types; import info.frostfs.sdk.dto.container.Container; import info.frostfs.sdk.enums.BasicAcl; -import info.frostfs.sdk.mappers.VersionMapper; import info.frostfs.sdk.mappers.netmap.PlacementPolicyMapper; +import info.frostfs.sdk.mappers.netmap.VersionMapper; import static info.frostfs.sdk.UuidExtension.asBytes; import static info.frostfs.sdk.UuidExtension.asUuid; diff --git a/models/src/main/java/info/frostfs/sdk/mappers/netmap/NodeInfoMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/netmap/NodeInfoMapper.java index a5791b3..97fa499 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/netmap/NodeInfoMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/netmap/NodeInfoMapper.java @@ -5,7 +5,6 @@ import frostfs.netmap.Types; import frostfs.netmap.Types.NodeInfo.Attribute; import info.frostfs.sdk.dto.netmap.NodeInfo; import info.frostfs.sdk.enums.NodeState; -import info.frostfs.sdk.mappers.VersionMapper; import java.util.stream.Collectors; diff --git a/models/src/main/java/info/frostfs/sdk/mappers/VersionMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/netmap/VersionMapper.java similarity index 88% rename from models/src/main/java/info/frostfs/sdk/mappers/VersionMapper.java rename to models/src/main/java/info/frostfs/sdk/mappers/netmap/VersionMapper.java index f12cb73..386cb78 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/VersionMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/netmap/VersionMapper.java @@ -1,7 +1,7 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.netmap; import frostfs.refs.Types; -import info.frostfs.sdk.dto.Version; +import info.frostfs.sdk.dto.netmap.Version; import static java.util.Objects.isNull; diff --git a/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectFilterMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectFilterMapper.java index 874e9b1..8ebf944 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectFilterMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectFilterMapper.java @@ -12,7 +12,7 @@ public class ObjectFilterMapper { private ObjectFilterMapper() { } - public static Service.SearchRequest.Body.Filter toGrpcMessage(ObjectFilter filter) { + public static Service.SearchRequest.Body.Filter toGrpcMessage(ObjectFilter filter) { if (isNull(filter)) { return null; } @@ -27,7 +27,7 @@ public class ObjectFilterMapper { return Service.SearchRequest.Body.Filter.newBuilder() .setMatchType(objectMatchType) .setKey(filter.getKey()) - .setValue(filter.getValue()) + .setValue(filter.getSerializedValue()) .build(); } } diff --git a/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapper.java index af8b898..93c432c 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapper.java @@ -1,27 +1,30 @@ package info.frostfs.sdk.mappers.object; +import com.google.protobuf.ByteString; import frostfs.object.Types; import info.frostfs.sdk.dto.container.ContainerId; import info.frostfs.sdk.dto.object.ObjectAttribute; import info.frostfs.sdk.dto.object.ObjectHeader; import info.frostfs.sdk.enums.ObjectType; -import info.frostfs.sdk.mappers.VersionMapper; import info.frostfs.sdk.mappers.container.ContainerIdMapper; +import info.frostfs.sdk.mappers.netmap.VersionMapper; import org.apache.commons.collections4.ListUtils; import java.util.stream.Collectors; import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; public class ObjectHeaderMapper { private static final String ERROR_UNKNOWN_VALUE_TEMPLATE = "Unknown ObjectType. Value: %s."; + private static final String ERROR_OBJECT_HEADER_MISSING_ERROR = "ObjectHeader is not present"; private ObjectHeaderMapper() { } public static Types.Header toGrpcMessage(ObjectHeader header) { if (isNull(header)) { - return null; + throw new IllegalArgumentException(ERROR_OBJECT_HEADER_MISSING_ERROR); } var objectType = Types.ObjectType.forNumber(header.getObjectType().value); @@ -32,13 +35,23 @@ public class ObjectHeaderMapper { } var head = Types.Header.newBuilder() + .setOwnerId(OwnerIdMapper.toGrpcMessage(header.getOwnerId())) + .setVersion(VersionMapper.toGrpcMessage(header.getVersion())) .setContainerId(ContainerIdMapper.toGrpcMessage(header.getContainerId())) - .setObjectType(objectType); + .setObjectType(objectType) + .setPayloadLength(header.getPayloadLength()); for (ObjectAttribute objectAttribute : header.getAttributes()) { head.addAttributes(ObjectAttributeMapper.toGrpcMessage(objectAttribute)); } + if (nonNull(header.getSplit())) { + var grpcSplit = Types.Header.Split.newBuilder() + .setSplitId(ByteString.copyFrom(header.getSplit().getSplitId().toBinary())) + .build(); + head.setSplit(grpcSplit); + } + return head.build(); } diff --git a/models/src/main/java/info/frostfs/sdk/mappers/OwnerIdMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/object/OwnerIdMapper.java similarity index 84% rename from models/src/main/java/info/frostfs/sdk/mappers/OwnerIdMapper.java rename to models/src/main/java/info/frostfs/sdk/mappers/object/OwnerIdMapper.java index a0a6b64..905f879 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/OwnerIdMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/object/OwnerIdMapper.java @@ -1,8 +1,8 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.object; import com.google.protobuf.ByteString; import frostfs.refs.Types; -import info.frostfs.sdk.dto.OwnerId; +import info.frostfs.sdk.dto.object.OwnerId; import static java.util.Objects.isNull; diff --git a/models/src/main/java/info/frostfs/sdk/mappers/response/MetaHeaderMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/response/MetaHeaderMapper.java new file mode 100644 index 0000000..d8e7324 --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/mappers/response/MetaHeaderMapper.java @@ -0,0 +1,33 @@ +package info.frostfs.sdk.mappers.response; + +import frostfs.session.Types; +import info.frostfs.sdk.dto.response.MetaHeader; +import info.frostfs.sdk.mappers.netmap.VersionMapper; + +import static java.util.Objects.isNull; + +public class MetaHeaderMapper { + private static final String ERROR_META_HEADER_MISSING_ERROR = "MetaHeader is not present"; + + private MetaHeaderMapper() { + } + + public static Types.RequestMetaHeader toGrpcMessage(MetaHeader metaHeader) { + if (isNull(metaHeader)) { + throw new IllegalArgumentException(ERROR_META_HEADER_MISSING_ERROR); + } + + return toGrpcMessageBuilder(metaHeader).build(); + } + + public static Types.RequestMetaHeader.Builder toGrpcMessageBuilder(MetaHeader metaHeader) { + if (isNull(metaHeader)) { + throw new IllegalArgumentException(ERROR_META_HEADER_MISSING_ERROR); + } + + return Types.RequestMetaHeader.newBuilder() + .setVersion(VersionMapper.toGrpcMessage(metaHeader.getVersion())) + .setEpoch(metaHeader.getEpoch()) + .setTtl(metaHeader.getTtl()); + } +} diff --git a/models/src/main/java/info/frostfs/sdk/mappers/StatusMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/response/ResponseStatusMapper.java similarity index 58% rename from models/src/main/java/info/frostfs/sdk/mappers/StatusMapper.java rename to models/src/main/java/info/frostfs/sdk/mappers/response/ResponseStatusMapper.java index 04ddd6e..192ea21 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/StatusMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/response/ResponseStatusMapper.java @@ -1,20 +1,20 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.response; import frostfs.status.Types; -import info.frostfs.sdk.dto.Status; +import info.frostfs.sdk.dto.response.ResponseStatus; import info.frostfs.sdk.enums.StatusCode; import static java.util.Objects.isNull; -public class StatusMapper { +public class ResponseStatusMapper { private static final String ERROR_UNKNOWN_VALUE_TEMPLATE = "Unknown StatusCode. Value: %s."; - private StatusMapper() { + private ResponseStatusMapper() { } - public static Status toModel(Types.Status status) { + public static ResponseStatus toModel(Types.Status status) { if (isNull(status)) { - return new Status(StatusCode.SUCCESS); + return new ResponseStatus(StatusCode.SUCCESS); } var statusCode = StatusCode.get(status.getCode()); @@ -24,6 +24,6 @@ public class StatusMapper { ); } - return new Status(statusCode, status.getMessage()); + return new ResponseStatus(statusCode, status.getMessage()); } } diff --git a/models/src/main/java/info/frostfs/sdk/mappers/SignatureMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/response/SignatureMapper.java similarity index 91% rename from models/src/main/java/info/frostfs/sdk/mappers/SignatureMapper.java rename to models/src/main/java/info/frostfs/sdk/mappers/response/SignatureMapper.java index 5e9e103..162d5a5 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/SignatureMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/response/SignatureMapper.java @@ -1,8 +1,8 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.response; import com.google.protobuf.ByteString; import frostfs.refs.Types; -import info.frostfs.sdk.dto.Signature; +import info.frostfs.sdk.dto.response.Signature; import static java.util.Objects.isNull; diff --git a/models/src/main/java/info/frostfs/sdk/mappers/SessionMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/session/SessionMapper.java similarity index 96% rename from models/src/main/java/info/frostfs/sdk/mappers/SessionMapper.java rename to models/src/main/java/info/frostfs/sdk/mappers/session/SessionMapper.java index ca14d05..1536f35 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/SessionMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/session/SessionMapper.java @@ -1,4 +1,4 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.session; import com.google.protobuf.CodedOutputStream; import com.google.protobuf.InvalidProtocolBufferException; diff --git a/models/src/test/java/info/frostfs/sdk/mappers/MetaHeaderMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/MetaHeaderMapperTest.java deleted file mode 100644 index 7d874cc..0000000 --- a/models/src/test/java/info/frostfs/sdk/mappers/MetaHeaderMapperTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package info.frostfs.sdk.mappers; - -import info.frostfs.sdk.dto.MetaHeader; -import info.frostfs.sdk.dto.Version; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -public class MetaHeaderMapperTest { - - @Test - void toGrpcMessage_success() { - //Given - var version = new Version(1, 2); - var metaHeader = new MetaHeader(version, 1, 2); - - //When - var result = MetaHeaderMapper.toGrpcMessage(metaHeader); - - //Then - assertNotNull(result); - assertEquals(metaHeader.getEpoch(), result.getEpoch()); - assertEquals(metaHeader.getTtl(), result.getTtl()); - assertEquals(metaHeader.getVersion().getMajor(), result.getVersion().getMajor()); - assertEquals(metaHeader.getVersion().getMinor(), result.getVersion().getMinor()); - } - - @Test - void toGrpcMessage_null() { - //When + Then - assertNull(MetaHeaderMapper.toGrpcMessage(null)); - } -} diff --git a/models/src/test/java/info/frostfs/sdk/mappers/VersionMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/netmap/VersionMapperTest.java similarity index 93% rename from models/src/test/java/info/frostfs/sdk/mappers/VersionMapperTest.java rename to models/src/test/java/info/frostfs/sdk/mappers/netmap/VersionMapperTest.java index 3fea7b7..25aa403 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/VersionMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/netmap/VersionMapperTest.java @@ -1,7 +1,7 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.netmap; import frostfs.refs.Types; -import info.frostfs.sdk.dto.Version; +import info.frostfs.sdk.dto.netmap.Version; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; diff --git a/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectFilterMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectFilterMapperTest.java index 3451ccc..7bc8aec 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectFilterMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectFilterMapperTest.java @@ -18,7 +18,7 @@ public class ObjectFilterMapperTest { @EnumSource(value = ObjectMatchType.class) void toGrpcMessage_success(ObjectMatchType type) { //Given - var objectFilter = new ObjectFilter(type, "key", "value"); + var objectFilter = new ObjectFilter.FilterByAttribute(type, "key", "value"); //When var result = ObjectFilterMapper.toGrpcMessage(objectFilter); @@ -40,7 +40,7 @@ public class ObjectFilterMapperTest { @Test void toGrpcMessage_notValidScheme() { //Given - var objectFilter = new ObjectFilter(UNSPECIFIED, "key", "value"); + var objectFilter = new ObjectFilter.FilterByAttribute(UNSPECIFIED, "key", "value"); //When + Then try (MockedStatic mockStatic = mockStatic(Types.MatchType.class)) { diff --git a/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapperTest.java index dd410b2..a2ca83c 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectHeaderMapperTest.java @@ -3,16 +3,16 @@ package info.frostfs.sdk.mappers.object; import com.google.protobuf.ByteString; import frostfs.object.Types; import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.netmap.Version; import info.frostfs.sdk.dto.object.ObjectAttribute; import info.frostfs.sdk.dto.object.ObjectHeader; +import info.frostfs.sdk.dto.object.OwnerId; import info.frostfs.sdk.enums.ObjectType; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.mockito.MockedStatic; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mockStatic; @@ -27,8 +27,11 @@ public class ObjectHeaderMapperTest { var objectHeader = new ObjectHeader( containerId, type, - List.of(new ObjectAttribute("Filename", "cat.jpg"), new ObjectAttribute("Filename2", "cat2.jpg")) + new ObjectAttribute("Filename", "cat.jpg"), + new ObjectAttribute("Filename2", "cat2.jpg") ); + objectHeader.setOwnerId(new OwnerId("NVxUSpEEJzYXZZtUs18PrJTD9QZkLLNQ8S")); + objectHeader.setVersion(new Version(1, 2)); //When var result = ObjectHeaderMapper.toGrpcMessage(objectHeader); @@ -59,7 +62,7 @@ public class ObjectHeaderMapperTest { void toGrpcMessage_notValidScheme() { //Given var containerId = new ContainerId("EQGx2QeYHJb53uRwYGzcQaW191sZpdNrjutk6veUSV2R"); - var objectHeader = new ObjectHeader(containerId, ObjectType.REGULAR, null); + var objectHeader = new ObjectHeader(containerId, ObjectType.REGULAR); //When + Then try (MockedStatic mockStatic = mockStatic(Types.ObjectType.class)) { diff --git a/models/src/test/java/info/frostfs/sdk/mappers/OwnerIdMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/object/OwnerIdMapperTest.java similarity index 92% rename from models/src/test/java/info/frostfs/sdk/mappers/OwnerIdMapperTest.java rename to models/src/test/java/info/frostfs/sdk/mappers/object/OwnerIdMapperTest.java index bc51895..e9ac8c6 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/OwnerIdMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/object/OwnerIdMapperTest.java @@ -1,6 +1,6 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.object; -import info.frostfs.sdk.dto.OwnerId; +import info.frostfs.sdk.dto.object.OwnerId; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/models/src/test/java/info/frostfs/sdk/mappers/response/MetaHeaderMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/response/MetaHeaderMapperTest.java new file mode 100644 index 0000000..3c48b52 --- /dev/null +++ b/models/src/test/java/info/frostfs/sdk/mappers/response/MetaHeaderMapperTest.java @@ -0,0 +1,57 @@ +package info.frostfs.sdk.mappers.response; + +import frostfs.session.Types; +import info.frostfs.sdk.dto.netmap.Version; +import info.frostfs.sdk.dto.response.MetaHeader; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class MetaHeaderMapperTest { + + @Test + void toGrpcMessage_success() { + //Given + var version = new Version(1, 2); + var metaHeader = new MetaHeader(version, 1, 2); + + //When + Types.RequestMetaHeader result = MetaHeaderMapper.toGrpcMessage(metaHeader); + + //Then + assertNotNull(result); + assertEquals(metaHeader.getEpoch(), result.getEpoch()); + assertEquals(metaHeader.getTtl(), result.getTtl()); + assertEquals(metaHeader.getVersion().getMajor(), result.getVersion().getMajor()); + assertEquals(metaHeader.getVersion().getMinor(), result.getVersion().getMinor()); + } + + @Test + void toGrpcMessage_null() { + //When + Then + assertThrows(IllegalArgumentException.class, () -> MetaHeaderMapper.toGrpcMessage(null)); + } + + @Test + void toGrpcMessageBuilder_success() { + //Given + var version = new Version(1, 2); + var metaHeader = new MetaHeader(version, 1, 2); + + //When + Types.RequestMetaHeader.Builder result = MetaHeaderMapper.toGrpcMessageBuilder(metaHeader); + + //Then + assertNotNull(result); + assertEquals(metaHeader.getEpoch(), result.getEpoch()); + assertEquals(metaHeader.getTtl(), result.getTtl()); + assertEquals(metaHeader.getVersion().getMajor(), result.getVersion().getMajor()); + assertEquals(metaHeader.getVersion().getMinor(), result.getVersion().getMinor()); + } + + @Test + void toGrpcMessageBuilder_null() { + //When + Then + assertThrows(IllegalArgumentException.class, () -> MetaHeaderMapper.toGrpcMessageBuilder(null)); + } +} diff --git a/models/src/test/java/info/frostfs/sdk/mappers/StatusMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/response/ResponseStatusMapperTest.java similarity index 80% rename from models/src/test/java/info/frostfs/sdk/mappers/StatusMapperTest.java rename to models/src/test/java/info/frostfs/sdk/mappers/response/ResponseStatusMapperTest.java index d0f5a59..d3073e2 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/StatusMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/response/ResponseStatusMapperTest.java @@ -1,4 +1,4 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.response; import frostfs.status.Types; import info.frostfs.sdk.enums.StatusCode; @@ -8,7 +8,7 @@ import org.junit.jupiter.params.provider.EnumSource; import static org.junit.jupiter.api.Assertions.*; -public class StatusMapperTest { +public class ResponseStatusMapperTest { @ParameterizedTest @EnumSource(value = StatusCode.class) @@ -20,7 +20,7 @@ public class StatusMapperTest { .build(); //When - var result = StatusMapper.toModel(status); + var result = ResponseStatusMapper.toModel(status); //Then assertNotNull(result); @@ -31,7 +31,7 @@ public class StatusMapperTest { @Test void toModel_null() { //When - var result = StatusMapper.toModel(null); + var result = ResponseStatusMapper.toModel(null); //Then assertNotNull(result); @@ -48,6 +48,6 @@ public class StatusMapperTest { .build(); //When + Then - assertThrows(IllegalArgumentException.class, () -> StatusMapper.toModel(status)); + assertThrows(IllegalArgumentException.class, () -> ResponseStatusMapper.toModel(status)); } } diff --git a/models/src/test/java/info/frostfs/sdk/mappers/SignatureMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/response/SignatureMapperTest.java similarity index 95% rename from models/src/test/java/info/frostfs/sdk/mappers/SignatureMapperTest.java rename to models/src/test/java/info/frostfs/sdk/mappers/response/SignatureMapperTest.java index 3435ab7..471c0aa 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/SignatureMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/response/SignatureMapperTest.java @@ -1,7 +1,7 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.response; import frostfs.refs.Types; -import info.frostfs.sdk.dto.Signature; +import info.frostfs.sdk.dto.response.Signature; import info.frostfs.sdk.enums.SignatureScheme; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; diff --git a/models/src/test/java/info/frostfs/sdk/mappers/SessionMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/session/SessionMapperTest.java similarity index 97% rename from models/src/test/java/info/frostfs/sdk/mappers/SessionMapperTest.java rename to models/src/test/java/info/frostfs/sdk/mappers/session/SessionMapperTest.java index f8c125e..3f7d0ea 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/SessionMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/session/SessionMapperTest.java @@ -1,4 +1,4 @@ -package info.frostfs.sdk.mappers; +package info.frostfs.sdk.mappers.session; import com.google.protobuf.ByteString; import frostfs.session.Types;