[#12] Extend method logic

Signed-off-by: Ori Bruk <o.bruk@yadro.com>
This commit is contained in:
Ori Bruk 2024-09-11 11:41:38 +03:00
parent c9a54d56fb
commit 23bbe08893
70 changed files with 1375 additions and 587 deletions

View file

@ -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<ObjectId> searchObjects(ContainerId cid, ObjectFilter... filters) {
public Iterable<ObjectId> searchObjects(ContainerId cid, ObjectFilter<?>... filters) {
return objectClientImpl.searchObjects(cid, filters);
}

View file

@ -0,0 +1,6 @@
package info.frostfs.sdk.enums;
public enum WaitExpects {
EXISTS,
REMOVED
}

View file

@ -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;
}
}

View file

@ -0,0 +1,6 @@
package info.frostfs.sdk.exceptions;
public class TimeoutException extends RuntimeException {
public TimeoutException() {
}
}

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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<String, Object> 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<String, Object> 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;
}

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -14,7 +14,9 @@ public interface ObjectClient {
ObjectId putObject(PutObjectParameters parameters);
ObjectId putSingleObject(ObjectFrostFS objectFrostFS);
void deleteObject(ContainerId containerId, ObjectId objectId);
Iterable<ObjectId> searchObjects(ContainerId cid, ObjectFilter... filters);
Iterable<ObjectId> searchObjects(ContainerId cid, ObjectFilter<?>... filters);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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<ContainerId> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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();
}
}

View file

@ -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());

View file

@ -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<ObjectId> 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);
}
public ObjectId putSingleObject(ObjectFrostFS modelObject) {
var sessionToken = getContext().getFrostFSClient().createSessionInternal(-1);
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 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);
modelObject.setObjectReader(reader);
return modelObject;
}
return obj.toBuilder().setPayload(ByteString.copyFrom(payload)).build();
}
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 fullLength = header.getPayloadLength() == 0
? getStreamSize(parameters.getPayload())
: header.getPayloadLength();
parameters.setFullLength(fullLength);
if (parameters.getMaxObjectSizeCache() == 0) {
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);
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<ObjectId> 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);
List<ObjectId> sentObjectIds = new ArrayList<>(objectsCount);
// keep attributes for the large object
var attributes = parameters.getHeader().getAttributes();
Split split = new Split();
parameters.getHeader().setSplit(split);
parameters.getHeader().setAttributes(new ArrayList<>());
// 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);
var result = putStreamObject(parameters);
sentObjectIds.add(result.getObjectId());
restBytes -= result.getObjectSize();
}
// send the last part and create linkObject
if (CollectionUtils.isNotEmpty(sentObjectIds)) {
split.setPrevious(sentObjectIds.get(sentObjectIds.size() - 1));
}
var largeObjectHeader =
new ObjectHeader(header.getContainerId(), ObjectType.REGULAR, attributes, fullLength, null);
largeObject.appendBlock(buffer, bytesCount);
split.setParentHeader(largeObjectHeader);
currentObject = new ObjectFrostFS(
header.getContainerId(),
bytesCount < objectSize ? Arrays.copyOfRange(buffer, 0, bytesCount) : buffer
);
currentObject.setSplit(split);
var result = putStreamObject(parameters);
if (largeObject.getPayloadLength() == fullLength) {
break;
}
sentObjectIds.add(result.getObjectId());
objectId = putSingleObject(currentObject);
sentObjectIds.add(objectId);
}
if (CollectionUtils.isEmpty(sentObjectIds)) {
currentObject.addAttributes(parameters.getHeader().getAttributes());
return putSingleObject(currentObject);
}
largeObject.addAttributes(parameters.getHeader().getAttributes());
largeObject.calculateHash();
currentObject.setParent(largeObject);
objectId = putSingleObject(currentObject);
sentObjectIds.add(objectId);
var linkObject = new LinkObject(header.getContainerId(), split.getSplitId(), largeObject);
var linkObject = new LinkObject(header.getContainerId(), split.getSplitId(), largeObjectHeader);
linkObject.addChildren(sentObjectIds);
linkObject.getHeader().getAttributes().clear();
putSingleObject(linkObject);
return objectToolsImpl.calculateObjectId(largeObject.getHeader());
return split.getParent();
}
// We are here if the payload is placed to one Object. It means no cut action, just simple PUT.
var singlePartResult = putStreamObject(parameters);
return singlePartResult.getObjectId();
}
private ObjectWriter getUploadStream(PutObjectParameters parameters) {
var header = parameters.getHeader();
header.setOwnerId(getContext().getOwnerId());
header.setVersion(getContext().getVersion());
var grpcHeader = ObjectHeaderMapper.toGrpcMessage(header);
grpcHeader = objectToolsImpl.updateSplitValues(grpcHeader, header.getSplit());
var oid = Types.ObjectID.newBuilder().setValue(getSha256(grpcHeader)).build();
var initRequest = createInitPutRequest(oid, grpcHeader);
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<Types.ObjectID> 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();
}
}

View file

@ -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));
}

View file

@ -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();

View file

@ -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());
}
}

View file

@ -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<Service.GetResponse> call;
public ObjectReader(Iterator<Service.GetResponse> call) {
public ObjectReaderImpl(Iterator<Service.GetResponse> call) {
this.call = call;
}

View file

@ -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<Service.PutRequest> 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();

View file

@ -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()));
}

View file

@ -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);
}
}

View file

@ -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<String, String> xHeaders) {
addMetaHeader(request, xHeaders, null);
}
public static void addMetaHeader(Message.Builder request,
Map<String, String> 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);
}
public static void addObjectSessionToken(Message.Builder request,
Types.SessionToken sessionToken,
frostfs.refs.Types.ContainerID cid,
frostfs.refs.Types.ObjectID oid,
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 Types.SessionToken createObjectTokenContext(Types.SessionToken sessionToken,
frostfs.refs.Types.Address address,
Types.ObjectSessionContext.Verb verb,
ECDsa key) {
if (isNull(request) || isNull(sessionToken)) {
return;
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();
}
}

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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 <T> void validate(T object, Class<?>... classes) {
if (isNull(object)) {
throw new ValidationException(OBJECT_IS_NULL);
}
Set<ConstraintViolation<T>> 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));
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}

View file

@ -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";
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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<NodeInfo> nodeInfoCollection) {
this.epoch = epoch;
this.nodeInfoCollection = nodeInfoCollection;
this.nodeInfoCollection = Collections.unmodifiableList(nodeInfoCollection);
}
public Long getEpoch() {

View file

@ -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<String, String> 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;
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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<T> {
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<String> {
public FilterByAttribute(ObjectMatchType matchType, String key, String value) {
super(matchType, key, value);
}
}
public static class FilterByObjectId extends ObjectFilter<ObjectId> {
public FilterByObjectId(ObjectMatchType matchType, ObjectId value) {
super(matchType, FilterConst.FILTER_HEADER_OBJECT_ID, value);
}
}
public static class FilterByOwnerId extends ObjectFilter<OwnerId> {
public FilterByOwnerId(ObjectMatchType matchType, OwnerId value) {
super(matchType, FilterConst.FILTER_HEADER_OWNER_ID, value);
}
}
public static class FilterByVersion extends ObjectFilter<Version> {
public FilterByVersion(ObjectMatchType matchType, Version value) {
super(matchType, FilterConst.FILTER_HEADER_VERSION, value);
}
}
public static class FilterByContainerId extends ObjectFilter<ContainerId> {
public FilterByContainerId(ObjectMatchType matchType, ContainerId value) {
super(matchType, FilterConst.FILTER_HEADER_CONTAINER_ID, value);
}
}
public static class FilterByEpoch extends ObjectFilter<Long> {
public FilterByEpoch(ObjectMatchType matchType, long value) {
super(matchType, FilterConst.FILTER_HEADER_CREATION_EPOCH, value);
}
}
public static class FilterByPayloadLength extends ObjectFilter<Long> {
public FilterByPayloadLength(ObjectMatchType matchType, long value) {
super(matchType, FilterConst.FILTER_HEADER_PAYLOAD_LENGTH, value);
}
}
public static class FilterByPayloadHash extends ObjectFilter<CheckSum> {
public FilterByPayloadHash(ObjectMatchType matchType, CheckSum value) {
super(matchType, FilterConst.FILTER_HEADER_PAYLOAD_HASH, value);
}
}
public static class FilterByParent extends ObjectFilter<ObjectId> {
public FilterByParent(ObjectMatchType matchType, ObjectId value) {
super(matchType, FilterConst.FILTER_HEADER_PARENT, value);
}
}
public static class FilterBySplitId extends ObjectFilter<SplitId> {
public FilterBySplitId(ObjectMatchType matchType, SplitId value) {
super(matchType, FilterConst.FILTER_HEADER_SPLIT_ID, value);
}
}
public static class FilterByECParent extends ObjectFilter<ObjectId> {
public FilterByECParent(ObjectMatchType matchType, ObjectId value) {
super(matchType, FilterConst.FILTER_HEADER_EC_PARENT, value);
}
}
public static class FilterByRootObject extends ObjectFilter<String> {
public FilterByRootObject() {
super(ObjectMatchType.UNSPECIFIED, FilterConst.FILTER_HEADER_ROOT, FieldConst.EMPTY_STRING);
}
}
public static class FilterByPhysicallyStored extends ObjectFilter<String> {
public FilterByPhysicallyStored() {
super(ObjectMatchType.UNSPECIFIED, FilterConst.FILTER_HEADER_PHY, FieldConst.EMPTY_STRING);
}
}
}

View file

@ -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() {

View file

@ -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<ObjectAttribute> attributes) {
if (isNull(containerId) || isNull(objectType)) {
throw new IllegalArgumentException("ContainerId or objectType is not present");
public ObjectHeader(ContainerId containerId, ObjectType objectType, ObjectAttribute... attributes) {
this(
containerId,
objectType,
Arrays.stream(attributes).collect(Collectors.toList()),
0L,
null
);
}
this.attributes = attributes;
this.containerId = containerId;
this.objectType = objectType;
}
public ObjectHeader(ContainerId containerId, List<ObjectAttribute> 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() {

View file

@ -0,0 +1,5 @@
package info.frostfs.sdk.dto.object;
public interface ObjectReader {
byte[] readChunk();
}

View file

@ -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;
}
}

View file

@ -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<ObjectId> getChildren() {
return children;
}
public Types.Signature getParentSignatureGrpc() {
return parentSignatureGrpc;
}
public void setParentSignatureGrpc(Types.Signature parentSignatureGrpc) {
this.parentSignatureGrpc = parentSignatureGrpc;
}
}

View file

@ -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

View file

@ -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;

View file

@ -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;
}

View file

@ -1,4 +1,4 @@
package info.frostfs.sdk.dto;
package info.frostfs.sdk.dto.response;
import info.frostfs.sdk.enums.SignatureScheme;

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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());
}
}

View file

@ -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());
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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));
}
}

View file

@ -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.*;

View file

@ -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<Types.MatchType> mockStatic = mockStatic(Types.MatchType.class)) {

View file

@ -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<Types.ObjectType> mockStatic = mockStatic(Types.ObjectType.class)) {

View file

@ -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;

View file

@ -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));
}
}

View file

@ -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));
}
}

View file

@ -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;

View file

@ -1,4 +1,4 @@
package info.frostfs.sdk.mappers;
package info.frostfs.sdk.mappers.session;
import com.google.protobuf.ByteString;
import frostfs.session.Types;