diff --git a/client/pom.xml b/client/pom.xml index f907964..2d87b21 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -6,7 +6,7 @@ info.frostfs.sdk frostfs-sdk-java - 0.3.0 + ${revision} client @@ -21,17 +21,17 @@ info.frostfs.sdk cryptography - 0.3.0 + ${revision} info.frostfs.sdk models - 0.3.0 + ${revision} info.frostfs.sdk exceptions - 0.3.0 + ${revision} commons-codec diff --git a/client/src/main/java/info/frostfs/sdk/FrostFSClient.java b/client/src/main/java/info/frostfs/sdk/FrostFSClient.java index 31a76b7..e6704ed 100644 --- a/client/src/main/java/info/frostfs/sdk/FrostFSClient.java +++ b/client/src/main/java/info/frostfs/sdk/FrostFSClient.java @@ -24,6 +24,9 @@ import info.frostfs.sdk.jdo.parameters.container.PrmContainerDelete; import info.frostfs.sdk.jdo.parameters.container.PrmContainerGet; import info.frostfs.sdk.jdo.parameters.container.PrmContainerGetAll; import info.frostfs.sdk.jdo.parameters.object.*; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmObjectPatch; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeGet; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeHashGet; import info.frostfs.sdk.jdo.parameters.session.PrmSessionCreate; import info.frostfs.sdk.jdo.result.ObjectHeaderResult; import info.frostfs.sdk.pool.SessionCache; @@ -33,6 +36,7 @@ import info.frostfs.sdk.services.impl.*; import info.frostfs.sdk.services.impl.interceptor.Configuration; import info.frostfs.sdk.services.impl.interceptor.MonitoringClientInterceptor; import info.frostfs.sdk.services.impl.rwhelper.ObjectWriter; +import info.frostfs.sdk.services.impl.rwhelper.RangeReader; import info.frostfs.sdk.utils.Validator; import io.grpc.Channel; import io.grpc.ClientInterceptors; @@ -164,6 +168,21 @@ public class FrostFSClient implements CommonClient { return objectClientImpl.searchObjects(args, ctx); } + @Override + public RangeReader getRange(PrmRangeGet args, CallContext ctx) { + return objectClientImpl.getRange(args, ctx); + } + + @Override + public byte[][] getRangeHash(PrmRangeHashGet args, CallContext ctx) { + return objectClientImpl.getRangeHash(args, ctx); + } + + @Override + public ObjectId patchObject(PrmObjectPatch args, CallContext ctx) { + return objectClientImpl.patchObject(args, ctx); + } + @Override public byte[] addChain(PrmApeChainAdd args, CallContext ctx) { return apeManagerClient.addChain(args, ctx); @@ -213,6 +232,7 @@ public class FrostFSClient implements CommonClient { return accountingClient.getBalance(ctx); } + @Override public String dial(CallContext ctx) { accountingClient.getBalance(ctx); return null; diff --git a/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmObjectPatch.java b/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmObjectPatch.java new file mode 100644 index 0000000..9f93c9a --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmObjectPatch.java @@ -0,0 +1,42 @@ +package info.frostfs.sdk.jdo.parameters.object.patch; + +import info.frostfs.sdk.annotations.NotNull; +import info.frostfs.sdk.dto.object.ObjectAttribute; +import info.frostfs.sdk.dto.object.patch.Address; +import info.frostfs.sdk.dto.object.patch.Range; +import info.frostfs.sdk.dto.session.SessionToken; +import info.frostfs.sdk.jdo.parameters.session.SessionContext; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +@Getter +@Builder +@AllArgsConstructor +public class PrmObjectPatch implements SessionContext { + @NotNull + private Address address; + + @NotNull + private Range range; + + @NotNull + private InputStream payload; + + private List newAttributes; + private boolean replaceAttributes; + private int maxChunkLength; + private SessionToken sessionToken; + private Map xHeaders; + + public PrmObjectPatch(Address address, Range range, InputStream payload, int maxChunkLength) { + this.address = address; + this.range = range; + this.payload = payload; + this.maxChunkLength = maxChunkLength; + } +} diff --git a/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmRangeGet.java b/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmRangeGet.java new file mode 100644 index 0000000..add15b7 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmRangeGet.java @@ -0,0 +1,35 @@ +package info.frostfs.sdk.jdo.parameters.object.patch; + +import info.frostfs.sdk.annotations.NotNull; +import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.object.ObjectId; +import info.frostfs.sdk.dto.object.patch.Range; +import info.frostfs.sdk.dto.session.SessionToken; +import info.frostfs.sdk.jdo.parameters.session.SessionContext; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.util.Map; + +@Getter +@Builder +@AllArgsConstructor +public class PrmRangeGet implements SessionContext { + @NotNull + private ContainerId containerId; + @NotNull + private ObjectId objectId; + @NotNull + private Range range; + + private boolean raw; + private SessionToken sessionToken; + private Map xHeaders; + + public PrmRangeGet(ContainerId containerId, ObjectId objectId, Range range) { + this.containerId = containerId; + this.objectId = objectId; + this.range = range; + } +} diff --git a/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmRangeHashGet.java b/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmRangeHashGet.java new file mode 100644 index 0000000..d860133 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/jdo/parameters/object/patch/PrmRangeHashGet.java @@ -0,0 +1,38 @@ +package info.frostfs.sdk.jdo.parameters.object.patch; + +import info.frostfs.sdk.annotations.NotNull; +import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.object.ObjectId; +import info.frostfs.sdk.dto.object.patch.Range; +import info.frostfs.sdk.dto.session.SessionToken; +import info.frostfs.sdk.jdo.parameters.session.SessionContext; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.util.List; +import java.util.Map; + +@Getter +@Builder +@AllArgsConstructor +public class PrmRangeHashGet implements SessionContext { + @NotNull + private ContainerId containerId; + @NotNull + private ObjectId objectId; + @NotNull + private List ranges; + @NotNull + private byte[] salt; + + private SessionToken sessionToken; + private Map xHeaders; + + public PrmRangeHashGet(ContainerId containerId, ObjectId objectId, List ranges, byte[] salt) { + this.containerId = containerId; + this.objectId = objectId; + this.ranges = ranges; + this.salt = salt; + } +} diff --git a/client/src/main/java/info/frostfs/sdk/pool/Pool.java b/client/src/main/java/info/frostfs/sdk/pool/Pool.java index 74143a2..45b818e 100644 --- a/client/src/main/java/info/frostfs/sdk/pool/Pool.java +++ b/client/src/main/java/info/frostfs/sdk/pool/Pool.java @@ -26,12 +26,16 @@ import info.frostfs.sdk.jdo.parameters.container.PrmContainerDelete; import info.frostfs.sdk.jdo.parameters.container.PrmContainerGet; import info.frostfs.sdk.jdo.parameters.container.PrmContainerGetAll; import info.frostfs.sdk.jdo.parameters.object.*; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmObjectPatch; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeGet; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeHashGet; import info.frostfs.sdk.jdo.parameters.session.PrmSessionCreate; import info.frostfs.sdk.jdo.pool.NodeParameters; import info.frostfs.sdk.jdo.pool.PoolInitParameters; import info.frostfs.sdk.jdo.result.ObjectHeaderResult; import info.frostfs.sdk.services.CommonClient; import info.frostfs.sdk.services.impl.rwhelper.ObjectWriter; +import info.frostfs.sdk.services.impl.rwhelper.RangeReader; import info.frostfs.sdk.utils.FrostFSMessages; import info.frostfs.sdk.utils.WaitUtil; import lombok.Getter; @@ -198,6 +202,7 @@ public class Pool implements CommonClient { return address + key; } + @Override public String dial(CallContext ctx) { InnerPool[] inner = new InnerPool[rebalanceParams.getNodesParams().length]; boolean atLeastOneHealthy = false; @@ -479,6 +484,24 @@ public class Pool implements CommonClient { return client.getClient().searchObjects(args, ctx); } + @Override + public RangeReader getRange(PrmRangeGet args, CallContext ctx) { + ClientWrapper client = connection(); + return client.getClient().getRange(args, ctx); + } + + @Override + public byte[][] getRangeHash(PrmRangeHashGet args, CallContext ctx) { + ClientWrapper client = connection(); + return client.getClient().getRangeHash(args, ctx); + } + + @Override + public ObjectId patchObject(PrmObjectPatch args, CallContext ctx) { + ClientWrapper client = connection(); + return client.getClient().patchObject(args, ctx); + } + @Override public byte[] addChain(PrmApeChainAdd args, CallContext ctx) { ClientWrapper client = connection(); diff --git a/client/src/main/java/info/frostfs/sdk/services/CommonClient.java b/client/src/main/java/info/frostfs/sdk/services/CommonClient.java index e0482fb..ce0dcba 100644 --- a/client/src/main/java/info/frostfs/sdk/services/CommonClient.java +++ b/client/src/main/java/info/frostfs/sdk/services/CommonClient.java @@ -1,5 +1,9 @@ package info.frostfs.sdk.services; +import info.frostfs.sdk.jdo.parameters.CallContext; + public interface CommonClient extends AccountingClient, ApeManagerClient, ContainerClient, NetmapClient, ObjectClient, SessionClient, ToolsClient { + + String dial(CallContext ctx); } diff --git a/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java b/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java index 86901b5..5e8362c 100644 --- a/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java +++ b/client/src/main/java/info/frostfs/sdk/services/ObjectClient.java @@ -4,8 +4,12 @@ import info.frostfs.sdk.dto.object.ObjectFrostFS; import info.frostfs.sdk.dto.object.ObjectId; import info.frostfs.sdk.jdo.parameters.CallContext; import info.frostfs.sdk.jdo.parameters.object.*; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmObjectPatch; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeGet; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeHashGet; import info.frostfs.sdk.jdo.result.ObjectHeaderResult; import info.frostfs.sdk.services.impl.rwhelper.ObjectWriter; +import info.frostfs.sdk.services.impl.rwhelper.RangeReader; public interface ObjectClient { ObjectHeaderResult getObjectHead(PrmObjectHeadGet args, CallContext ctx); @@ -21,4 +25,10 @@ public interface ObjectClient { void deleteObject(PrmObjectDelete args, CallContext ctx); Iterable searchObjects(PrmObjectSearch args, CallContext ctx); + + RangeReader getRange(PrmRangeGet args, CallContext ctx); + + byte[][] getRangeHash(PrmRangeHashGet args, CallContext ctx); + + ObjectId patchObject(PrmObjectPatch args, CallContext ctx); } diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java b/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java index 203d1e6..266b630 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/ObjectClientImpl.java @@ -14,16 +14,18 @@ import info.frostfs.sdk.jdo.ClientEnvironment; import info.frostfs.sdk.jdo.PutObjectResult; import info.frostfs.sdk.jdo.parameters.CallContext; import info.frostfs.sdk.jdo.parameters.object.*; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmObjectPatch; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeGet; +import info.frostfs.sdk.jdo.parameters.object.patch.PrmRangeHashGet; import info.frostfs.sdk.jdo.parameters.session.SessionContext; import info.frostfs.sdk.jdo.result.ObjectHeaderResult; import info.frostfs.sdk.mappers.container.ContainerIdMapper; import info.frostfs.sdk.mappers.object.*; +import info.frostfs.sdk.mappers.object.patch.AddressMapper; +import info.frostfs.sdk.mappers.object.patch.RangeMapper; import info.frostfs.sdk.services.ContextAccessor; import info.frostfs.sdk.services.ObjectClient; -import info.frostfs.sdk.services.impl.rwhelper.ObjectReaderImpl; -import info.frostfs.sdk.services.impl.rwhelper.ObjectStreamer; -import info.frostfs.sdk.services.impl.rwhelper.ObjectWriter; -import info.frostfs.sdk.services.impl.rwhelper.SearchReader; +import info.frostfs.sdk.services.impl.rwhelper.*; import info.frostfs.sdk.tools.RequestConstructor; import info.frostfs.sdk.tools.Verifier; import org.apache.commons.collections4.CollectionUtils; @@ -200,6 +202,77 @@ public class ObjectClientImpl extends ContextAccessor implements ObjectClient { return new ObjectId(grpcObject.getObjectId().getValue().toByteArray()); } + @Override + public RangeReader getRange(PrmRangeGet args, CallContext ctx) { + validate(args); + + var request = createGetRangeRequest(args, ctx); + + var service = deadLineAfter(objectServiceBlockingClient, ctx.getTimeout(), ctx.getTimeUnit()); + return new RangeReader(service.getRange(request)); + } + + @Override + public byte[][] getRangeHash(PrmRangeHashGet args, CallContext ctx) { + validate(args); + + var request = createGetRangeHashRequest(args, ctx); + + var service = deadLineAfter(objectServiceBlockingClient, ctx.getTimeout(), ctx.getTimeUnit()); + var response = service.getRangeHash(request); + + Verifier.checkResponse(response); + + return response.getBody().getHashListList().stream().map(ByteString::toByteArray).toArray(byte[][]::new); + } + + @Override + public ObjectId patchObject(PrmObjectPatch args, CallContext ctx) { + validate(args); + + var request = createInitPatchRequest(args); + var protoToken = RequestConstructor.createObjectTokenContext( + getOrCreateSession(args, ctx), + request.getBody().getAddress(), + frostfs.session.Types.ObjectSessionContext.Verb.PATCH, + getContext().getKey() + ); + + var currentPos = args.getRange().getOffset(); + var chunkSize = args.getMaxChunkLength(); + byte[] chunkBuffer = new byte[chunkSize]; + + var service = deadLineAfter(objectServiceClient, ctx.getTimeout(), ctx.getTimeUnit()); + PatchStreamer writer = new PatchStreamer(service); + + var bytesCount = readNBytes(args.getPayload(), chunkBuffer, chunkSize); + while (bytesCount > 0) { + var range = Service.Range.newBuilder() + .setOffset(currentPos) + .setLength(bytesCount) + .build(); + + Service.PatchRequest.Body.Patch.newBuilder() + .setChunk(ByteString.copyFrom(chunkBuffer, 0, bytesCount)) + .setSourceRange(range) + .build(); + + currentPos += bytesCount; + + RequestConstructor.addMetaHeader(request, args.getXHeaders(), protoToken); + sign(request, getContext().getKey()); + + writer.write(request.build()); + bytesCount = readNBytes(args.getPayload(), chunkBuffer, chunkSize); + } + + var response = writer.complete(); + + Verifier.checkResponse(response); + + return ObjectIdMapper.toModel(response.getBody().getObjectId()); + } + private ObjectFrostFS getObject(Service.GetRequest request, CallContext ctx) { var reader = getObjectInit(request, ctx); @@ -371,7 +444,6 @@ public class ObjectClientImpl extends ContextAccessor implements ObjectClient { } private Service.GetRequest createGetRequest(PrmObjectGet args, CallContext ctx) { - var address = Types.Address.newBuilder() .setContainerId(ContainerIdMapper.toGrpcMessage(args.getContainerId())) .setObjectId(ObjectIdMapper.toGrpcMessage(args.getObjectId())) @@ -510,4 +582,70 @@ public class ObjectClientImpl extends ContextAccessor implements ObjectClient { return request.build(); } + + private Service.GetRangeRequest createGetRangeRequest(PrmRangeGet args, CallContext ctx) { + var address = Types.Address.newBuilder() + .setContainerId(ContainerIdMapper.toGrpcMessage(args.getContainerId())) + .setObjectId(ObjectIdMapper.toGrpcMessage(args.getObjectId())) + .build(); + var body = Service.GetRangeRequest.Body.newBuilder() + .setAddress(address) + .setRange(RangeMapper.toGrpcMessage(args.getRange())) + .setRaw(args.isRaw()) + .build(); + var request = Service.GetRangeRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(args, ctx); + var protoToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.RANGE, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, args.getXHeaders(), protoToken); + sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.GetRangeHashRequest createGetRangeHashRequest(PrmRangeHashGet args, CallContext ctx) { + var address = Types.Address.newBuilder() + .setContainerId(ContainerIdMapper.toGrpcMessage(args.getContainerId())) + .setObjectId(ObjectIdMapper.toGrpcMessage(args.getObjectId())) + .build(); + var body = Service.GetRangeHashRequest.Body.newBuilder() + .setAddress(address) + .setType(Types.ChecksumType.SHA256) + .setSalt(ByteString.copyFrom(args.getSalt())) + .addAllRanges(RangeMapper.toGrpcMessages(args.getRanges())) + .build(); + var request = Service.GetRangeHashRequest.newBuilder() + .setBody(body); + + var sessionToken = getOrCreateSession(args, ctx); + var protoToken = RequestConstructor.createObjectTokenContext( + sessionToken, + address, + frostfs.session.Types.ObjectSessionContext.Verb.RANGEHASH, + getContext().getKey() + ); + + RequestConstructor.addMetaHeader(request, args.getXHeaders(), protoToken); + sign(request, getContext().getKey()); + + return request.build(); + } + + private Service.PatchRequest.Builder createInitPatchRequest(PrmObjectPatch args) { + var address = AddressMapper.toGrpcMessage(args.getAddress()); + var body = Service.PatchRequest.Body.newBuilder() + .setAddress(address) + .setReplaceAttributes(args.isReplaceAttributes()) + .addAllNewAttributes(ObjectAttributeMapper.toGrpcMessages(args.getNewAttributes())) + .build(); + return Service.PatchRequest.newBuilder() + .setBody(body); + } } diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectStreamer.java b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectStreamer.java index 0556fb5..cadfbf1 100644 --- a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectStreamer.java +++ b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/ObjectStreamer.java @@ -7,11 +7,11 @@ import info.frostfs.sdk.utils.WaitUtil; import io.grpc.stub.StreamObserver; import lombok.Getter; +import static info.frostfs.sdk.constants.AppConst.DEFAULT_POLL_INTERVAL; import static info.frostfs.sdk.constants.ErrorConst.PROTO_MESSAGE_IS_EMPTY_TEMPLATE; import static java.util.Objects.isNull; public class ObjectStreamer { - private static final long POLL_INTERVAL = 10; private final StreamObserver requestObserver; private final PutResponseCallback responseObserver; @@ -35,7 +35,7 @@ public class ObjectStreamer { requestObserver.onCompleted(); while (isNull(responseObserver.getResponse())) { - WaitUtil.sleep(POLL_INTERVAL); + WaitUtil.sleep(DEFAULT_POLL_INTERVAL); } return responseObserver.getResponse(); diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/PatchStreamer.java b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/PatchStreamer.java new file mode 100644 index 0000000..4cdee35 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/PatchStreamer.java @@ -0,0 +1,62 @@ +package info.frostfs.sdk.services.impl.rwhelper; + +import frostfs.object.ObjectServiceGrpc; +import frostfs.object.Service; +import info.frostfs.sdk.exceptions.ProcessFrostFSException; +import info.frostfs.sdk.utils.WaitUtil; +import io.grpc.stub.StreamObserver; +import lombok.Getter; + +import static info.frostfs.sdk.constants.AppConst.DEFAULT_POLL_INTERVAL; +import static info.frostfs.sdk.constants.ErrorConst.PROTO_MESSAGE_IS_EMPTY_TEMPLATE; +import static java.util.Objects.isNull; + +public class PatchStreamer { + private final StreamObserver requestObserver; + private final PatchResponseCallback responseObserver; + + public PatchStreamer(ObjectServiceGrpc.ObjectServiceStub objectServiceStub) { + PatchResponseCallback responseObserver = new PatchResponseCallback(); + + this.responseObserver = responseObserver; + this.requestObserver = objectServiceStub.patch(responseObserver); + } + + public void write(Service.PatchRequest request) { + if (isNull(request)) { + throw new ProcessFrostFSException( + String.format(PROTO_MESSAGE_IS_EMPTY_TEMPLATE, Service.PutRequest.class.getName()) + ); + } + requestObserver.onNext(request); + } + + public Service.PatchResponse complete() { + requestObserver.onCompleted(); + + while (isNull(responseObserver.getResponse())) { + WaitUtil.sleep(DEFAULT_POLL_INTERVAL); + } + + return responseObserver.getResponse(); + } + + @Getter + private static class PatchResponseCallback implements StreamObserver { + private Service.PatchResponse response; + + @Override + public void onNext(Service.PatchResponse patchResponse) { + this.response = patchResponse; + } + + @Override + public void onError(Throwable throwable) { + throw new ProcessFrostFSException(throwable); + } + + @Override + public void onCompleted() { + } + } +} diff --git a/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/RangeReader.java b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/RangeReader.java new file mode 100644 index 0000000..75c4c64 --- /dev/null +++ b/client/src/main/java/info/frostfs/sdk/services/impl/rwhelper/RangeReader.java @@ -0,0 +1,25 @@ +package info.frostfs.sdk.services.impl.rwhelper; + +import frostfs.object.Service; +import info.frostfs.sdk.tools.Verifier; + +import java.util.Iterator; + +public class RangeReader { + public Iterator call; + + public RangeReader(Iterator call) { + this.call = call; + } + + public byte[] readChunk() { + if (!call.hasNext()) { + return null; + } + + var response = call.next(); + Verifier.checkResponse(response); + + return response.getBody().getChunk().toByteArray(); + } +} diff --git a/cryptography/pom.xml b/cryptography/pom.xml index ac56a86..e9e2c6b 100644 --- a/cryptography/pom.xml +++ b/cryptography/pom.xml @@ -6,7 +6,7 @@ info.frostfs.sdk frostfs-sdk-java - 0.3.0 + ${revision} cryptography @@ -21,7 +21,7 @@ info.frostfs.sdk exceptions - 0.3.0 + ${revision} com.google.protobuf diff --git a/exceptions/pom.xml b/exceptions/pom.xml index 4cb8bcc..c3b4546 100644 --- a/exceptions/pom.xml +++ b/exceptions/pom.xml @@ -6,7 +6,7 @@ info.frostfs.sdk frostfs-sdk-java - 0.3.0 + ${revision} exceptions diff --git a/models/pom.xml b/models/pom.xml index 32cade4..e913463 100644 --- a/models/pom.xml +++ b/models/pom.xml @@ -6,7 +6,7 @@ info.frostfs.sdk frostfs-sdk-java - 0.3.0 + ${revision} models @@ -21,17 +21,17 @@ info.frostfs.sdk cryptography - 0.3.0 + ${revision} info.frostfs.sdk protos - 0.3.0 + ${revision} info.frostfs.sdk exceptions - 0.3.0 + ${revision} diff --git a/models/src/main/java/info/frostfs/sdk/constants/AppConst.java b/models/src/main/java/info/frostfs/sdk/constants/AppConst.java index 35d64c6..feb1ca5 100644 --- a/models/src/main/java/info/frostfs/sdk/constants/AppConst.java +++ b/models/src/main/java/info/frostfs/sdk/constants/AppConst.java @@ -13,6 +13,7 @@ public class AppConst { public static final int SHA256_HASH_LENGTH = 32; public static final int UUID_BYTE_ARRAY_LENGTH = 16; public static final int DEFAULT_GRPC_TIMEOUT = 5; + public static final long DEFAULT_POLL_INTERVAL = 10; private AppConst() { } diff --git a/models/src/main/java/info/frostfs/sdk/dto/object/patch/Address.java b/models/src/main/java/info/frostfs/sdk/dto/object/patch/Address.java new file mode 100644 index 0000000..ae30880 --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/dto/object/patch/Address.java @@ -0,0 +1,13 @@ +package info.frostfs.sdk.dto.object.patch; + +import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.object.ObjectId; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class Address { + private final ObjectId objectId; + private final ContainerId containerId; +} diff --git a/models/src/main/java/info/frostfs/sdk/dto/object/patch/Range.java b/models/src/main/java/info/frostfs/sdk/dto/object/patch/Range.java new file mode 100644 index 0000000..67a56aa --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/dto/object/patch/Range.java @@ -0,0 +1,11 @@ +package info.frostfs.sdk.dto.object.patch; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class Range { + private long offset; + private long length; +} diff --git a/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapper.java index 687aa86..f29c284 100644 --- a/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapper.java +++ b/models/src/main/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapper.java @@ -2,6 +2,10 @@ package info.frostfs.sdk.mappers.object; import frostfs.object.Types; import info.frostfs.sdk.dto.object.ObjectAttribute; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; import static java.util.Objects.isNull; @@ -10,6 +14,14 @@ public class ObjectAttributeMapper { private ObjectAttributeMapper() { } + public static List toGrpcMessages(List attributes) { + if (CollectionUtils.isEmpty(attributes)) { + return null; + } + + return attributes.stream().map(ObjectAttributeMapper::toGrpcMessage).collect(Collectors.toList()); + } + public static Types.Header.Attribute toGrpcMessage(ObjectAttribute attribute) { if (isNull(attribute)) { return null; diff --git a/models/src/main/java/info/frostfs/sdk/mappers/object/patch/AddressMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/object/patch/AddressMapper.java new file mode 100644 index 0000000..1510b7a --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/mappers/object/patch/AddressMapper.java @@ -0,0 +1,25 @@ +package info.frostfs.sdk.mappers.object.patch; + +import frostfs.refs.Types; +import info.frostfs.sdk.dto.object.patch.Address; +import info.frostfs.sdk.mappers.container.ContainerIdMapper; +import info.frostfs.sdk.mappers.object.ObjectIdMapper; + +import static java.util.Objects.isNull; + +public class AddressMapper { + + private AddressMapper() { + } + + public static Types.Address toGrpcMessage(Address address) { + if (isNull(address)) { + return null; + } + + return Types.Address.newBuilder() + .setContainerId(ContainerIdMapper.toGrpcMessage(address.getContainerId())) + .setObjectId(ObjectIdMapper.toGrpcMessage(address.getObjectId())) + .build(); + } +} diff --git a/models/src/main/java/info/frostfs/sdk/mappers/object/patch/RangeMapper.java b/models/src/main/java/info/frostfs/sdk/mappers/object/patch/RangeMapper.java new file mode 100644 index 0000000..f428545 --- /dev/null +++ b/models/src/main/java/info/frostfs/sdk/mappers/object/patch/RangeMapper.java @@ -0,0 +1,35 @@ +package info.frostfs.sdk.mappers.object.patch; + +import frostfs.object.Service; +import info.frostfs.sdk.dto.object.patch.Range; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.Objects.isNull; + +public class RangeMapper { + + private RangeMapper() { + } + + public static List toGrpcMessages(List ranges) { + if (CollectionUtils.isEmpty(ranges)) { + return null; + } + + return ranges.stream().map(RangeMapper::toGrpcMessage).collect(Collectors.toList()); + } + + public static Service.Range toGrpcMessage(Range range) { + if (isNull(range)) { + return null; + } + + return Service.Range.newBuilder() + .setOffset(range.getOffset()) + .setLength(range.getLength()) + .build(); + } +} diff --git a/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapperTest.java index 4ae2902..160af7a 100644 --- a/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapperTest.java +++ b/models/src/test/java/info/frostfs/sdk/mappers/object/ObjectAttributeMapperTest.java @@ -4,10 +4,39 @@ import frostfs.object.Types; import info.frostfs.sdk.dto.object.ObjectAttribute; import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; public class ObjectAttributeMapperTest { + @Test + void toGrpcMessages_success() { + //Given + var objectAttribute1 = new ObjectAttribute("key1", "value1"); + var objectAttribute2 = new ObjectAttribute("key2", "value2"); + + //When + var result = ObjectAttributeMapper.toGrpcMessages(Arrays.asList(objectAttribute1, objectAttribute2)); + + //Then + assertNotNull(result); + assertThat(result).isNotNull().hasSize(2); + assertEquals(objectAttribute1.getKey(), result.get(0).getKey()); + assertEquals(objectAttribute1.getValue(), result.get(0).getValue()); + assertEquals(objectAttribute2.getKey(), result.get(1).getKey()); + assertEquals(objectAttribute2.getValue(), result.get(1).getValue()); + } + + @Test + void toGrpcMessages_null() { + //When + Then + assertNull(ObjectAttributeMapper.toGrpcMessages(null)); + assertNull(ObjectAttributeMapper.toGrpcMessages(Collections.emptyList())); + } + @Test void toGrpcMessage_success() { //Given diff --git a/models/src/test/java/info/frostfs/sdk/mappers/object/patch/AddressMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/object/patch/AddressMapperTest.java new file mode 100644 index 0000000..b53ff87 --- /dev/null +++ b/models/src/test/java/info/frostfs/sdk/mappers/object/patch/AddressMapperTest.java @@ -0,0 +1,39 @@ +package info.frostfs.sdk.mappers.object.patch; + +import info.frostfs.sdk.dto.container.ContainerId; +import info.frostfs.sdk.dto.object.ObjectId; +import info.frostfs.sdk.dto.object.patch.Address; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AddressMapperTest { + + @Test + void toGrpcMessage_success() { + //Given + var objectId = new ObjectId("85orCLKSu3X1jGiTFmwmTUsBU88RBARNwuRwrEy5pyww"); + var containerId = new ContainerId("EQGx2QeYHJb53uRwYGzcQaW191sZpdNrjutk6veUSV2R"); + var address = new Address(objectId, containerId); + + //When + var result = AddressMapper.toGrpcMessage(address); + + //Then + assertNotNull(result); + assertEquals( + address.getContainerId().getValue(), + new ContainerId(result.getContainerId().getValue().toByteArray()).getValue() + ); + assertEquals( + address.getObjectId().getValue(), + new ObjectId(result.getObjectId().getValue().toByteArray()).getValue() + ); + } + + @Test + void toGrpcMessage_null() { + //When + Then + assertNull(AddressMapper.toGrpcMessage(null)); + } +} diff --git a/models/src/test/java/info/frostfs/sdk/mappers/object/patch/RangeMapperTest.java b/models/src/test/java/info/frostfs/sdk/mappers/object/patch/RangeMapperTest.java new file mode 100644 index 0000000..771a9ac --- /dev/null +++ b/models/src/test/java/info/frostfs/sdk/mappers/object/patch/RangeMapperTest.java @@ -0,0 +1,58 @@ +package info.frostfs.sdk.mappers.object.patch; + +import info.frostfs.sdk.dto.object.patch.Range; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +public class RangeMapperTest { + + @Test + void toGrpcMessages_success() { + //Given + var range1 = new Range(1, 10); + var range2 = new Range(2, 20); + + //When + var result = RangeMapper.toGrpcMessages(Arrays.asList(range1, range2)); + + //Then + assertNotNull(result); + assertThat(result).isNotNull().hasSize(2); + assertEquals(range1.getOffset(), result.get(0).getOffset()); + assertEquals(range1.getLength(), result.get(0).getLength()); + assertEquals(range2.getOffset(), result.get(1).getOffset()); + assertEquals(range2.getLength(), result.get(1).getLength()); + } + + @Test + void toGrpcMessages_null() { + //When + Then + assertNull(RangeMapper.toGrpcMessages(null)); + assertNull(RangeMapper.toGrpcMessages(Collections.emptyList())); + } + + @Test + void toGrpcMessage_success() { + //Given + var range = new Range(1, 10); + + //When + var result = RangeMapper.toGrpcMessage(range); + + //Then + assertNotNull(result); + assertEquals(range.getOffset(), result.getOffset()); + assertEquals(range.getLength(), result.getLength()); + } + + @Test + void toGrpcMessage_null() { + //When + Then + assertNull(RangeMapper.toGrpcMessage(null)); + } +} diff --git a/pom.xml b/pom.xml index 72eb9eb..d390c12 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ info.frostfs.sdk frostfs-sdk-java - 0.3.0 + ${revision} pom client @@ -17,6 +17,8 @@ + 0.4.0 + 11 11 UTF-8 diff --git a/protos/pom.xml b/protos/pom.xml index d3a2b3b..f5ea90a 100644 --- a/protos/pom.xml +++ b/protos/pom.xml @@ -6,7 +6,7 @@ info.frostfs.sdk frostfs-sdk-java - 0.3.0 + ${revision} protos