Skip to content

Added batch copy #420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/main/java/com/aliyun/oss/OSS.java
Original file line number Diff line number Diff line change
Expand Up @@ -4259,4 +4259,17 @@ public UdfApplicationLog getUdfApplicationLog(GetUdfApplicationLogRequest getUdf
* @throws ClientException
*/
VoidResult deleteBucketTransferAcceleration(String bucketName) throws OSSException, ClientException;

/**
* batch copy a batch of objects in the same bucket.
*
* @param copyObjectsRequest
* A {@link CopyObjectsRequest} instance that specifies bucket
* source key and target key。
* @return A {@link CopyObjectResult} instance.
* @throws OSSException
* @throws ClientException
*/
public CopyObjectsResult copyObjects(CopyObjectsRequest copyObjectsRequest) throws OSSException, ClientException;

}
5 changes: 5 additions & 0 deletions src/main/java/com/aliyun/oss/OSSClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1918,6 +1918,11 @@ public VoidResult deleteBucketTransferAcceleration(String bucketName) throws OSS
return this.bucketOperation.deleteBucketTransferAcceleration(new GenericRequest(bucketName));
}

@Override
public CopyObjectsResult copyObjects(CopyObjectsRequest copyObjectsRequest) throws OSSException, ClientException {
return objectOperation.copyObjects(copyObjectsRequest);
}

@Override
public void shutdown() {
try {
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/aliyun/oss/common/parser/RequestMarshallers.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public final class RequestMarshallers {

public static final SetBucketResourceGroupRequestMarshaller setBucketResourceGroupRequestMarshaller = new SetBucketResourceGroupRequestMarshaller();
public static final PutBucketTransferAccelerationRequestMarshaller putBucketTransferAccelerationRequestMarshaller = new PutBucketTransferAccelerationRequestMarshaller();
public static final CopyObjectsRequestMarshaller copyObjectsRequestMarshaller = new CopyObjectsRequestMarshaller();

public interface RequestMarshaller<R> extends Marshaller<FixedLengthInputStream, R> {

Expand Down Expand Up @@ -1739,6 +1740,34 @@ public byte[] marshall(SetBucketTransferAccelerationRequest input) {
}
}

public static final class CopyObjectsRequestMarshaller implements RequestMarshaller2<CopyObjectsRequest> {

@Override
public byte[] marshall(CopyObjectsRequest input) {
StringBuffer xmlBody = new StringBuffer();

xmlBody.append("<Copy>");
if(input.getObjects() != null && !input.getObjects().isEmpty()){
for (CopyObjects objs : input.getObjects()) {
xmlBody.append("<Object>");
xmlBody.append("<SourceKey>" + escapeKey(objs.getSourceKey()) + "</SourceKey>");
xmlBody.append("<TargetKey>" + escapeKey(objs.getTargetKey()) + "</TargetKey>");
xmlBody.append("</Object>");
}
}
xmlBody.append("</Copy>");
byte[] rawData = null;
try {
rawData = xmlBody.toString().getBytes(DEFAULT_CHARSET_NAME);
} catch (UnsupportedEncodingException e) {
throw new ClientException("Unsupported encoding " + e.getMessage(), e);
}

return rawData;
}

}

private static enum EscapedChar {
// "\r"
RETURN("&#x000D;"),
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,36 @@ public VoidResult renameObject(RenameObjectRequest renameObjectRequest) throws O
return doOperation(request, requestIdResponseParser, bucketName, destObject);
}

public CopyObjectsResult copyObjects(CopyObjectsRequest copyObjectsRequest) throws OSSException, ClientException {

assertParameterNotNull(copyObjectsRequest, "copyObjectsRequest");

String bucketName = copyObjectsRequest.getBucketName();

assertParameterNotNull(bucketName, "bucketName");
ensureBucketNameValid(bucketName);

if(copyObjectsRequest.getObjects() == null && copyObjectsRequest.getObjects().isEmpty()){
throw new IllegalArgumentException("Batch copy object cannot be empty");
}

Map<String, String> headers = new HashMap<String, String>();
populateRequestPayerHeader(headers, copyObjectsRequest.getRequestPayer());

Map<String, String> params = new HashMap<String, String>();
params.put(RequestParameters.COPY, null);

byte[] rawContent = copyObjectsRequestMarshaller.marshall(copyObjectsRequest);

RequestMessage request = new OSSRequestMessageBuilder(getInnerClient()).setEndpoint(getEndpoint(copyObjectsRequest))
.setMethod(HttpMethod.POST).setBucket(bucketName).setParameters(params).setHeaders(headers)
.setInputSize(rawContent.length).setInputStream(new ByteArrayInputStream(rawContent))
.setOriginalRequest(copyObjectsRequest).build();

return doOperation(request, ResponseParsers.copyObjectsResponseParser, bucketName, null, true);
}


private static enum MetadataDirective {

/* Copy metadata from source object */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,5 @@ public final class RequestParameters {
public static final String START_AFTER = "start-after";
public static final String FETCH_OWNER = "fetch-owner";
public static final String SUBRESOURCE_TRANSFER_ACCELERATION = "transferAcceleration";
public static final String COPY = "copy";
}
60 changes: 60 additions & 0 deletions src/main/java/com/aliyun/oss/internal/ResponseParsers.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public final class ResponseParsers {
public static final GetSymbolicLinkResponseParser getSymbolicLinkResponseParser = new GetSymbolicLinkResponseParser();

public static final DeleteDirectoryResponseParser deleteDirectoryResponseParser = new DeleteDirectoryResponseParser();
public static final CopyObjectsResponseParser copyObjectsResponseParser = new CopyObjectsResponseParser();

public static Long parseLongWithDefault(String defaultValue){
if(defaultValue == null || "".equals(defaultValue)){
Expand Down Expand Up @@ -3838,4 +3839,63 @@ private TransferAcceleration parseTransferAcceleration(InputStream inputStream)
}
}

public static final class CopyObjectsResponseParser implements ResponseParser<CopyObjectsResult> {
@Override
public CopyObjectsResult parse(ResponseMessage response) throws ResponseParseException {
try {
CopyObjectsResult result = parseCopyObjects(response.getContent());
result.setRequestId(response.getRequestId());
result.setResponse(response);
return result;
} finally {
safeCloseResponse(response);
}
}

private CopyObjectsResult parseCopyObjects(InputStream inputStream) throws ResponseParseException {
CopyObjectsResult result = new CopyObjectsResult();
if (inputStream == null) {
return result;
}

try {
Element root = getXmlRootElement(inputStream);

if(root.getChild("Success") != null){
List<CopyObjectsSuccessResult> successObjects = new ArrayList<CopyObjectsSuccessResult>();
List<Element> successElements = root.getChild("Success").getChildren("Object");

for (Element e : successElements) {
CopyObjectsSuccessResult successResult = new CopyObjectsSuccessResult();
successResult.setSourceKey(e.getChildText("SourceKey"));
successResult.setTargetKey(e.getChildText("TargetKey"));
successResult.setETag(e.getChildText("ETag"));
successObjects.add(successResult);
}
result.setSuccessObjects(successObjects);
}

if(root.getChild("Failed") != null){
List<CopyObjectsFailedResult> failedObjects = new ArrayList<CopyObjectsFailedResult>();
List<Element> failedElements = root.getChild("Failed").getChildren("Object");

for (Element e : failedElements) {
CopyObjectsFailedResult failedResult = new CopyObjectsFailedResult();
failedResult.setSourceKey(e.getChildText("SourceKey"));
failedResult.setTargetKey(e.getChildText("TargetKey"));
failedResult.setErrorStatus(e.getChildText("ErrorStatus"));
failedObjects.add(failedResult);
}
result.setFailedObjects(failedObjects);
}
return result;
} catch (JDOMParseException e) {
throw new ResponseParseException(e.getPartialDocument() + ": " + e.getMessage(), e);
} catch (Exception e) {
throw new ResponseParseException(e.getMessage(), e);
}
}
}


}
2 changes: 1 addition & 1 deletion src/main/java/com/aliyun/oss/internal/SignParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ public class SignParameters {
SUBRESOURCE_INVENTORY, SUBRESOURCE_INVENTORY_ID, SUBRESOURCE_CONTINUATION_TOKEN, SUBRESOURCE_WORM,
SUBRESOURCE_WORM_ID, SUBRESOURCE_WORM_EXTEND, SUBRESOURCE_CALLBACK, SUBRESOURCE_CALLBACK_VAR,
SUBRESOURCE_DIR, SUBRESOURCE_RENAME, SUBRESOURCE_DIR_DELETE, SUBRESOURCE_TRANSFER_ACCELERATION,
X_OSS_AC_SOURCE_IP, X_OSS_AC_SUBNET_MASK, X_OSS_AC_VPC_ID, X_OSS_AC_FORWARD_ALLOW});
X_OSS_AC_SOURCE_IP, X_OSS_AC_SUBNET_MASK, X_OSS_AC_VPC_ID, X_OSS_AC_FORWARD_ALLOW, COPY});

}
34 changes: 34 additions & 0 deletions src/main/java/com/aliyun/oss/model/CopyObjects.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.aliyun.oss.model;

public class CopyObjects {
// Source object key.
private String sourceKey;
// Target object key.
private String targetKey;

public String getSourceKey() {
return sourceKey;
}

public void setSourceKey(String sourceKey) {
this.sourceKey = sourceKey;
}

public CopyObjects withSourceKey(String sourceKey) {
this.sourceKey = sourceKey;
return this;
}

public String getTargetKey() {
return targetKey;
}

public void setTargetKey(String targetKey) {
this.targetKey = targetKey;
}

public CopyObjects withTargetKey(String targetKey) {
this.targetKey = targetKey;
return this;
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/aliyun/oss/model/CopyObjectsFailedResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.aliyun.oss.model;

public class CopyObjectsFailedResult extends CopyObjects {
// Error state when copying objects.
private String errorStatus;

public String getErrorStatus() {
return errorStatus;
}

public void setErrorStatus(String errorStatus) {
this.errorStatus = errorStatus;
}
}
15 changes: 15 additions & 0 deletions src/main/java/com/aliyun/oss/model/CopyObjectsRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.aliyun.oss.model;

import java.util.List;

public class CopyObjectsRequest extends GenericRequest {
private List<CopyObjects> objects;

public List<CopyObjects> getObjects() {
return objects;
}

public void setObjects(List<CopyObjects> objects) {
this.objects = objects;
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/aliyun/oss/model/CopyObjectsResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.aliyun.oss.model;

import java.util.List;

public class CopyObjectsResult extends GenericResult {
/**
* Successfully copied objects collection.
*/
private List<CopyObjectsSuccessResult> successObjects;
/**
* Copy failed objects collection.
*/
private List<CopyObjectsFailedResult> failedObjects;

public List<CopyObjectsSuccessResult> getSuccessObjects() {
return successObjects;
}

public void setSuccessObjects(List<CopyObjectsSuccessResult> successObjects) {
this.successObjects = successObjects;
}

public List<CopyObjectsFailedResult> getFailedObjects() {
return failedObjects;
}

public void setFailedObjects(List<CopyObjectsFailedResult> failedObjects) {
this.failedObjects = failedObjects;
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/aliyun/oss/model/CopyObjectsSuccessResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.aliyun.oss.model;

public class CopyObjectsSuccessResult extends CopyObjects {
// Target object's ETag
private String eTag;

public String getETag() {
return eTag;
}

public void setETag(String eTag) {
this.eTag = eTag;
}
}
50 changes: 50 additions & 0 deletions src/samples/BatchCopyObjectsSample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;

public class BatchCopyObjectsSample {

private static String endpoint = "*** Provide OSS endpoint ***";
private static String accessKeyId = "*** Provide your AccessKeyId ***";
private static String accessKeySecret = "*** Provide your AccessKeySecret ***";
private static String bucketName = "*** Provide bucket name ***";
private static String key = "*** Provide object name ***";
private static String targetKey = "*** Provide target object name ***";

public static void main(String[] args) {
// Create an OSSClient instance.
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

try {
// batch copy a batch of objects in the same bucket.
byte[] content = { 'A', 'l', 'i', 'y', 'u', 'n' };
ossClient.putObject(bucketName, key, new ByteArrayInputStream(content));

CopyObjectsRequest copyObjectsRequest = new CopyObjectsRequest();
List<CopyObjects> objects = new ArrayList<CopyObjects>();
CopyObjects obj1 = new CopyObjects().withSourceKey(key).withTargetKey(targetKey);
objects.add(obj1);
copyObjectsRequest.setObjects(objects);
copyObjectsRequest.setBucketName(bucketName);
CopyObjectsResult copyObjectsResult = ossClient.copyObjects(copyObjectsRequest);
System.out.println(copyObjectsResult.getSuccessObjects().get(0).getETag());
} catch (OSSException oe) {
System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Error Message: " + ce.getMessage());
} finally {
/*
* Do not forget to shut down the client finally to release all allocated resources.
*/
ossClient.shutdown();
}
}
}
Loading