Commit 72154574 authored by xiexy's avatar xiexy

Default Changelist

parent 7e2c685d
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cos-modules</artifactId>
<groupId>com.cftech</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cos-qcloud-module</artifactId>
<dependencies>
<dependency>
<groupId>com.cftech</groupId>
<artifactId>cos-core-module</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
package com.qcloud.cos;
public interface COSEncryption extends COS{
}
package com.qcloud.cos;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.region.Region;
public class ClientConfig {
// 默认的获取连接的超时时间, 单位ms
private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = -1;
// 默认连接超时, 单位ms
private static final int DEFAULT_CONNECTION_TIMEOUT = 30 * 1000;
// 默认的SOCKET读取超时时间, 单位ms
private static final int DEFAULT_SOCKET_TIMEOUT = 30 * 1000;
// 默认的维护最大HTTP连接数
private static final int DEFAULT_MAX_CONNECTIONS_COUNT = 1024;
// 多次签名的默认过期时间,单位秒
private static final int DEFAULT_SIGN_EXPIRED = 300;
// 默认的user_agent标识
private static final String DEFAULT_USER_AGENT = "cos-java-sdk-v5.4.0";
// Read Limit
private static final int DEFAULT_READ_LIMIT = (2 << 17) + 1;
private Region region;
private HttpProtocol httpProtocol = HttpProtocol.http;
private String endPointSuffix = null;
// http proxy代理,如果使用http proxy代理,需要设置IP与端口
private String httpProxyIp = null;
private int httpProxyPort = 0;
private int signExpired = DEFAULT_SIGN_EXPIRED;
private int connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
private int socketTimeout = DEFAULT_SOCKET_TIMEOUT;
private int maxConnectionsCount = DEFAULT_MAX_CONNECTIONS_COUNT;
private String userAgent = DEFAULT_USER_AGENT;
private int readLimit = DEFAULT_READ_LIMIT;
public ClientConfig(Region region) {
super();
this.region = region;
}
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
public HttpProtocol getHttpProtocol() {
return httpProtocol;
}
public void setHttpProtocol(HttpProtocol httpProtocol) {
this.httpProtocol = httpProtocol;
}
public String getHttpProxyIp() {
return httpProxyIp;
}
public void setHttpProxyIp(String httpProxyIp) {
this.httpProxyIp = httpProxyIp;
}
public int getHttpProxyPort() {
return httpProxyPort;
}
public void setHttpProxyPort(int httpProxyPort) {
this.httpProxyPort = httpProxyPort;
}
public int getSignExpired() {
return signExpired;
}
public void setSignExpired(int signExpired) {
this.signExpired = signExpired;
}
public int getConnectionRequestTimeout() {
return connectionRequestTimeout;
}
public void setConnectionRequestTimeout(int connectionRequestTimeout) {
this.connectionRequestTimeout = connectionRequestTimeout;
}
public int getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public int getSocketTimeout() {
return socketTimeout;
}
public void setSocketTimeout(int socketTimeout) {
this.socketTimeout = socketTimeout;
}
public int getMaxConnectionsCount() {
return maxConnectionsCount;
}
public void setMaxConnectionsCount(int maxConnectionsCount) {
this.maxConnectionsCount = maxConnectionsCount;
}
public void setUserAgent(String userAgent) {
this.userAgent = userAgent;
}
public String getUserAgent() {
return userAgent;
}
public String getEndPointSuffix() {
return endPointSuffix;
}
public void setEndPointSuffix(String endPointSuffix) {
this.endPointSuffix = endPointSuffix;
}
public int getReadLimit() {
return readLimit;
}
public void setReadLimit(int readLimit) {
this.readLimit = readLimit;
}
}
package com.qcloud.cos;
/**
* @author chengwu
* cos返回给用户的错误码信息, code为0为成功
* 此处的错误码是SDK包括:用户的参数错误(如路径不符合), 网络错误(无法和cos服务端通信), 服务端故障, 其他未知错误
*/
public class ErrorCode {
public static final int PARAMS_ERROR = -1; // 参数错误
public static final int NETWORK_ERROR = -2; // 网络错误
public static final int SERVER_ERROR = -3; // 服务端故障
public static final int UNKNOWN_ERROR = -4; // 其他未知错误
}
package com.qcloud.cos;
/**
* Common COS HTTP header values used throughout the COS Java client.
*/
public interface Headers {
/*
* Standard HTTP Headers
*/
public static final String HOST = "Host";
public static final String CACHE_CONTROL = "Cache-Control";
public static final String CONTENT_DISPOSITION = "Content-Disposition";
public static final String CONTENT_ENCODING = "Content-Encoding";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_MD5 = "Content-MD5";
public static final String CONTENT_TYPE = "Content-Type";
public static final String CONTENT_LANGUAGE = "Content-Language";
public static final String DATE = "Date";
public static final String ETAG = "ETag";
public static final String LAST_MODIFIED = "Last-Modified";
public static final String SERVER = "Server";
public static final String USER_AGENT = "User-Agent";
/*
* Cos HTTP Headers
*/
/** Prefix for general COS headers: x-cos- */
public static final String COS_PREFIX = "x-cos-";
/** COS's canned ACL header: x-cos-acl */
public static final String COS_CANNED_ACL = "x-cos-acl";
/** Cos's alternative date header: x-cos-date */
public static final String COS_ALTERNATE_DATE = "x-cos-date";
/** Prefix for COS user metadata: x-cos-meta- */
public static final String COS_USER_METADATA_PREFIX = "x-cos-meta-";
/** COS's version ID header */
public static final String COS_VERSION_ID = "x-cos-version-id";
/** COS's Multi-Factor Authentication header */
public static final String COS_AUTHORIZATION = "Authorization";
/** COS response header for a request's cos request ID */
public static final String REQUEST_ID = "x-cos-request-id";
/** COS response header for TRACE ID */
public static final String TRACE_ID = "x-cos-trace-id";
/** COS request header indicating how to handle metadata when copying an object */
public static final String METADATA_DIRECTIVE = "x-cos-metadata-directive";
/** DevPay token header */
public static final String SECURITY_TOKEN = "x-cos-security-token";
/** Header describing what class of storage a user wants */
public static final String STORAGE_CLASS = "x-cos-storage-class";
/** Header for optional server-side encryption algorithm */
public static final String SERVER_SIDE_ENCRYPTION = "x-cos-server-side-encryption";
/** Header for the encryption algorithm used when encrypting the object with customer-provided keys */
public static final String SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM = "x-cos-server-side-encryption-customer-algorithm";
/** Header for the customer-provided key for server-side encryption */
public static final String SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY = "x-cos-server-side-encryption-customer-key";
/** Header for the MD5 digest of the customer-provided key for server-side encryption */
public static final String SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5 = "x-cos-server-side-encryption-customer-key-MD5";
/** Header for optional object expiration */
public static final String EXPIRATION = "x-cos-expiration";
/** Header for optional object expiration */
public static final String EXPIRES = "Expires";
/** ETag matching constraint header for the copy object request */
public static final String COPY_SOURCE_IF_MATCH = "x-cos-copy-source-if-match";
/** ETag non-matching constraint header for the copy object request */
public static final String COPY_SOURCE_IF_NO_MATCH = "x-cos-copy-source-if-none-match";
/** Unmodified since constraint header for the copy object request */
public static final String COPY_SOURCE_IF_UNMODIFIED_SINCE = "x-cos-copy-source-if-unmodified-since";
/** Modified since constraint header for the copy object request */
public static final String COPY_SOURCE_IF_MODIFIED_SINCE = "x-cos-copy-source-if-modified-since";
/** Range header for the get object request */
public static final String RANGE = "Range";
/**Range header for the copy part request */
public static final String COPY_PART_RANGE = "x-cos-copy-source-range";
/** Modified since constraint header for the get object request */
public static final String GET_OBJECT_IF_MODIFIED_SINCE = "If-Modified-Since";
/** Unmodified since constraint header for the get object request */
public static final String GET_OBJECT_IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
/** ETag matching constraint header for the get object request */
public static final String GET_OBJECT_IF_MATCH = "If-Match";
/** ETag non-matching constraint header for the get object request */
public static final String GET_OBJECT_IF_NONE_MATCH = "If-None-Match";
/** Encrypted symmetric key header that is used in the envelope encryption mechanism */
public static final String CRYPTO_KEY = "x-cos-key";
/** Initialization vector (IV) header that is used in the symmetric and envelope encryption mechanisms */
public static final String CRYPTO_IV = "x-cos-iv";
/** JSON-encoded description of encryption materials used during encryption */
public static final String MATERIALS_DESCRIPTION = "x-cos-matdesc";
/** Instruction file header to be placed in the metadata of instruction files */
public static final String CRYPTO_INSTRUCTION_FILE = "x-cos-crypto-instr-file";
/** Header for the original, unencrypted size of an encrypted object */
public static final String UNENCRYPTED_CONTENT_LENGTH = "x-cos-unencrypted-content-length";
/** Header for the optional original unencrypted Content MD5 of an encrypted object */
public static final String UNENCRYPTED_CONTENT_MD5 = "x-cos-unencrypted-content-md5";
/** Header for optional redirect location of an object */
public static final String REDIRECT_LOCATION = "x-cos-website-redirect-location";
/** Header for the optional restore information of an object */
public static String RESTORE = "x-cos-restore";
/** Header for the optional delete marker information of an object */
public static String DELETE_MARKER = "x-cos-delete-marker";
/**
* Key wrapping algorithm such as "AESWrap" and "RSA/ECB/OAEPWithSHA-256AndMGF1Padding".
*/
public static final String CRYPTO_KEYWRAP_ALGORITHM = "x-cos-wrap-alg";
/**
* Content encryption algorithm, such as "AES/GCM/NoPadding".
*/
public static final String CRYPTO_CEK_ALGORITHM = "x-cos-cek-alg";
/**
* Tag length applicable to authenticated encrypt/decryption.
*/
public static final String CRYPTO_TAG_LENGTH = "x-cos-tag-len";
/** Region where the bucket is located. This header is returned only in HEAD bucket and ListObjects response. */
public static final String COS_BUCKET_REGION = "x-cos-bucket-region";
}
\ No newline at end of file
package com.qcloud.cos.auth;
public class AnonymousCOSCredentials implements COSCredentials {
private String appId;
/**
*
* @param appId the appid which your resource belong to.
* @deprecated appid should be included in bucket name. for example if your appid
* is 125123123, previous bucket is ott. you should set bucket as ott-125123123.
*
* use {@link AnonymousCOSCredentials#AnonymousCOSCredentials()}
*/
@Deprecated
public AnonymousCOSCredentials(String appId) {
super();
if (appId == null) {
throw new IllegalArgumentException("Appid cannot be null.");
}
try {
Long.valueOf(appId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Appid is invalid num str.");
}
this.appId = appId;
}
public AnonymousCOSCredentials() {
super();
this.appId = null;
}
@Override
public String getCOSAppId() {
return appId;
}
@Override
public String getCOSAccessKeyId() {
return null;
}
@Override
public String getCOSSecretKey() {
return null;
}
}
package com.qcloud.cos.auth;
public class BasicCOSCredentials implements COSCredentials {
private final String appId;
private final String accessKey;
private final String secretKey;
/**
*
* @param appId the appid which your resource belong to.
* @param accessKey your accessKey(SecretId). you can get it by https://console.qcloud.com/capi
* @param secretKey your secretKey. you can get it by https://console.qcloud.com/capi
* @deprecated appid should be included in bucket name. for example if your appid
* is 125123123, previous bucket is ott. you should set bucket as ott-125123123.
* use {@link BasicCOSCredentials#BasicCOSCredentials(String, String)}
*/
@Deprecated
public BasicCOSCredentials(String appId, String accessKey, String secretKey) {
super();
if (appId == null) {
throw new IllegalArgumentException("Appid cannot be null.");
}
try {
Long.valueOf(appId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Appid is invalid num str.");
}
if (accessKey == null) {
throw new IllegalArgumentException("Access key cannot be null.");
}
if (secretKey == null) {
throw new IllegalArgumentException("Secret key cannot be null.");
}
this.appId = appId;
this.accessKey = accessKey;
this.secretKey = secretKey;
}
/**
*
* @param accessKey your accessKey(secretId). you can get it by https://console.qcloud.com/capi
* @param secretKey your secretKey. you can get it by https://console.qcloud.com/capi
*
*/
public BasicCOSCredentials(String accessKey, String secretKey) {
super();
appId = null;
if (accessKey == null) {
throw new IllegalArgumentException("Access key cannot be null.");
}
if (secretKey == null) {
throw new IllegalArgumentException("Secret key cannot be null.");
}
this.accessKey = accessKey;
this.secretKey = secretKey;
}
@Override
public String getCOSAppId() {
return appId;
}
@Override
public String getCOSAccessKeyId() {
return accessKey;
}
@Override
public String getCOSSecretKey() {
return secretKey;
}
}
package com.qcloud.cos.auth;
public class BasicSessionCredentials implements COSSessionCredentials {
/**
* @param appId the appid which your resource belong to.
* @param accessKey your accessKey(SecretId). you can get it by https://console.qcloud.com/capi
* @param secretKey your secretKey. you can get it by https://console.qcloud.com/capi
* @param sessionToken the sessionToken you get from cam.
* @deprecated appid should be included in bucket name. for example if your appid is 125123123,
* previous bucket is ott. you should set bucket as ott-125123123. use
* {@link BasicSessionCredentials#BasicSessionCredentials(String, String, String)}
*/
@Deprecated
public BasicSessionCredentials(String appId, String accessKey, String secretKey,
String sessionToken) {
super();
if (appId == null) {
throw new IllegalArgumentException("Appid cannot be null.");
}
try {
Long.valueOf(appId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Appid is invalid num str.");
}
if (accessKey == null) {
throw new IllegalArgumentException("Access key cannot be null.");
}
if (secretKey == null) {
throw new IllegalArgumentException("Secret key cannot be null.");
}
if (sessionToken == null) {
throw new IllegalArgumentException("Session Token cannot be null.");
}
this.appId = appId;
this.accessKey = accessKey;
this.secretKey = secretKey;
this.sessionToken = sessionToken;
}
/**
* @param appId the appid which your resource belong to.
* @param accessKey your accessKey(SecretId). you can get it by https://console.qcloud.com/capi
* @param secretKey your secretKey. you can get it by https://console.qcloud.com/capi
* @param sessionToken the sessionToken you get from cam.
*/
public BasicSessionCredentials(String accessKey, String secretKey, String sessionToken) {
super();
if (accessKey == null) {
throw new IllegalArgumentException("Access key cannot be null.");
}
if (secretKey == null) {
throw new IllegalArgumentException("Secret key cannot be null.");
}
if (sessionToken == null) {
throw new IllegalArgumentException("Session Token cannot be null.");
}
this.appId = null;
this.accessKey = accessKey;
this.secretKey = secretKey;
this.sessionToken = sessionToken;
}
@Override
public String getCOSAppId() {
return appId;
};
@Override
public String getCOSAccessKeyId() {
return accessKey;
}
@Override
public String getCOSSecretKey() {
return secretKey;
}
@Override
public String getSessionToken() {
return sessionToken;
}
private final String appId;
private final String accessKey;
private final String secretKey;
private final String sessionToken;
}
package com.qcloud.cos.auth;
public interface COSCredentials {
/**
* Returns the COS AppId for this credentials object.
*
* @return The COS AppId for this credentials object.
*/
public String getCOSAppId();
/**
* Returns the COS access key ID for this credentials object.
*
* @return The COS access key ID for this credentials object.
*/
public String getCOSAccessKeyId();
/**
* Returns the COS secret access key for this credentials object.
*
* @return The COS secret access key for this credentials object.
*/
public String getCOSSecretKey();
}
package com.qcloud.cos.auth;
public interface COSSessionCredentials extends COSCredentials {
/**
* Returns the session token for this session.
*/
public String getSessionToken();
}
package com.qcloud.cos.auth;
import static com.qcloud.cos.auth.COSSignerConstants.LINE_SEPARATOR;
import static com.qcloud.cos.auth.COSSignerConstants.Q_AK;
import static com.qcloud.cos.auth.COSSignerConstants.Q_HEADER_LIST;
import static com.qcloud.cos.auth.COSSignerConstants.Q_KEY_TIME;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGNATURE;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_KEY;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_VALUE;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_TIME;
import static com.qcloud.cos.auth.COSSignerConstants.Q_URL_PARAM_LIST;
import static com.qcloud.cos.auth.COSSignerConstants.SIGN_EXPIRED_TIME;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.HmacUtils;
import com.qcloud.cos.Headers;
import com.qcloud.cos.http.CosHttpRequest;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.internal.CosServiceRequest;
import com.qcloud.cos.utils.UrlEncoderUtils;
public class COSSigner {
private long signExpiredTime = SIGN_EXPIRED_TIME;
// 获取签名有效期
public long getSignExpiredTime() {
return signExpiredTime;
}
// 设置签名有效期,单位为秒, 默认3600秒
public void setSignExpiredTime(long signExpiredTime) {
this.signExpiredTime = signExpiredTime;
}
private boolean isAnonymous(COSCredentials cred) {
return cred instanceof AnonymousCOSCredentials;
}
public <X extends CosServiceRequest> void sign(CosHttpRequest<X> request, COSCredentials cred) {
if (isAnonymous(cred)) {
return;
}
Date expiredTime = new Date(System.currentTimeMillis() + this.signExpiredTime * 1000);
String authoriationStr =
buildAuthorizationStr(request.getHttpMethod(), request.getResourcePath(),
request.getHeaders(), request.getParameters(), cred, expiredTime);
request.addHeader(Headers.COS_AUTHORIZATION, authoriationStr);
if (cred instanceof COSSessionCredentials) {
request.addHeader(Headers.SECURITY_TOKEN,
((COSSessionCredentials) cred).getSessionToken());
}
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
COSCredentials cred, Date expiredTime) {
return buildAuthorizationStr(methodName, resouce_path, new HashMap<String, String>(),
new HashMap<String, String>(), cred, expiredTime);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
Map<String, String> headerMap, Map<String, String> paramMap, COSCredentials cred,
Date expiredTime) {
if (isAnonymous(cred)) {
return null;
}
Map<String, String> signHeaders = buildSignHeaders(headerMap);
// 签名中的参数和http 头部 都要进行字符串排序
TreeMap<String, String> sortedSignHeaders = new TreeMap<>();
TreeMap<String, String> sortedParams = new TreeMap<>();
sortedSignHeaders.putAll(signHeaders);
sortedParams.putAll(paramMap);
String qHeaderListStr = buildSignMemberStr(sortedSignHeaders);
String qUrlParamListStr = buildSignMemberStr(sortedParams);
String qKeyTimeStr, qSignTimeStr;
qKeyTimeStr = qSignTimeStr = buildTimeStr(expiredTime);
String signKey = HmacUtils.hmacSha1Hex(cred.getCOSSecretKey(), qKeyTimeStr);
String formatMethod = methodName.toString().toLowerCase();
String formatUri = resouce_path;
String formatParameters = formatMapToStr(sortedParams);
String formatHeaders = formatMapToStr(sortedSignHeaders);
String formatStr = new StringBuilder().append(formatMethod).append(LINE_SEPARATOR)
.append(formatUri).append(LINE_SEPARATOR).append(formatParameters)
.append(LINE_SEPARATOR).append(formatHeaders).append(LINE_SEPARATOR).toString();
String hashFormatStr = DigestUtils.sha1Hex(formatStr);
String stringToSign = new StringBuilder().append(Q_SIGN_ALGORITHM_VALUE)
.append(LINE_SEPARATOR).append(qSignTimeStr).append(LINE_SEPARATOR)
.append(hashFormatStr).append(LINE_SEPARATOR).toString();
String signature = HmacUtils.hmacSha1Hex(signKey, stringToSign);
String authoriationStr = new StringBuilder().append(Q_SIGN_ALGORITHM_KEY).append("=")
.append(Q_SIGN_ALGORITHM_VALUE).append("&").append(Q_AK).append("=")
.append(cred.getCOSAccessKeyId()).append("&").append(Q_SIGN_TIME).append("=")
.append(qSignTimeStr).append("&").append(Q_KEY_TIME).append("=").append(qKeyTimeStr)
.append("&").append(Q_HEADER_LIST).append("=").append(qHeaderListStr).append("&")
.append(Q_URL_PARAM_LIST).append("=").append(qUrlParamListStr).append("&")
.append(Q_SIGNATURE).append("=").append(signature).toString();
return authoriationStr;
}
private Map<String, String> buildSignHeaders(Map<String, String> originHeaders) {
Map<String, String> signHeaders = new HashMap<>();
for (String key : originHeaders.keySet()) {
// if (key.equalsIgnoreCase("host") || key.equalsIgnoreCase("content-type")
// || key.equalsIgnoreCase("content-md5") || key.startsWith("x")
// || key.startsWith("X")) {
if (key.equalsIgnoreCase("content-type")
|| key.equalsIgnoreCase("content-md5") || key.startsWith("x")
|| key.startsWith("X")) {
String lowerKey = key.toLowerCase();
String value = originHeaders.get(key);
signHeaders.put(lowerKey, value);
}
}
return signHeaders;
}
private String buildSignMemberStr(Map<String, String> signHeaders) {
StringBuilder strBuilder = new StringBuilder();
boolean seenOne = false;
for (String key : signHeaders.keySet()) {
if (!seenOne) {
seenOne = true;
} else {
strBuilder.append(";");
}
strBuilder.append(key.toLowerCase());
}
return strBuilder.toString();
}
private String formatMapToStr(Map<String, String> kVMap) {
StringBuilder strBuilder = new StringBuilder();
boolean seeOne = false;
for (String key : kVMap.keySet()) {
String lowerKey = key.toLowerCase();
String encodeKey = UrlEncoderUtils.encode(lowerKey);
String encodedValue = "";
if (kVMap.get(key) != null) {
encodedValue = UrlEncoderUtils.encode(kVMap.get(key));
}
if (!seeOne) {
seeOne = true;
} else {
strBuilder.append("&");
}
strBuilder.append(encodeKey).append("=").append(encodedValue);
}
return strBuilder.toString();
}
private String buildTimeStr(Date expiredTime) {
StringBuilder strBuilder = new StringBuilder();
long startTime = System.currentTimeMillis() / 1000;
long endTime = expiredTime.getTime() / 1000;
strBuilder.append(startTime).append(";").append(endTime);
return strBuilder.toString();
}
}
package com.qcloud.cos.auth;
public class COSSignerConstants {
public static final String LINE_SEPARATOR = "\n";
public static final String Q_SIGN_ALGORITHM_KEY = "q-sign-algorithm";
public static final String Q_SIGN_ALGORITHM_VALUE = "sha1";
public static final String Q_AK = "q-ak";
public static final String Q_SIGN_TIME = "q-sign-time";
public static final String Q_KEY_TIME = "q-key-time";
public static final String Q_HEADER_LIST = "q-header-list";
public static final String Q_URL_PARAM_LIST = "q-url-param-list";
public static final String Q_SIGNATURE = "q-signature";
public static final long SIGN_EXPIRED_TIME = 3600;
}
package com.qcloud.cos.common_utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.Charset;
/**
* @author chengwu
* 封装了一些常用的文件操作函数
*/
public class CommonFileUtils {
private static Logger LOG = LoggerFactory.getLogger(CommonFileUtils.class);
/**
* 判断指定路径的文件是否有效, 即文件存在,且可读
* @param filePath
* @return 有效返回true, 否则返回false
*/
public static boolean isLegalFile(String filePath) {
File file = new File(filePath);
if (!file.exists() || file.isDirectory() || !file.canRead()) {
return false;
}
return true;
}
/**
* 获取文件长度,单位为字节
*
* @param filePath 文件的本地路径
* @return 文件长度,单位为字节
* @throws Exception 文件不存在或者是一个目录,则抛出异常
*/
public static long getFileLength(String filePath) throws Exception {
File file = new File(filePath);
return file.length();
}
/**
* 打开对应的文件,并返回文件输入流
*
* @param filePath 文件路径
* @return 文件输入流
* @throws FileNotFoundException 如果文件不存在,则抛出异常
*/
public static FileInputStream getFileInputStream(String filePath) throws Exception {
FileInputStream localFileInputStream = new FileInputStream(filePath);
return localFileInputStream;
}
/**
* 关闭对应的文件流
*
* @param inputStream 待关闭的文件流
* @param filePath 对应的文件名
* @throws IOException 关闭时发生IO异常,则抛出
*/
public static void closeFileStream(InputStream inputStream, String filePath){
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
LOG.error("close file {} occur an IOExcpetion {}", filePath, e);
}
}
/**
* 获取小文件的全部内容
*
* @param filePath
* @return
* @throws Exception
*/
public static String getFileContent(String filePath) throws Exception {
int fileLength = ((Long) getFileLength(filePath)).intValue();
return getFileContent(filePath, 0, fileLength);
}
/**
* 获取文件指定块的内容
*
* @param filePath 文件路径
* @param offset 偏移量,即从哪里开始读取,单位为字节
* @param length 读取的长度,单位为字节
* @return 返回读取的内容,实际读取的长度小于等于length
* @throws Exception
*/
public static String getFileContent(String filePath, long offset, int length) throws Exception {
FileInputStream fileInputStream = null;
try {
fileInputStream = getFileInputStream(filePath);
return getFileContent(fileInputStream, offset, length);
} finally {
closeFileStream(fileInputStream, filePath);
}
}
/**
* 读取指定流从某处开始的内容,此函数有一定的风险,如果流对应的内容过大,则会造成OOM
*
* @param inputStream
* @param offset 读取的开始偏移
* @param length 读取的长度
* @return 读取的内容
* @throws Exception
*/
public static String getFileContent(InputStream inputStream, long offset, int length)
throws Exception {
byte[] fileContent = getFileContentByte(inputStream, offset, length);
return new String(fileContent, Charset.forName("ISO-8859-1"));
}
public static byte[] getFileContentByte(InputStream inputStream, long offset, int length)
throws Exception {
if (offset < 0 || length < 0) {
throw new Exception("getFileContent param error");
}
byte[] fileContent = null;
byte[] tempBuf = new byte[length];
inputStream.skip(offset);
int readLen = inputStream.read(tempBuf);
if (readLen < 0) {
fileContent = new byte[0];
return fileContent;
}
if (readLen < length) {
fileContent = new byte[readLen];
System.arraycopy(tempBuf, 0, fileContent, 0, readLen);
} else {
fileContent = tempBuf;
}
return fileContent;
}
/**
* 删除文件
* @param filePath 文件路径
*/
public static void remove(String filePath) {
File file = new File(filePath);
if (file.exists() && file.isFile()) {
file.delete();
}
}
/**
* 获取文件上次的修改时间
*
* @param filePath 文件的本地路径
* @return 文件长度,单位为字节
* @throws Exception 文件不存在或者是一个目录,则抛出异常
*/
public static long getFileLastModified(String filePath) throws Exception {
if (!isLegalFile(filePath)) {
String errorMsg = filePath + " is not file or not exist or can't be read!";
LOG.error(errorMsg);
throw new Exception(errorMsg);
}
File file = new File(filePath);
return file.lastModified();
}
}
package com.qcloud.cos.common_utils;
import com.qcloud.cos.exception.ParamException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author chengwu 封装一些参数检查的类,如果检查未通过抛出参数异常
*/
public class CommonParamCheckUtils {
/**
* 判断参数是否为NULL,如果为NULL,抛出参数异常
*
* @param objName
* 参数名
* @param obj
* 参数对象
* @throws ParamException
*/
public static void AssertNotNull(String objName, Object obj) throws ParamException {
if (obj == null) {
throw new ParamException(objName + " is null, please check!");
}
}
/**
* 判断文件是否适合使用整文件上传,使用范围0 ~ 10MB, 大文件应该用分片上传
*
* @param localFilePath
* 本地文件路径
* @throws ParamException
*/
public static void AssertUploadEntireFileInRange(String localFilePath) throws ParamException {
long fileSize = 0;
try {
fileSize = CommonFileUtils.getFileLength(localFilePath);
} catch (Exception e) {
throw new ParamException(localFilePath + " is not effective file!");
}
long maxFileSize = 10 * 1024 * 1024;
if (fileSize > maxFileSize) {
throw new ParamException(localFilePath + " is too large, please use uploadSliceFile interface!");
}
}
/**
* 判断分片尺寸是否在规定的范围内,抛出参数异常,目前的有效值为64KB ~ 10MB
*
* @param sliceSize
* 分片大小, 单位Byte
* @throws ParamException
*/
public static void AssertSliceInRange(int sliceSize) throws ParamException {
int maxSliceSize = 10 * 1024 * 1024; // 10MB
int minSliceSize = 64 * 1024; // 64KB
if (sliceSize > maxSliceSize || sliceSize < minSliceSize) {
throw new ParamException("sliceSize legal value is [64KB, 100MB]");
}
}
private static void AssertNotContainIllegalLetter(String cosPath) throws ParamException {
String[] illegalLetters = {"?", "*", ":", "|", "\\", "<", ">", "\""};
for (String illegalLetter : illegalLetters) {
if (cosPath.contains(illegalLetter)) {
throw new ParamException("cosFilePath contail illeagl letter " + illegalLetter);
}
}
String pattern = "/(\\s*)/";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(cosPath);
if (m.find()) {
throw new ParamException("cosFilePath contail illeagl letter / /");
}
}
/**
* 判断用户指定的cos目录路径是否合法有效, 即必须以/结尾, 同时不包含非法字符
*
* @param cosFolderPath
* cos目录路径
* @throws ParamException
*/
public static void AssertLegalCosFolderPath(String cosFolderPath) throws ParamException {
if (cosFolderPath == null || !cosFolderPath.startsWith("/") || !cosFolderPath.endsWith("/")) {
throw new ParamException(cosFolderPath + " is not cos folder path! Tips: make sure ends with /");
}
AssertNotContainIllegalLetter(cosFolderPath);
}
/**
* 判断用户指定的cos文件路径是否合法有效, 即不以/结尾, 同时不包含非法字符
*
* @param cosFilePath
* cos文件路径
* @throws ParamException
*/
public static void AssertLegalCosFilePath(String cosFilePath) throws ParamException {
if (cosFilePath == null || !cosFilePath.startsWith("/") || cosFilePath.endsWith("/")) {
throw new ParamException(cosFilePath + " is not cos file path! Tips: make sure not ends with /");
}
AssertNotContainIllegalLetter(cosFilePath);
}
/**
* 判断cos目录是否是根路径,即路径为/
*
* @param cosCosFolderPath
* cos目录路径
* @throws ParamException
*/
public static void AssertNotRootCosPath(String cosCosFolderPath) throws ParamException {
if (cosCosFolderPath == null || cosCosFolderPath.equals("/")) {
throw new ParamException(
"bucket operation is only allowed by web console! please visit http://console.qcloud.com/cos!");
}
}
/**
* 判断用户指定的本地文件路径是否合法有效,即文件存在且可读
*
* @param localFilePath
* 本地文件路径
* @throws ParamException
*/
public static void AssertLegalLocalFilePath(String localFilePath) throws ParamException {
if (localFilePath == null || !CommonFileUtils.isLegalFile(localFilePath)) {
throw new ParamException(localFilePath + " is not file or not exist or can't be read!");
}
}
public static void AssertLegalXCosMeta(Map<String, String> xCosMetaMap) throws ParamException {
for (String x_cos_meta_key : xCosMetaMap.keySet()) {
AssertNotNull("x_cos_meta_key", x_cos_meta_key);
if (!x_cos_meta_key.startsWith("x-cos-meta-")) {
throw new ParamException("x-cos-meta name must starts with x-cos-meta-");
}
String x_cos_meta_value = xCosMetaMap.get(x_cos_meta_key);
AssertNotNull("x_cos_meta_value", x_cos_meta_value);
if (x_cos_meta_value.isEmpty()) {
throw new ParamException("x-cos-meta value can't be empty!");
}
}
}
public static void AssertLegalUpdateFlag(int updateFlag) throws ParamException {
if (updateFlag == 0) {
throw new ParamException("please update at least one attribute!");
}
}
public static void AssertLegalSliceSize(int sliceSize) throws ParamException {
if (sliceSize != 512 * 1024 && sliceSize != 1024 * 1024 && sliceSize != 2 * 1024 * 1024
&& sliceSize != 3 * 1024 * 1024) {
throw new ParamException("valid slice is 512KB, 1MB, 2MB, 3MB");
} else {
}
}
}
package com.qcloud.cos.common_utils;
import com.qcloud.cos.exception.AbstractCosException;
import com.qcloud.cos.exception.UnknownException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class CommonPathUtils {
private static final Logger LOG = LoggerFactory.getLogger(CommonPathUtils.class);
private static final String PATH_DELIMITER = "/";
public static String encodeRemotePath(String urlPath) throws AbstractCosException {
StringBuilder pathBuilder = new StringBuilder();
String[] pathSegmentsArr = urlPath.split(PATH_DELIMITER);
for (String pathSegment : pathSegmentsArr) {
if (!pathSegment.isEmpty()) {
try {
pathBuilder.append(PATH_DELIMITER).append(URLEncoder.encode(pathSegment, "UTF-8").replace("+", "%20"));
} catch (UnsupportedEncodingException e) {
String errMsg = "Unsupported ecnode exception:" + e.toString();
LOG.error(errMsg);
throw new UnknownException(errMsg);
}
}
}
if (urlPath.endsWith(PATH_DELIMITER)) {
pathBuilder.append(PATH_DELIMITER);
}
return pathBuilder.toString();
}
}
package com.qcloud.cos.common_utils;
/**
* 求sha1, 未使用JAVA自带类,是为了获取分片的中间状态(state数组)
* @author chengwu
*
*/
public final class CommonSha1Utils {
private int state[] = new int[5];
private long count;
public byte[] digestBits;
public boolean digestValid;
public CommonSha1Utils() {
state = new int[5];
count = 0;
if (block == null)
block = new int[16];
digestBits = new byte[20];
digestValid = false;
}
/**
* Add specific bytes to the digest.
*/
public synchronized void update(byte input[], int offset, int len) {
for (int i = 0; i < len; i++) {
update(input[i + offset]);
}
}
/**
* Add an array of bytes to the digest.
*/
public synchronized void update(byte input[]) {
update(input, 0, input.length);
}
/**
* Treat the string as a sequence of ISO-Latin1 (8 bit) characters.
*/
public void updateASCII(String input) {
int i, len;
byte x;
len = input.length();
for (i = 0; i < len; i++) {
x = (byte) (input.charAt(i) & 0xff);
update(x);
}
}
/*
* The following array forms the basis for the transform buffer. Update puts bytes into this
* buffer and then transform adds it into the state of the digest.
*/
private int block[] = new int[16];
private int blockIndex;
/*
* These functions are taken out of #defines in Steve's code. Java doesn't have a preprocessor
* so the first step is to just promote them to real methods. Later we can optimize them out
* into inline code, note that by making them final some compilers will inline them when given
* the -O flag.
*/
final int rol(int value, int bits) {
int q = (value << bits) | (value >>> (32 - bits));
return q;
}
final int blk0(int i) {
block[i] = (rol(block[i], 24) & 0xFF00FF00) | (rol(block[i], 8) & 0x00FF00FF);
return block[i];
}
final int blk(int i) {
block[i & 15] = rol(block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15]
^ block[i & 15], 1);
return (block[i & 15]);
}
final void R0(int data[], int v, int w, int x, int y, int z, int i) {
data[z] += ((data[w] & (data[x] ^ data[y])) ^ data[y]) + blk0(i) + 0x5A827999
+ rol(data[v], 5);
data[w] = rol(data[w], 30);
}
final void R1(int data[], int v, int w, int x, int y, int z, int i) {
data[z] +=
((data[w] & (data[x] ^ data[y])) ^ data[y]) + blk(i) + 0x5A827999 + rol(data[v], 5);
data[w] = rol(data[w], 30);
}
final void R2(int data[], int v, int w, int x, int y, int z, int i) {
data[z] += (data[w] ^ data[x] ^ data[y]) + blk(i) + 0x6ED9EBA1 + rol(data[v], 5);
data[w] = rol(data[w], 30);
}
final void R3(int data[], int v, int w, int x, int y, int z, int i) {
data[z] += (((data[w] | data[x]) & data[y]) | (data[w] & data[x])) + blk(i) + 0x8F1BBCDC
+ rol(data[v], 5);
data[w] = rol(data[w], 30);
}
final void R4(int data[], int v, int w, int x, int y, int z, int i) {
data[z] += (data[w] ^ data[x] ^ data[y]) + blk(i) + 0xCA62C1D6 + rol(data[v], 5);
data[w] = rol(data[w], 30);
}
int dd[] = new int[5];
/**
* Hash a single 512-bit block. This is the core of the algorithm.
*
* Note that working with arrays is very inefficent in Java as it does a class cast check each
* time you store into the array.
*
*/
void transform() {
/* Copy context->state[] to working vars */
dd[0] = state[0];
dd[1] = state[1];
dd[2] = state[2];
dd[3] = state[3];
dd[4] = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(dd, 0, 1, 2, 3, 4, 0);
R0(dd, 4, 0, 1, 2, 3, 1);
R0(dd, 3, 4, 0, 1, 2, 2);
R0(dd, 2, 3, 4, 0, 1, 3);
R0(dd, 1, 2, 3, 4, 0, 4);
R0(dd, 0, 1, 2, 3, 4, 5);
R0(dd, 4, 0, 1, 2, 3, 6);
R0(dd, 3, 4, 0, 1, 2, 7);
R0(dd, 2, 3, 4, 0, 1, 8);
R0(dd, 1, 2, 3, 4, 0, 9);
R0(dd, 0, 1, 2, 3, 4, 10);
R0(dd, 4, 0, 1, 2, 3, 11);
R0(dd, 3, 4, 0, 1, 2, 12);
R0(dd, 2, 3, 4, 0, 1, 13);
R0(dd, 1, 2, 3, 4, 0, 14);
R0(dd, 0, 1, 2, 3, 4, 15);
R1(dd, 4, 0, 1, 2, 3, 16);
R1(dd, 3, 4, 0, 1, 2, 17);
R1(dd, 2, 3, 4, 0, 1, 18);
R1(dd, 1, 2, 3, 4, 0, 19);
R2(dd, 0, 1, 2, 3, 4, 20);
R2(dd, 4, 0, 1, 2, 3, 21);
R2(dd, 3, 4, 0, 1, 2, 22);
R2(dd, 2, 3, 4, 0, 1, 23);
R2(dd, 1, 2, 3, 4, 0, 24);
R2(dd, 0, 1, 2, 3, 4, 25);
R2(dd, 4, 0, 1, 2, 3, 26);
R2(dd, 3, 4, 0, 1, 2, 27);
R2(dd, 2, 3, 4, 0, 1, 28);
R2(dd, 1, 2, 3, 4, 0, 29);
R2(dd, 0, 1, 2, 3, 4, 30);
R2(dd, 4, 0, 1, 2, 3, 31);
R2(dd, 3, 4, 0, 1, 2, 32);
R2(dd, 2, 3, 4, 0, 1, 33);
R2(dd, 1, 2, 3, 4, 0, 34);
R2(dd, 0, 1, 2, 3, 4, 35);
R2(dd, 4, 0, 1, 2, 3, 36);
R2(dd, 3, 4, 0, 1, 2, 37);
R2(dd, 2, 3, 4, 0, 1, 38);
R2(dd, 1, 2, 3, 4, 0, 39);
R3(dd, 0, 1, 2, 3, 4, 40);
R3(dd, 4, 0, 1, 2, 3, 41);
R3(dd, 3, 4, 0, 1, 2, 42);
R3(dd, 2, 3, 4, 0, 1, 43);
R3(dd, 1, 2, 3, 4, 0, 44);
R3(dd, 0, 1, 2, 3, 4, 45);
R3(dd, 4, 0, 1, 2, 3, 46);
R3(dd, 3, 4, 0, 1, 2, 47);
R3(dd, 2, 3, 4, 0, 1, 48);
R3(dd, 1, 2, 3, 4, 0, 49);
R3(dd, 0, 1, 2, 3, 4, 50);
R3(dd, 4, 0, 1, 2, 3, 51);
R3(dd, 3, 4, 0, 1, 2, 52);
R3(dd, 2, 3, 4, 0, 1, 53);
R3(dd, 1, 2, 3, 4, 0, 54);
R3(dd, 0, 1, 2, 3, 4, 55);
R3(dd, 4, 0, 1, 2, 3, 56);
R3(dd, 3, 4, 0, 1, 2, 57);
R3(dd, 2, 3, 4, 0, 1, 58);
R3(dd, 1, 2, 3, 4, 0, 59);
R4(dd, 0, 1, 2, 3, 4, 60);
R4(dd, 4, 0, 1, 2, 3, 61);
R4(dd, 3, 4, 0, 1, 2, 62);
R4(dd, 2, 3, 4, 0, 1, 63);
R4(dd, 1, 2, 3, 4, 0, 64);
R4(dd, 0, 1, 2, 3, 4, 65);
R4(dd, 4, 0, 1, 2, 3, 66);
R4(dd, 3, 4, 0, 1, 2, 67);
R4(dd, 2, 3, 4, 0, 1, 68);
R4(dd, 1, 2, 3, 4, 0, 69);
R4(dd, 0, 1, 2, 3, 4, 70);
R4(dd, 4, 0, 1, 2, 3, 71);
R4(dd, 3, 4, 0, 1, 2, 72);
R4(dd, 2, 3, 4, 0, 1, 73);
R4(dd, 1, 2, 3, 4, 0, 74);
R4(dd, 0, 1, 2, 3, 4, 75);
R4(dd, 4, 0, 1, 2, 3, 76);
R4(dd, 3, 4, 0, 1, 2, 77);
R4(dd, 2, 3, 4, 0, 1, 78);
R4(dd, 1, 2, 3, 4, 0, 79);
/* Add the working vars back into context.state[] */
state[0] += dd[0];
state[1] += dd[1];
state[2] += dd[2];
state[3] += dd[3];
state[4] += dd[4];
}
/**
*
* SHA1Init - Initialize new context
*/
public void init() {
/* SHA1 initialization constants */
state[0] = 0x67452301;
state[1] = 0xEFCDAB89;
state[2] = 0x98BADCFE;
state[3] = 0x10325476;
state[4] = 0xC3D2E1F0;
count = 0;
digestBits = new byte[20];
digestValid = false;
blockIndex = 0;
}
/**
* Add one byte to the digest. When this is implemented all of the abstract class methods end up
* calling this method for types other than bytes.
*/
public synchronized void update(byte b) {
int mask = (8 * (blockIndex & 3));
count += 8;
block[blockIndex >> 2] &= ~(0xff << mask);
block[blockIndex >> 2] |= (b & 0xff) << mask;
blockIndex++;
if (blockIndex == 64) {
transform();
blockIndex = 0;
}
}
/**
* Complete processing on the message digest.
*/
public void finish() {
byte bits[] = new byte[8];
int i;
for (i = 0; i < 8; i++) {
bits[i] = (byte) ((count >>> (((7 - i) * 8))) & 0xff);
}
update((byte) 128);
while (blockIndex != 56)
update((byte) 0);
// This should cause a transform to happen.
update(bits);
for (i = 0; i < 20; i++) {
digestBits[i] = (byte) ((state[i >> 2] >> ((3 - (i & 3)) * 8)) & 0xff);
}
digestValid = true;
}
/** Return a string that identifies this algorithm */
public String getAlg() {
return "SHA1";
}
/**
* Print out the digest in a form that can be easily compared to the test vectors.
*/
public String digout() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 20; i++) {
char c1, c2;
c1 = (char) ((digestBits[i] >>> 4) & 0xf);
c2 = (char) (digestBits[i] & 0xf);
c1 = (char) ((c1 > 9) ? 'a' + (c1 - 10) : '0' + c1);
c2 = (char) ((c2 > 9) ? 'a' + (c2 - 10) : '0' + c2);
sb.append(c1);
sb.append(c2);
/*
* if (((i+1) % 4) == 0) sb.append(' ');
*/
}
return sb.toString();
}
// 输出中间状态
public String dumpTempState() {
StringBuilder sb = new StringBuilder();
final int count = 5;
for (int index = 0; index < count; ++index) {
for (int i = 0; i < 4; ++i) {
sb.append(String.format("%02x", (byte)(state[index] >>> (i * 8))));
}
}
return sb.toString();
}
}
package com.qcloud.cos.demo;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.Bucket;
import com.qcloud.cos.model.CannedAccessControlList;
import com.qcloud.cos.model.CreateBucketRequest;
import com.qcloud.cos.region.Region;
/**
* 展示了创建bucket, 删除bucket, 查询bucket是否存在的demo
*
*/
public class BucketDemo {
// 创建bucket
public static void CreateBucketDemo() {
// 1 初始化用户身份信息(appid, secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名称, 需包含appid
String bucketName = "publicreadbucket-1251668577";
CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
// 设置bucket的权限为PublicRead(公有读私有写), 其他可选有私有读写, 公有读私有写
createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead);
Bucket bucket = cosclient.createBucket(createBucketRequest);
// 关闭客户端
cosclient.shutdown();
}
// 删除bucket, 只用于空bucket, 含有数据的bucket需要在删除前清空删除。
public static void DeleteBucketDemo() {
// 1 初始化用户身份信息(appid, secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名称, 需包含appid
String bucketName = "publicreadbucket-1251668577";
// 删除bucket
cosclient.deleteBucket(bucketName);
// 关闭客户端
cosclient.shutdown();
}
// 查询bucket是否存在
public static void JudgeBucketExistDemo() {
// 1 初始化用户身份信息(appid, secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
String bucketName = "publicreadbucket-1251668577";
// 判断bucket是否存在
cosclient.doesBucketExist(bucketName);
// 关闭客户端
cosclient.shutdown();
}
}
package com.qcloud.cos.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.CopyObjectRequest;
import com.qcloud.cos.model.CopyObjectResult;
import com.qcloud.cos.model.CopyResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.Copy;
import com.qcloud.cos.transfer.TransferManager;
public class CopyFileDemo {
// copyObject最大支持5G文件的copy, 5G以上的文件copy请参照TransferManagerDemo中的copy示例
public static void copySmallFileDemo() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// 要拷贝的bucket region, 支持跨园区拷贝
Region srcBucketRegion = new Region("ap-shanghai");
// 源bucket, bucket名需包含appid
String srcBucketName = "srcBucket-1251668577";
// 要拷贝的源文件
String srcKey = "aaa/bbb.txt";
// 目的bucket, bucket名需包含appid
String destBucketName = "destBucket-1251668577";
// 要拷贝的目的文件
String destKey = "ccc/ddd.txt";
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketRegion, srcBucketName,
srcKey, destBucketName, destKey);
try {
CopyObjectResult copyObjectResult = cosclient.copyObject(copyObjectRequest);
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
}
cosclient.shutdown();
}
// 对于5G以上的文件,需要通过分块上传中的copypart来实现,步骤较多,实现较复杂。
// 因此在TransferManager中封装了一个copy接口,能根据文件大小自动的选择接口,既支持5G以下的文件copy, 也支持5G以上的文件copy。推荐使用该接口进行文件的copy。
public static void copyBigFileDemo() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
ExecutorService threadPool = Executors.newFixedThreadPool(32);
// 传入一个threadpool, 若不传入线程池, 默认TransferManager中会生成一个单线程的线程池。
TransferManager transferManager = new TransferManager(cosclient, threadPool);
// 要拷贝的bucket region, 支持跨园区拷贝
Region srcBucketRegion = new Region("ap-shanghai");
// 源bucket, bucket名需包含appid
String srcBucketName = "srcBucket-1251668577";
// 要拷贝的源文件
String srcKey = "aaa/bbb.txt";
// 目的bucket, bucket名需包含appid
String destBucketName = "destBucket-1251668577";
// 要拷贝的目的文件
String destKey = "ccc/ddd.txt";
// 生成用于获取源文件信息的srcCOSClient
COSClient srcCOSClient = new COSClient(cred, new ClientConfig(srcBucketRegion));
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketRegion, srcBucketName,
srcKey, destBucketName, destKey);
try {
Copy copy = transferManager.copy(copyObjectRequest, srcCOSClient, null);
// 返回一个异步结果copy, 可同步的调用waitForCopyResult等待copy结束, 成功返回CopyResult, 失败抛出异常.
CopyResult copyResult = copy.waitForCopyResult();
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
transferManager.shutdownNow();
srcCOSClient.shutdown();
cosclient.shutdown();
}
}
package com.qcloud.cos.demo;
import java.util.ArrayList;
import java.util.List;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.exception.MultiObjectDeleteException;
import com.qcloud.cos.exception.MultiObjectDeleteException.DeleteError;
import com.qcloud.cos.model.DeleteObjectRequest;
import com.qcloud.cos.model.DeleteObjectsRequest;
import com.qcloud.cos.model.DeleteObjectsRequest.KeyVersion;
import com.qcloud.cos.model.DeleteObjectsResult;
import com.qcloud.cos.model.DeleteObjectsResult.DeletedObject;
import com.qcloud.cos.region.Region;
/**
* DelFileDemo展示了删除单个文件的DelObject, 删除多个文件的DelObjects的使用示例.
*/
public class DelFileDemo {
// 删除单个文件(不带版本号, 即bucket未开启多版本)
public static void DelSingleFile() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
try {
String key = "aaa/bbb.txt";
cosclient.deleteObject(bucketName, key);
} catch (CosServiceException e) { // 如果是其他错误, 比如参数错误, 身份验证不过等会抛出CosServiceException
e.printStackTrace();
} catch (CosClientException e) { // 如果是客户端错误,比如连接不上COS
e.printStackTrace();
}
// 关闭客户端
cosclient.shutdown();
}
// 批量删除文件(不带版本号, 即bucket未开启多版本)
public static void BatchDelFile() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName);
// 设置要删除的key列表, 最多一次删除1000个
ArrayList<KeyVersion> keyList = new ArrayList<>();
// 传入要删除的文件名
keyList.add(new KeyVersion("/aaa.txt"));
keyList.add(new KeyVersion("/bbb.mp4"));
keyList.add(new KeyVersion("/ccc/ddd.jpg"));
deleteObjectsRequest.setKeys(keyList);
// 批量删除文件
try {
DeleteObjectsResult deleteObjectsResult = cosclient.deleteObjects(deleteObjectsRequest);
List<DeletedObject> deleteObjectResultArray = deleteObjectsResult.getDeletedObjects();
} catch (MultiObjectDeleteException mde) { // 如果部分产出成功部分失败, 返回MultiObjectDeleteException
List<DeletedObject> deleteObjects = mde.getDeletedObjects();
List<DeleteError> deleteErrors = mde.getErrors();
} catch (CosServiceException e) { // 如果是其他错误, 比如参数错误, 身份验证不过等会抛出CosServiceException
e.printStackTrace();
} catch (CosClientException e) { // 如果是客户端错误,比如连接不上COS
e.printStackTrace();
}
// 关闭客户端
cosclient.shutdown();
}
// 批量删除带有版本号的文件(即bucket开启了多版本)
public static void BatchDelFileWithVersion() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName);
// 设置要删除的key列表, 最多一次删除1000个
ArrayList<KeyVersion> keyList = new ArrayList<>();
// 传入要删除的文件名
keyList.add(new KeyVersion("/aaa.txt", "axbefagagaxxfafa"));
keyList.add(new KeyVersion("/bbb.mp4", "awcafa1faxg0lx"));
keyList.add(new KeyVersion("/ccc/ddd.jpg", "kafa1kxxaa2ymh"));
deleteObjectsRequest.setKeys(keyList);
// 批量删除文件
try {
DeleteObjectsResult deleteObjectsResult = cosclient.deleteObjects(deleteObjectsRequest);
List<DeletedObject> deleteObjectResultArray = deleteObjectsResult.getDeletedObjects();
} catch (MultiObjectDeleteException mde) { // 如果部分产出成功部分失败, 返回MultiObjectDeleteException
List<DeletedObject> deleteObjects = mde.getDeletedObjects();
List<DeleteError> deleteErrors = mde.getErrors();
} catch (CosServiceException e) { // 如果是其他错误, 比如参数错误, 身份验证不过等会抛出CosServiceException
e.printStackTrace();
} catch (CosClientException e) { // 如果是客户端错误,比如连接不上COS
e.printStackTrace();
}
// 关闭客户端
cosclient.shutdown();
}
}
///*
// * To change this license header, choose License Headers in Project Properties. To change this
// * template file, choose Tools | Templates and open the template in the editor.
// */
//package com.qcloud.cos.demo;
//
//import com.qcloud.cos.COSClient;
//import com.qcloud.cos.ClientConfig;
//import com.qcloud.cos.request.CreateFolderRequest;
//import com.qcloud.cos.sign.Credentials;
//
//
///**
// * @author chengwu cos Demo代码
// */
//public class Demo {
//
// public static void main(String[] args) throws Exception {
//
// // 设置用户属性, 包括appid, secretId和SecretKey
// // 这些属性可以通过cos控制台获取(https://console.qcloud.com/cos)
// long appId = 1253344332;
// String secretId = "AKID1tZ2IKGmCOM8h3q7qMeiZDerqcAVtWDg";
// String secretKey = "MYXIq9GApHWYNyMXVEj04vYyBAvSmtmS";
// // 设置要操作的bucket
// String bucketName = "faye5";
// // 初始化客户端配置
// ClientConfig clientConfig = new ClientConfig();
// // 设置bucket所在的区域,比如广州(gz), 天津(tj)
// clientConfig.setRegion("sh");
// // 初始化秘钥信息
// Credentials cred = new Credentials(appId, secretId, secretKey);
// // 初始化cosClient
// COSClient cosClient = new COSClient(clientConfig, cred);
// ///////////////////////////////////////////////////////////////
// // 文件操作 //
// ///////////////////////////////////////////////////////////////
// // 1. 上传文件(默认不覆盖)
// // 将本地的local_file_1.txt上传到bucket下的根分区下,并命名为sample_file.txt
// // 默认不覆盖, 如果cos上已有文件, 则返回错误
// /*String cosFilePath = "/sample_file.txt";
// String localFilePath1 = "src/test/resources/bigfile.txt";
// UploadFileRequest uploadFileRequest =
// new UploadFileRequest(bucketName, cosFilePath, localFilePath1);
// uploadFileRequest.setEnableSavePoint(false);
// uploadFileRequest.setEnableShaDigest(false);
// String uploadFileRet = cosClient.uploadFile(uploadFileRequest);
// System.out.println("upload file ret:" + uploadFileRet);
//
// // 2. 下载文件
// String localPathDown = "src/test/resources/local_file_down.txt";
// GetFileLocalRequest getFileLocalRequest =
// new GetFileLocalRequest(bucketName, cosFilePath, localPathDown);
// getFileLocalRequest.setUseCDN(false);
// getFileLocalRequest.setReferer("*.myweb.cn");
// String getFileResult = cosClient.getFileLocal(getFileLocalRequest);
// System.out.println("getFileResult:" + getFileResult);
//
// // 3. 上传文件(覆盖)
// // 将本地的local_file_2.txt上传到bucket下的根分区下,并命名为sample_file.txt
// String localFilePath2 = "src/test/resources/local_file_2.txt";
// byte[] contentBuffer = CommonFileUtils.getFileContent(localFilePath2)
// .getBytes(Charset.forName(("ISO-8859-1")));
// UploadFileRequest overWriteFileRequest =
// new UploadFileRequest(bucketName, cosFilePath, contentBuffer);
// overWriteFileRequest.setInsertOnly(InsertOnly.OVER_WRITE);
// String overWriteFileRet = cosClient.uploadFile(overWriteFileRequest);
// System.out.println("overwrite file ret:" + overWriteFileRet);
//
// // 4. 获取文件属性
// StatFileRequest statFileRequest = new StatFileRequest(bucketName, cosFilePath);
// String statFileRet = cosClient.statFile(statFileRequest);
// System.out.println("stat file ret:" + statFileRet);
//
// // 5. 更新文件属性
// UpdateFileRequest updateFileRequest = new UpdateFileRequest(bucketName, cosFilePath);
// updateFileRequest.setBizAttr("测试目录");
// updateFileRequest.setAuthority(FileAuthority.WPRIVATE);
// updateFileRequest.setCacheControl("no cache");
// updateFileRequest.setContentDisposition("cos_sample.txt");
// updateFileRequest.setContentLanguage("english");
// updateFileRequest.setContentType("application/json");
// updateFileRequest.setXCosMeta("x-cos-meta-xxx", "xxx");
// updateFileRequest.setXCosMeta("x-cos-meta-yyy", "yyy");
// updateFileRequest.setContentEncoding("gzip");
// String updateFileRet = cosClient.updateFile(updateFileRequest);
// System.out.println("update file ret:" + updateFileRet);
//
// // 6. 更新文件后再次获取属性
// statFileRet = cosClient.statFile(statFileRequest);
// System.out.println("stat file ret:" + statFileRet);
//
// // 6.1 move文件,从/sample_file.txt移动为./sample_file.txt.bak
// String dstFilePath = cosFilePath + ".bak";
// MoveFileRequest moveRequest = new MoveFileRequest(bucketName, cosFilePath, dstFilePath);
// String moveFileRet = cosClient.moveFile(moveRequest);
// System.out.println("first move file ret:" + moveFileRet);
// // 6.2 在从/sample_file.txt.bak移动为/sample_file.txt
// moveRequest = new MoveFileRequest(bucketName, dstFilePath, cosFilePath);
// moveFileRet = cosClient.moveFile(moveRequest);
// System.out.println("second move file ret:" + moveFileRet);
//
// // 7. 删除文件
// DelFileRequest delFileRequest = new DelFileRequest(bucketName, cosFilePath);
// String delFileRet = cosClient.delFile(delFileRequest);
// System.out.println("del file ret:" + delFileRet);*/
//
// ///////////////////////////////////////////////////////////////
// // 目录操作 //
// ///////////////////////////////////////////////////////////////
// // 1. 生成目录, 目录名为sample_folder
// String cosFolderPath = "/xxsample_folder/";
// CreateFolderRequest createFolderRequest =
// new CreateFolderRequest(bucketName, cosFolderPath);
// String createFolderRet = cosClient.createFolder(createFolderRequest);
// System.out.println("create folder ret:" + createFolderRet);
//
// // 2. 更新目录的biz_attr属性
// /*UpdateFolderRequest updateFolderRequest =
// new UpdateFolderRequest(bucketName, cosFolderPath);
// updateFolderRequest.setBizAttr("这是一个测试目录");
// String updateFolderRet = cosClient.updateFolder(updateFolderRequest);
// System.out.println("update folder ret:" + updateFolderRet);
//
// // 3. 获取目录属性
// StatFolderRequest statFolderRequest = new StatFolderRequest(bucketName, cosFolderPath);
// String statFolderRet = cosClient.statFolder(statFolderRequest);
// System.out.println("stat folder ret:" + statFolderRet);
//
// // 4. list目录, 获取目录下的成员
// ListFolderRequest listFolderRequest = new ListFolderRequest(bucketName, cosFolderPath);
// String listFolderRet = cosClient.listFolder(listFolderRequest);
// System.out.println("list folder ret:" + listFolderRet);
//
// // 5. 删除目录
// DelFolderRequest delFolderRequest = new DelFolderRequest(bucketName, cosFolderPath);
// String delFolderRet = cosClient.delFolder(delFolderRequest);
// System.out.println("del folder ret:" + delFolderRet);*/
//
// // 关闭释放资源
// cosClient.shutdown();
// System.out.println("shutdown!");
//
// }
//}
package com.qcloud.cos.demo;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.util.Date;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.AnonymousCOSCredentials;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.model.GeneratePresignedUrlRequest;
import com.qcloud.cos.model.ResponseHeaderOverrides;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.utils.DateUtils;
/**
* GeneratePresignedUrlDemo展示了生成预签名的下载链接与上传连接的使用示例.
* 用于可将生成的连接分发给移动端或者他人, 即可实现在签名有效期内上传或者下载文件.
*/
public class GeneratePresignedUrlDemo {
// 获取下载的预签名连接
public static void GenerateSimplePresignedDownloadUrl() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa.txt";
GeneratePresignedUrlRequest req =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
// 设置签名过期时间(可选), 若未进行设置则默认使用ClientConfig中的签名过期时间(5分钟)
// 这里设置签名在半个小时后过期
Date expirationDate = new Date(System.currentTimeMillis() + 30 * 60 * 1000);
req.setExpiration(expirationDate);
URL url = cosclient.generatePresignedUrl(req);
System.out.println(url.toString());
cosclient.shutdown();
}
// 获取预签名的下载链接, 并设置返回的content-type, cache-control等http头
public static void GeneratePresignedDownloadUrlWithOverrideResponseHeader() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa.txt";
GeneratePresignedUrlRequest req =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
// 设置下载时返回的http头
ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
String responseContentType = "image/x-icon";
String responseContentLanguage = "zh-CN";
String responseContentDispositon = "filename=\"abc.txt\"";
String responseCacheControl = "no-cache";
String cacheExpireStr =
DateUtils.formatRFC822Date(new Date(System.currentTimeMillis() + 24 * 3600 * 1000));
responseHeaders.setContentType(responseContentType);
responseHeaders.setContentLanguage(responseContentLanguage);
responseHeaders.setContentDisposition(responseContentDispositon);
responseHeaders.setCacheControl(responseCacheControl);
responseHeaders.setExpires(cacheExpireStr);
req.setResponseHeaders(responseHeaders);
// 设置签名过期时间(可选), 若未进行设置则默认使用ClientConfig中的签名过期时间(5分钟)
// 这里设置签名在半个小时后过期
Date expirationDate = new Date(System.currentTimeMillis() + 30 * 60 * 1000);
req.setExpiration(expirationDate);
URL url = cosclient.generatePresignedUrl(req);
System.out.println(url.toString());
cosclient.shutdown();
}
// 获取预签名的下载链接, 用于匿名bucket, 匿名bucket生成的预下载链接不包含签名
public static void GeneratePresignedDownloadUrlAnonymous() {
// 1 初始化用户身份信息, 匿名身份不用传入ak sk
COSCredentials cred = new AnonymousCOSCredentials();
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa.txt";
GeneratePresignedUrlRequest req =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
URL url = cosclient.generatePresignedUrl(req);
System.out.println(url.toString());
cosclient.shutdown();
}
// 生成预签名的上传连接
public static void GeneratePresignedUploadUrl() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa.txt";
Date expirationTime = new Date(System.currentTimeMillis() + 30 * 60 * 1000);
URL url = cosclient.generatePresignedUrl(bucketName, key, expirationTime, HttpMethodName.PUT);
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
// 写入要上传的数据
out.write("This text uploaded as object.");
out.close();
int responseCode = connection.getResponseCode();
System.out.println("Service returned response code " + responseCode);
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
cosclient.shutdown();
}
}
package com.qcloud.cos.demo;
import java.util.List;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.COSObjectSummary;
import com.qcloud.cos.model.ListObjectsRequest;
import com.qcloud.cos.model.ObjectListing;
import com.qcloud.cos.region.Region;
/**
* ListObjectsDemo展示了如何列出object
*/
public class ListObjectsDemo {
public static void listObjectsDemo() {
// 1 初始化用户身份信息(appid, secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名称, 需包含appid
String bucketName = "mybucket-1251668577";
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
// 设置bucket名称
listObjectsRequest.setBucketName(bucketName);
// prefix表示列出的object的key以prefix开始
listObjectsRequest.setPrefix("");
// 设置最大遍历出多少个对象, 一次listobject最大支持1000
listObjectsRequest.setMaxKeys(1000);
// listObjectsRequest.setDelimiter("/");
ObjectListing objectListing = null;
try {
objectListing = cosclient.listObjects(listObjectsRequest);
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
}
// common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
List<String> commonPrefixs = objectListing.getCommonPrefixes();
// object summary表示所有列出的object列表
List<COSObjectSummary> cosObjectSummaries = objectListing.getObjectSummaries();
for (COSObjectSummary cosObjectSummary : cosObjectSummaries) {
// 文件的路径key
String key = cosObjectSummary.getKey();
// 文件的etag
String etag = cosObjectSummary.getETag();
// 文件的长度
long fileSize = cosObjectSummary.getSize();
// 文件的存储类型
String storageClasses = cosObjectSummary.getStorageClass();
System.out.println("key: " + key);
}
cosclient.shutdown();
}
// 如果要获取超过maxkey数量的object或者获取所有的object, 则需要循环调用listobject, 用上一次返回的next marker作为下一次调用的marker,
// 直到返回的truncated为false
public static void listAllObjects() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
// 设置bucket名称
listObjectsRequest.setBucketName(bucketName);
// prefix表示列出的object的key以prefix开始
listObjectsRequest.setPrefix("");
// deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
listObjectsRequest.setDelimiter("");
// 设置最大遍历出多少个对象, 一次listobject最大支持1000
listObjectsRequest.setMaxKeys(1000);
ObjectListing objectListing = null;
do {
try {
objectListing = cosclient.listObjects(listObjectsRequest);
} catch (CosServiceException e) {
e.printStackTrace();
return;
} catch (CosClientException e) {
e.printStackTrace();
return;
}
// common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
List<String> commonPrefixs = objectListing.getCommonPrefixes();
// object summary表示所有列出的object列表
List<COSObjectSummary> cosObjectSummaries = objectListing.getObjectSummaries();
for (COSObjectSummary cosObjectSummary : cosObjectSummaries) {
// 文件的路径key
String key = cosObjectSummary.getKey();
// 文件的etag
String etag = cosObjectSummary.getETag();
// 文件的长度
long fileSize = cosObjectSummary.getSize();
// 文件的存储类型
String storageClasses = cosObjectSummary.getStorageClass();
}
String nextMarker = objectListing.getNextMarker();
listObjectsRequest.setMarker(nextMarker);
} while (objectListing.isTruncated());
cosclient.shutdown();
}
public static void main(String[] args) {
listAllObjects();
}
}
package com.qcloud.cos.demo;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.StorageClass;
import com.qcloud.cos.region.Region;
/**
* SimpleUpload 给出了简单上传的示例
*/
public class SimpleUploadFileDemo {
// 将本地文件上传到COS
public static void SimpleUploadFileFromLocal() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "/aaa/bbb.txt";
File localFile = new File("src/test/resources/len10M.txt");
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
// 设置存储类型, 默认是标准(Standard), 低频(standard_ia), 近线(nearline)
putObjectRequest.setStorageClass(StorageClass.Standard_IA);
try {
PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
// putobjectResult会返回文件的etag
String etag = putObjectResult.getETag();
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
}
// 关闭客户端
cosclient.shutdown();
}
// 从输入流进行读取并上传到COS
public static void SimpleUploadFileFromStream() {
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "/aaa/bbb.jpg";
File localFile = new File("src/test/resources/len10M.txt");
InputStream input = new ByteArrayInputStream(new byte[10]);
ObjectMetadata objectMetadata = new ObjectMetadata();
// 从输入流上传必须制定content length, 否则http客户端可能会缓存所有数据,存在内存OOM的情况
objectMetadata.setContentLength(10);
// 默认下载时根据cos路径key的后缀返回响应的contenttype, 上传时设置contenttype会覆盖默认值
objectMetadata.setContentType("image/jpeg");
PutObjectRequest putObjectRequest =
new PutObjectRequest(bucketName, key, input, objectMetadata);
// 设置存储类型, 默认是标准(Standard), 低频(standard_ia), 近线(nearline)
putObjectRequest.setStorageClass(StorageClass.Standard_IA);
try {
PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
// putobjectResult会返回文件的etag
String etag = putObjectResult.getETag();
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
}
// 关闭客户端
cosclient.shutdown();
}
}
package com.qcloud.cos.demo;
import java.io.File;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicSessionCredentials;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
public class TemporyTokenDemo {
// 该例子介绍使用临时秘钥来访问COS上的资源
// 临时秘钥通过云API向腾讯云权限管理系统CAM申请,java云api可以在此获取:https://github.com/QcloudApi/qcloudapi-sdk-java
public static BasicSessionCredentials getSessionCredential() {
// 实际应用中,这里通过云api请求得到临时秘钥后,构造BasicSessionCredential
BasicSessionCredentials cred =
new BasicSessionCredentials("111111111111122222",
"333333334afafafaa", "efd2f92e6b35562d387971ec7e78cfa051d058ad3");
return cred;
}
// 使用临时秘钥进行上传和下载
public static void UseTemporyTokenUploadAndDownload() {
// 使用云api秘钥,可以获取一个临时secret id,secret key和session token,
BasicSessionCredentials cred = getSessionCredential();
// 设置区域, 这里设置为北京一区
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 生成cos客户端对象
COSClient cosClient = new COSClient(cred, clientConfig);
// 上传的bucket名字
String bucketName = "rabbitliutj-1000000";
// 上传object, 建议20M以下的文件使用该接口
File localFile = new File("src/test/resources/len5M.txt");
String key = "/upload_single_demo5M.txt";
// 上传
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
ObjectMetadata objectMetadata = new ObjectMetadata();
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
System.out.println(putObjectResult.getMetadata());
// 下载
File downFile = new File("src/test/resources/len5M_down.txt");
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
ObjectMetadata downObjectMeta = cosClient.getObject(getObjectRequest, downFile);
// 关闭客户端(关闭后台线程)
cosClient.shutdown();
}
public static void main(String[] args) throws Exception {
UseTemporyTokenUploadAndDownload();
}
}
package com.qcloud.cos.event;
import com.qcloud.cos.transfer.PersistableTransfer;
public interface COSProgressListener extends ProgressListener {
/**
* Called when the information to resume an upload/download operation is
* available, The execution of the callback of this listener is managed by
* {@link COSProgressListener}. Implementation of this interface should
* never block.
* Note any exception thrown by the listener will get ignored. Should there
* be need to capture any such exception, you may consider wrapping the
* listener with
* {@link ExceptionReporter#wrap(ProgressListener)}.
*
* @param persistableTransfer
* A non null opaque token used to resume an upload or download.
*
* @see COSProgressListener
* @see ExceptionReporter
*/
public void onPersistableTransfer(final PersistableTransfer persistableTransfer);
}
package com.qcloud.cos.event;
import com.qcloud.cos.transfer.PersistableTransfer;
/**
* COS specific progress listener chain.
*/
public class COSProgressListenerChain extends ProgressListenerChain implements COSProgressListener {
/**
* Create a listener chain that directly passes all the progress events to the specified
* listeners.
*
* @param listeners only listeners of type {@link COSProgressListener} will be notified with the
* COS transfer events.
*/
public COSProgressListenerChain(ProgressListener... listeners) {
super(listeners);
}
@Override
public void onPersistableTransfer(PersistableTransfer persistableTransfer) {
for (ProgressListener listener : getListeners()) {
if (listener instanceof COSProgressListener) {
COSProgressListener cosListener = (COSProgressListener) listener;
cosListener.onPersistableTransfer(persistableTransfer);
}
}
}
}
package com.qcloud.cos.event;
import java.util.concurrent.Future;
import org.slf4j.LoggerFactory;
import com.qcloud.cos.transfer.PersistableTransfer;
/**
* Used to publish transfer events.
*/
public class COSProgressPublisher extends SDKProgressPublisher {
/**
* Used to deliver a persistable transfer to the given cos listener.
*
* @param listener only listener of type {@link COSProgressListener} will be
* notified.
*
* @return the future of a submitted task; or null if the delivery is
* synchronous with no future task involved. Note a listener should never
* block, and therefore returning null is the typical case.
*/
public static Future<?> publishTransferPersistable(
final ProgressListener listener,
final PersistableTransfer persistableTransfer) {
if (persistableTransfer == null
|| !(listener instanceof COSProgressListener))
return null;
final COSProgressListener coslistener = (COSProgressListener)listener;
return deliverEvent(coslistener, persistableTransfer);
}
private static Future<?> deliverEvent(final COSProgressListener listener,
final PersistableTransfer persistableTransfer) {
if (SYNC) { // forces all callbacks to be made synchronously
return quietlyCallListener(listener, persistableTransfer);
}
if (!ASYNC) { // forces all callbacks to be made asynchronously
if (listener instanceof DeliveryMode) {
DeliveryMode mode = (DeliveryMode) listener;
if (mode.isSyncCallSafe()) {
// Safe to call the listener directly
return quietlyCallListener(listener, persistableTransfer);
}
}
}
// Not safe to call the listener directly; so submit an async task.
// This is unfortunate as the listener should never block in the first
// place, but such task submission is necessary to remain backward
// compatible.
return setLatestFutureTask(getExecutorService().submit(new Runnable() {
@Override public void run() {
listener.onPersistableTransfer(persistableTransfer);
}
}));
}
private static Future<?> quietlyCallListener(
final COSProgressListener listener,
final PersistableTransfer persistableTransfer) {
try {
listener.onPersistableTransfer(persistableTransfer);
} catch(Throwable t) {
// That's right, we need to suppress all errors so as to be on par
// with the async mode where all failures will be ignored.
LoggerFactory.getLogger(COSProgressPublisher.class)
.debug("Failure from the event listener", t);
}
return null;
}
}
package com.qcloud.cos.event;
/**
* Used to indicate whether it is safe to deliver progress events to the
* listener synchronously. In general, a progress listener should never block,
* which is a necessary condition for the safety for synchronous delivery.
*
* @see SyncProgressListener
*/
public interface DeliveryMode {
/**
* Returns true if it is safe to make a synchronous callback to the
* implementing listener without the risk of incurring undue latency; false
* otherwise.
*/
public boolean isSyncCallSafe();
/**
* Provides convenient method to check if a listener is safe to be invoked
* synchronously.
*/
public static class Check {
public static boolean isSyncCallSafe(ProgressListener listener) {
if (listener instanceof DeliveryMode) {
DeliveryMode mode = (DeliveryMode) listener;
return mode.isSyncCallSafe();
}
return listener == null;
}
}
}
package com.qcloud.cos.event;
import com.qcloud.cos.transfer.TransferProgress;
/**
* TransferProgressUpdatingListener for multiple-file transfer. In addition
* to updating the TransferProgress, it also sends out ByteTrasnferred
* events to a ProgressListenerChain.
*/
public final class MultipleFileTransferProgressUpdatingListener extends
TransferProgressUpdatingListener implements DeliveryMode {
private final ProgressListenerChain progressListenerChain;
public MultipleFileTransferProgressUpdatingListener(
TransferProgress transferProgress,
ProgressListenerChain progressListenerChain) {
super(transferProgress);
this.progressListenerChain = progressListenerChain;
}
@Override
public void progressChanged(ProgressEvent progressEvent) {
super.progressChanged(progressEvent);
progressListenerChain.progressChanged(progressEvent);
}
@Override
public boolean isSyncCallSafe() {
return progressListenerChain == null
|| progressListenerChain.isSyncCallSafe();
}
}
\ No newline at end of file
package com.qcloud.cos.event;
import java.util.concurrent.CountDownLatch;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.transfer.MultipleFileTransfer;
import com.qcloud.cos.transfer.Transfer;
import com.qcloud.cos.transfer.Transfer.TransferState;
public final class MultipleFileTransferStateChangeListener implements TransferStateChangeListener {
private final CountDownLatch latch;
private final MultipleFileTransfer<?> multipleFileTransfer;
public MultipleFileTransferStateChangeListener(CountDownLatch latch,
MultipleFileTransfer<?> multipleFileTransfer) {
this.latch = latch;
this.multipleFileTransfer = multipleFileTransfer;
}
@Override
public void transferStateChanged(Transfer upload, TransferState state) {
// There's a race here: we can't start monitoring the state of
// individual transfers until we have added all the transfers to the
// list, or we may incorrectly report completion.
try {
latch.await();
} catch ( InterruptedException e ) {
throw new CosClientException("Couldn't wait for all downloads to be queued");
}
synchronized (multipleFileTransfer) {
if ( multipleFileTransfer.getState() == state || multipleFileTransfer.isDone() )
return;
/*
* If we're not already in a terminal state, allow a transition
* to a non-waiting state. Mark completed if this download is
* completed and the monitor says all of the rest are as well.
*/
if ( state == TransferState.InProgress ) {
multipleFileTransfer.setState(state);
} else if ( multipleFileTransfer.getMonitor().isDone() ) {
multipleFileTransfer.collateFinalState();
} else {
multipleFileTransfer.setState(TransferState.InProgress);
}
}
}
}
\ No newline at end of file
package com.qcloud.cos.event;
import java.util.EnumMap;
import java.util.Map;
/**
* A progress event. Typically this is used to notify a chunk of bytes has been
* transferred. Also used to notify other types of progress events such as a
* transfer starting, or failing.
*/
public class ProgressEvent {
/** The number of bytes associated with the progress event. */
private final long bytes;
private final ProgressEventType eventType;
/**
* Creates a BYTE_TRANSFER_EVENT with the specified bytesTransferred data.
*/
@Deprecated
public ProgressEvent(long bytes) {
this(ProgressEventType.BYTE_TRANSFER_EVENT, bytes);
}
/**
* Creates a ProgressEvent object with the specified event type.
*
* @param eventType
* Type of the progress event. This parameter must not be null.
*/
public ProgressEvent(ProgressEventType eventType) {
this(eventType, 0);
}
/**
* Creates a ProgressEvent object.
*
* @param eventType
* Type of the progress event. This parameter must not be null.
* @param bytes
* Number of bytes involved.
*/
public ProgressEvent(ProgressEventType eventType, long bytes) {
if (eventType == null)
throw new IllegalArgumentException("eventType must not be null.");
if (bytes < 0)
throw new IllegalArgumentException("bytes reported must be non-negative");
this.eventType = eventType;
this.bytes = bytes;
}
/**
* Returns the number of bytes associated with the event. The number of
* bytes are not necessarily the same as the number of bytes transferred,
* and it's meaning depends on the specific event type. For example, the
* bytes of a {@link ProgressEventType#REQUEST_CONTENT_LENGTH_EVENT} refers
* to the expected number of bytes to be sent to COS, not the actual number
* of bytes that have been transferred.
*/
public long getBytes() {
return bytes;
}
/**
* Convenient method to returns the number of bytes transferred in this
* event, or the number of bytes reset (or discarded) if negative. In
* particular, bytes of a content-length event is excluded.
*/
public long getBytesTransferred() {
switch(eventType) {
case REQUEST_BYTE_TRANSFER_EVENT:
case RESPONSE_BYTE_TRANSFER_EVENT:
return bytes;
case HTTP_RESPONSE_CONTENT_RESET_EVENT:
case HTTP_REQUEST_CONTENT_RESET_EVENT:
case RESPONSE_BYTE_DISCARD_EVENT:
return 0 - bytes;
default:
return 0;
}
}
/**
* Returns the unique event code identifying the type of event this object
* represents.
*
* @return The unique event code that identifies what type of specific type
* of event this object represents.
*
* @deprecated Use {@link #getEventType()} instead.
*/
@Deprecated
public int getEventCode() {
Integer legacyCode = legacyEventCodes.get(eventType);
// Returns -1 if the event type does not have a legacy event code
return legacyCode == null ? -1 : legacyCode;
}
/**
* Returns the type of event this object represents. This method never
* returns null.
*
* @return The type of event this object represents.
*/
public ProgressEventType getEventType() {
return eventType;
}
// Deprecated integer event codes
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_PREPARING_EVENT} */
@Deprecated public static final int PREPARING_EVENT_CODE = 1;
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_STARTED_EVENT} */
@Deprecated public static final int STARTED_EVENT_CODE = 2;
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_COMPLETED_EVENT} */
@Deprecated public static final int COMPLETED_EVENT_CODE = 4;
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_FAILED_EVENT} */
@Deprecated public static final int FAILED_EVENT_CODE = 8;
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_CANCELED_EVENT} */
@Deprecated public static final int CANCELED_EVENT_CODE = 16;
/** @deprecated Replaced by {@link ProgressEventType#HTTP_REQUEST_CONTENT_RESET_EVENT} */
@Deprecated public static final int RESET_EVENT_CODE = 32;
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_PART_STARTED_EVENT} */
@Deprecated public static final int PART_STARTED_EVENT_CODE = 1024;
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_PART_COMPLETED_EVENT} */
@Deprecated public static final int PART_COMPLETED_EVENT_CODE = 2048;
/** @deprecated Replaced by {@link ProgressEventType#TRANSFER_PART_FAILED_EVENT} */
@Deprecated public static final int PART_FAILED_EVENT_CODE = 4096;
// Mapping from event types to the legacy event codes
private static final Map<ProgressEventType, Integer> legacyEventCodes =
new EnumMap<ProgressEventType, Integer>(ProgressEventType.class);
static {
legacyEventCodes.put(ProgressEventType.BYTE_TRANSFER_EVENT, 0);
legacyEventCodes.put(ProgressEventType.TRANSFER_PREPARING_EVENT, PREPARING_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.TRANSFER_STARTED_EVENT, STARTED_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.TRANSFER_COMPLETED_EVENT, COMPLETED_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.TRANSFER_FAILED_EVENT, FAILED_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.TRANSFER_CANCELED_EVENT, CANCELED_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.HTTP_REQUEST_CONTENT_RESET_EVENT, RESET_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.HTTP_RESPONSE_CONTENT_RESET_EVENT,RESET_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.TRANSFER_PART_STARTED_EVENT, PART_STARTED_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.TRANSFER_PART_COMPLETED_EVENT, PART_COMPLETED_EVENT_CODE);
legacyEventCodes.put(ProgressEventType.TRANSFER_PART_FAILED_EVENT, PART_FAILED_EVENT_CODE);
}
@Override
public String toString() {
return eventType + ", bytes: " + bytes;
}
}
package com.qcloud.cos.event;
/**
* An interface that filters the incoming events before passing
* them into the registered listeners.
*/
public interface ProgressEventFilter {
/**
* Returns the filtered event object that will be actually passed into
* the listeners. Returns null if the event should be completely blocked.
*/
public ProgressEvent filter(ProgressEvent progressEvent);
}
\ No newline at end of file
package com.qcloud.cos.event;
/**
* An enumeration that denotes various types of progress event.
*/
public enum ProgressEventType {
//////////////////////////////////////////////////////////////////////////
// Request Cycle Event:
// related to the execution of a single http request-response to COS
//////////////////////////////////////////////////////////////////////////
/**
* A general byte transfer event that happens during sending a request or
* reading a response.
*/
@Deprecated
BYTE_TRANSFER_EVENT,
/**
* Event of the content length to be sent in a request.
*/
REQUEST_CONTENT_LENGTH_EVENT,
/**
* Event of the content length received in a response.
*/
RESPONSE_CONTENT_LENGTH_EVENT,
/**
* Used to indicate the number of bytes to be sent to COS.
*/
REQUEST_BYTE_TRANSFER_EVENT,
/**
* Used to indicate the number of bytes received from COS.
*/
RESPONSE_BYTE_TRANSFER_EVENT,
/**
* Used to indicate the number of bytes discarded after being received from COS.
*/
RESPONSE_BYTE_DISCARD_EVENT,
/* Generic request progress events */
/**
* Event indicating that the client has started sending the COS API request.
* This type of event is guaranteed to be only fired once during a
* request-response cycle, even when the request is retried.
*/
CLIENT_REQUEST_STARTED_EVENT,
/**
* Event indicating that the client has started sending the HTTP request.
* The request progress listener will be notified of multiple instances of
* this type of event if the request gets retried.
*/
HTTP_REQUEST_STARTED_EVENT,
/**
* Event indicating that the client has finished sending the HTTP request.
* The request progress listener will be notified of multiple instances of
* this type of event if the request gets retried.
*/
HTTP_REQUEST_COMPLETED_EVENT,
/**
* Event indicating that the HTTP request content is reset, which may or may not
* be caused by the retry of the request.
*/
HTTP_REQUEST_CONTENT_RESET_EVENT,
/**
* Event indicating that a failed request is detected as retryable and is
* ready for the next retry.
*/
CLIENT_REQUEST_RETRY_EVENT,
/**
* Event indicating that the client has started reading the HTTP response.
* The request progress listener will be notified of this event only if the
* client receives a successful service response (i.e. 2XX status code).
*/
HTTP_RESPONSE_STARTED_EVENT,
/**
* Event indicating that the client has finished reading the HTTP response.
* The request progress listener will be notified of this event only if the
* client receives a successful service response (i.e. 2XX status code).
*/
HTTP_RESPONSE_COMPLETED_EVENT,
/**
* Event indicating that the HTTP response content is reset.
*/
HTTP_RESPONSE_CONTENT_RESET_EVENT,
/**
* Event indicating that the client has received a successful service
* response and has finished parsing the response data.
*/
CLIENT_REQUEST_SUCCESS_EVENT,
/**
* Event indicating that a client request has failed (after retries have
* been conducted).
*/
CLIENT_REQUEST_FAILED_EVENT,
//////////////////////////////////////////////////////////////////////////
// Transfer Event:
// Progress events that are used by COS client */
//////////////////////////////////////////////////////////////////////////
TRANSFER_PREPARING_EVENT,
TRANSFER_STARTED_EVENT,
TRANSFER_COMPLETED_EVENT,
TRANSFER_FAILED_EVENT,
TRANSFER_CANCELED_EVENT,
TRANSFER_PART_STARTED_EVENT,
TRANSFER_PART_COMPLETED_EVENT,
TRANSFER_PART_FAILED_EVENT;
/**
* Returns true if this event type is a transfer event, which may involve
* multiple request cycle events.
*
* @see #isRequestCycleEvent()
*/
public boolean isTransferEvent() {
switch (this) {
case TRANSFER_CANCELED_EVENT:
case TRANSFER_COMPLETED_EVENT:
case TRANSFER_FAILED_EVENT:
case TRANSFER_PART_COMPLETED_EVENT:
case TRANSFER_PART_FAILED_EVENT:
case TRANSFER_PART_STARTED_EVENT:
case TRANSFER_PREPARING_EVENT:
case TRANSFER_STARTED_EVENT:
return true;
default:
return false;
}
}
/**
* Returns true if this event type is related to the execution of a
* single http request-response to COS; false otherwise.
*/
public boolean isRequestCycleEvent() {
return !isTransferEvent();
}
/**
* Returns true if this even type is associated with some number of bytes;
* false otherwise.
*/
public boolean isByteCountEvent() {
switch (this) {
case BYTE_TRANSFER_EVENT:
case HTTP_REQUEST_CONTENT_RESET_EVENT:
case HTTP_RESPONSE_CONTENT_RESET_EVENT:
case REQUEST_BYTE_TRANSFER_EVENT:
case RESPONSE_BYTE_TRANSFER_EVENT:
case RESPONSE_BYTE_DISCARD_EVENT:
case REQUEST_CONTENT_LENGTH_EVENT:
case RESPONSE_CONTENT_LENGTH_EVENT:
return true;
default:
return false;
}
}
}
\ No newline at end of file
package com.qcloud.cos.event;
import java.io.IOException;
import java.io.InputStream;
import com.qcloud.cos.internal.CosServiceRequest;
import com.qcloud.cos.internal.SdkFilterInputStream;
public class ProgressInputStream extends SdkFilterInputStream {
/**
* @param is the request content input stream
* @param progressListener Optional progress listener
* @return If the progress listener is non null returns a new input stream decorated with
* progress reporting functionality. If progress listener is null it returns the same input
* stream.
*/
public static InputStream inputStreamForRequest(InputStream is, ProgressListener progressListener) {
return progressListener == null
? is
: new RequestProgressInputStream(is, progressListener);
}
/**
* Returns an input stream for response progress tracking purposes. If
* request/response progress tracking is not enabled, this method simply
* return the given input stream as is.
*
* @param is the response content input stream
*/
public static InputStream inputStreamForResponse(InputStream is, CosServiceRequest req) {
return req == null
? is
: new ResponseProgressInputStream(is, req.getGeneralProgressListener());
}
/**
* Returns an input stream for response progress tracking purposes. If request/response progress tracking is not enabled, this
* method simply return the given input stream as is.
*
* @param is the response content input stream
* @param progressListener Optional progress listener
* @return If the progress listener is non null returns a new input stream decorated with progress reporting functionality. If
* progress listener is null it returns the same input stream.
*/
public static InputStream inputStreamForResponse(InputStream is, ProgressListener progressListener) {
return progressListener == null
? is
: new ResponseProgressInputStream(is, progressListener);
}
/** The threshold of bytes between notifications. */
private static final int DEFAULT_NOTIFICATION_THRESHOLD = 8 * 1024;
private final ProgressListener listener;
private final int notifyThresHold;
/** The number of bytes read that the listener hasn't been notified about yet. */
private int unnotifiedByteCount;
private boolean hasBeenRead;
private boolean doneEOF;
private long notifiedByteCount;
public ProgressInputStream(InputStream is, ProgressListener listener) {
this(is, listener, DEFAULT_NOTIFICATION_THRESHOLD);
}
public ProgressInputStream(InputStream is, ProgressListener listener, int notifyThresHold) {
super(is);
if (is == null || listener == null)
throw new IllegalArgumentException();
this.notifyThresHold = notifyThresHold;
this.listener = listener;
}
/**
* The read method is called for the very first time.
* Defaults to do nothing.
*/
protected void onFirstRead() {}
/**
* An end-of-file event is to be notified.
* Defaults to do nothing.
*/
protected void onEOF() {}
/**
* Defaults to behave the same as {@link #onEOF()}.
*/
protected void onClose() {
eof();
}
/**
* A reset event is to be notified. Default to do nothing.
*/
protected void onReset() {}
/**
* Upon notification of the number of bytes transferred since last
* notification. Default to do nothing.
*/
protected void onNotifyBytesRead() {}
/**
* Upon reading the given number of bytes.
* The default behavior is to accumulate the byte count and only fire off
* a notification by invoking {@link #onNotifyBytesRead()} if the count
* has exceeded the threshold.
*/
private void onBytesRead(int bytesRead) {
unnotifiedByteCount += bytesRead;
if (unnotifiedByteCount >= notifyThresHold) {
onNotifyBytesRead();
notifiedByteCount += unnotifiedByteCount;
unnotifiedByteCount = 0;
}
}
@Override
public int read() throws IOException {
if (!hasBeenRead) {
onFirstRead();
hasBeenRead = true;
}
int ch = super.read();
if (ch == -1)
eof();
else
onBytesRead(1);
return ch;
}
@Override
public void reset() throws IOException {
super.reset();
onReset();
unnotifiedByteCount = 0;
notifiedByteCount = 0;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (!hasBeenRead) {
onFirstRead();
hasBeenRead = true;
}
int bytesRead = super.read(b, off, len);
if (bytesRead == -1)
eof();
else
onBytesRead(bytesRead);
return bytesRead;
}
private void eof() {
if (doneEOF)
return;
onEOF();
unnotifiedByteCount = 0;
doneEOF = true;
}
public final InputStream getWrappedInputStream() {
return in;
}
protected final int getUnnotifiedByteCount() {
return unnotifiedByteCount;
}
protected final long getNotifiedByteCount() {
return notifiedByteCount;
}
@Override
public void close() throws IOException {
onClose(); // report any left over bytes not yet reported
super.close();
}
public final ProgressListener getListener() {
return listener;
}
}
package com.qcloud.cos.event;
import com.qcloud.cos.exception.CosClientException;
public interface ProgressListener {
public static final ProgressListener NOOP = new ProgressListener() {
@Override public void progressChanged(ProgressEvent progressEvent) {}
};
/**
* Called when progress has changed, such as additional bytes transferred,
* transfer failed, etc. The execution of the callback of this listener is managed
* by {@link SDKProgressPublisher}. Implementation of this interface
* should never block.
* <p>
* If the implementation follows the best practice and doesn't block, it
* should then extends from {@link SyncProgressListener}.
* <p>
* Note any exception thrown by the listener will get ignored.
* Should there be need to capture any such exception, you may consider
* wrapping the listener with {@link ExceptionReporter#wrap(ProgressListener)}.
*
* @param progressEvent
* The event describing the progress change.
*
* @see SDKProgressPublisher
* @see ExceptionReporter
*/
public void progressChanged(ProgressEvent progressEvent);
/**
* A utility class for capturing and reporting the first exception thrown by
* a given progress listener. Note once an exception is thrown by the
* underlying listener, all subsequent events will no longer be notified to
* the listener.
*/
public static class ExceptionReporter implements ProgressListener, DeliveryMode {
private final ProgressListener listener;
private final boolean syncCallSafe;
private volatile Throwable cause;
public ExceptionReporter(ProgressListener listener) {
if (listener == null)
throw new IllegalArgumentException();
this.listener = listener;
if (listener instanceof DeliveryMode) {
DeliveryMode cs = (DeliveryMode) listener;
syncCallSafe = cs.isSyncCallSafe();
} else
syncCallSafe = false;
}
/**
* Delivers the progress event to the underlying listener but only if
* there has not been an exception previously thrown by the listener.
* <p>
* {@inheritDoc}
*/
@Override public void progressChanged(ProgressEvent progressEvent) {
if (cause != null)
return;
try {
this.listener.progressChanged(progressEvent);
} catch(Throwable t) {
cause = t;
}
}
/**
* Throws the underlying exception, if any, as an
* {@link CosClientException}; or do nothing otherwise.
*/
public void throwExceptionIfAny() {
if (cause != null)
throw new CosClientException(cause);
}
/**
* Returns the underlying exception, if any; or null otherwise.
*/
public Throwable getCause() {
return cause;
}
/**
* Returns a wrapper for the given listener to capture the first
* exception thrown.
*/
public static ExceptionReporter wrap(ProgressListener listener) {
return new ExceptionReporter(listener);
}
@Override public boolean isSyncCallSafe() { return syncCallSafe; }
}
}
package com.qcloud.cos.event;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* This class wraps a ProgressListener object, and manages all its callback
* execution. Callbacks are executed sequentially in a separate single thread.
*/
public class ProgressListenerCallbackExecutor {
/** The wrapped ProgressListener **/
private final ProgressListener listener;
/** A single thread pool for executing all ProgressListener callbacks. **/
private static ExecutorService executor;
public ProgressListenerCallbackExecutor(ProgressListener listener) {
this.listener = listener;
}
public void progressChanged(final ProgressEvent progressEvent) {
if (listener == null) return;
synchronized (ProgressListenerCallbackExecutor.class) {
if (executor == null) {
executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("java-sdk-progress-listener-callback-thread");
t.setDaemon(true);
return t;
}
});
}
executor.submit(new Runnable() {
@Override
public void run() {
listener.progressChanged(progressEvent);
}
});
}
}
/**
* Returns a new ProgressListenerCallbackExecutor instance that wraps the
* specified ProgressListener if it is not null, otherwise directly returns
* null.
*/
public static ProgressListenerCallbackExecutor wrapListener(ProgressListener listener) {
return listener == null ?
null : new ProgressListenerCallbackExecutor(listener);
}
}
package com.qcloud.cos.event;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of ProgressListener interface that delegates
* progressChanged callback to multiple listeners. It also takes
* an optional ProgressEventFilter to filter incoming events before
* passing them to the listeners.
*/
public class ProgressListenerChain implements ProgressListener, DeliveryMode {
private static final Logger log = LoggerFactory.getLogger(ProgressListenerChain.class);
private final List<ProgressListener> listeners = new CopyOnWriteArrayList<ProgressListener>();
private final ProgressEventFilter progressEventFilter;
/**
* True if synchronous callback to every listener in this chain is safe with
* no risk of incurring undue latency.
*
* @see SDKProgressPublisher
*/
private volatile boolean syncCallSafe = true;
/**
* Create a listener chain that directly passes all the progress events to
* the specified listeners.
*/
public ProgressListenerChain(ProgressListener... listeners) {
this(null, listeners);
}
/**
* Create a listener chain with a ProgressEventFilter.
*/
public ProgressListenerChain(ProgressEventFilter progressEventFilter, ProgressListener... listeners) {
if (listeners == null) {
throw new IllegalArgumentException(
"Progress Listeners cannot be null.");
}
for (ProgressListener listener : listeners)
addProgressListener(listener);
this.progressEventFilter = progressEventFilter;
}
public synchronized void addProgressListener(ProgressListener listener) {
if (listener == null)
return;
if (syncCallSafe)
syncCallSafe = Check.isSyncCallSafe(listener);
this.listeners.add(listener);
}
public synchronized void removeProgressListener(ProgressListener listener) {
if (listener == null) return;
this.listeners.remove(listener);
}
/**
* Returns the listeners associated with this listener chain.
*/
protected List<ProgressListener> getListeners() {
return listeners;
}
public void progressChanged(final ProgressEvent progressEvent) {
ProgressEvent filteredEvent = progressEvent;
if (progressEventFilter != null) {
filteredEvent = progressEventFilter.filter(progressEvent);
if (filteredEvent == null) return;
}
for ( ProgressListener listener : listeners ) {
try {
listener.progressChanged(filteredEvent);
} catch ( RuntimeException e ) {
log.warn("Couldn't update progress listener", e);
}
}
}
@Override public boolean isSyncCallSafe() { return syncCallSafe; }
}
package com.qcloud.cos.event;
import java.io.InputStream;
import static com.qcloud.cos.event.SDKProgressPublisher.publishRequestBytesTransferred;
import static com.qcloud.cos.event.SDKProgressPublisher.publishRequestReset;
/**
* Used for request input stream progress tracking purposes.
*/
class RequestProgressInputStream extends ProgressInputStream {
RequestProgressInputStream(InputStream is, ProgressListener listener) {
super(is, listener);
}
@Override
protected void onReset() {
publishRequestReset(getListener(), getNotifiedByteCount());
}
@Override
protected void onEOF() {
onNotifyBytesRead();
}
@Override
protected void onNotifyBytesRead() {
publishRequestBytesTransferred(getListener(), getUnnotifiedByteCount());
}
}
\ No newline at end of file
package com.qcloud.cos.event;
import static com.qcloud.cos.event.SDKProgressPublisher.publishResponseBytesTransferred;
import static com.qcloud.cos.event.SDKProgressPublisher.publishResponseReset;
import java.io.InputStream;
/**
* Used for response input stream progress tracking purposes.
*/
class ResponseProgressInputStream extends ProgressInputStream {
ResponseProgressInputStream(InputStream is, ProgressListener listener) {
super(is, listener);
}
@Override
protected void onReset() {
publishResponseReset(getListener(), getNotifiedByteCount());
}
@Override
protected void onEOF() {
onNotifyBytesRead();
}
@Override
protected void onNotifyBytesRead() {
publishResponseBytesTransferred(getListener(), getUnnotifiedByteCount());
}
}
\ No newline at end of file
package com.qcloud.cos.event;
/**
* Abstract adapter class for a progress listener that is delivered with
* progress event synchronously.
*/
public abstract class SyncProgressListener
implements ProgressListener, DeliveryMode {
/**
* Always returns true.
*/
@Override public boolean isSyncCallSafe() { return true; }
}
package com.qcloud.cos.event;
public class TransferCompletionFilter implements ProgressEventFilter {
@Override
public ProgressEvent filter(ProgressEvent progressEvent) {
// Block COMPLETE events from the low-level GetObject operation,
// but we still want to keep the BytesTransferred
return progressEvent.getEventType() == ProgressEventType.TRANSFER_COMPLETED_EVENT
? null // discard this event
: progressEvent
;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment