Java tutorial
/* * Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package com.baidubce; import com.baidubce.auth.BceV1Signer; import com.baidubce.http.BceHttpClient; import com.baidubce.http.Headers; import com.baidubce.http.handler.HttpResponseHandler; import com.baidubce.internal.InternalRequest; import com.baidubce.model.AbstractBceResponse; import com.baidubce.util.DateUtils; import org.apache.http.annotation.ThreadSafe; import java.net.URI; import java.net.URISyntaxException; import java.util.Date; /** * Abstract base class for BCE service clients. * * <p> * Responsible for basic client capabilities that are the same across all BCE SDK Java clients * (ex: setting the client endpoint). * * <p> * Subclass names should be in the form of "com.baidubce.services.xxx.XxxClient", while "xxx" is the service ID and * "Xxx" is the capitalized service ID. */ @ThreadSafe public abstract class AbstractBceClient { /** * The default service domain for BCE. */ public static final String DEFAULT_SERVICE_DOMAIN = "baidubce.com"; /** * The common URL prefix for all BCE service APIs. */ public static final String URL_PREFIX = "v1"; /** * The default string encoding for all BCE service APIs. */ public static final String DEFAULT_ENCODING = "UTF-8"; /** * The default http request content type for all BCE service APIs. */ public static final String DEFAULT_CONTENT_TYPE = "application/json; charset=utf-8"; /** * The target service ID. */ private String serviceId; /** * The endpoint URI for the service. */ private URI endpoint; /** * Responsible for sending HTTP requests to services. */ private BceHttpClient client; /** * The client configuration for this client. */ protected BceClientConfiguration config; /** * A list of handlers for processing HTTP responses from services. * * @see com.baidubce.http.BceHttpClient#execute(InternalRequest, Class, HttpResponseHandler[]) */ private HttpResponseHandler[] responseHandlers; /** * Constructs a new AbstractBceClient with the specified client configuration and handlers. * * <p> * The constructor will extract serviceId from the class name automatically. * And if there is no endpoint specified in the client configuration, the constructor will create a default one. * * @param config the client configuration. The constructor makes a copy of this parameter so that it is * safe to change the configuration after then. * @param responseHandlers a list of handlers for processing HTTP responses from services. See * {@link com.baidubce.http.BceHttpClient#execute(InternalRequest, Class, HttpResponseHandler[])} * @param isHttpAsyncPutEnabled whether or not PUT method use Async manner. * @throws IllegalStateException if the class name does not follow the naming convention for BCE clients. * @throws IllegalArgumentException if the endpoint specified in the client configuration is not a valid URI. */ public AbstractBceClient(BceClientConfiguration config, HttpResponseHandler[] responseHandlers, boolean isHttpAsyncPutEnabled) { this.serviceId = this.computeServiceId(); this.config = config; this.endpoint = this.computeEndpoint(); this.client = new BceHttpClient(config, new BceV1Signer(), isHttpAsyncPutEnabled); this.responseHandlers = responseHandlers; } /** * constructor with isHttpAsyncPutEnabled default value : false */ public AbstractBceClient(BceClientConfiguration config, HttpResponseHandler[] responseHandlers) { this(config, responseHandlers, false); } /** * Returns true if the target service supports regions. * * <p> * The result will impact the construction of default service endpoint. * * @return true if the target service supports regions. */ public boolean isRegionSupported() { return true; } /** * Returns the service endpoint to which this client will send requests. * * @return the service endpoint to which this client will send requests. */ public URI getEndpoint() { return this.endpoint; } /** * Returns the target service ID. * * @return the target service ID. */ public String getServiceId() { return this.serviceId; } public BceHttpClient getClient() { return client; } public void setClient(BceHttpClient client) { this.client = client; } /** * Shuts down the client and releases all underlying resources. * * <p> * Invoking this method is NOT a must. Once it is called, no subsequent requests should be made. */ public void shutdown() { this.client.shutdown(); } /** * Subclasses should invoke this method for sending request to the target service. * * <p> * This method will add "Content-Type" and "Date" to headers with default values if not present. * * @param request the request to build up the HTTP request. * @param responseClass the response class. * @return the final response object. */ protected <T extends AbstractBceResponse> T invokeHttpClient(InternalRequest request, Class<T> responseClass) { if (!request.getHeaders().containsKey(Headers.CONTENT_TYPE)) { request.addHeader(Headers.CONTENT_TYPE, DEFAULT_CONTENT_TYPE); } if (!request.getHeaders().containsKey(Headers.DATE)) { request.addHeader(Headers.DATE, DateUtils.formatRfc822Date(new Date())); } return this.client.execute(request, responseClass, this.responseHandlers); } /** * Returns the service ID based on the actual class name. * * <p> * The class name should be in the form of "com.baidubce.services.xxx.XxxClient", * while "xxx" is the service ID and * "Xxx" is the capitalized service ID. * * @return the computed service ID. * @throws IllegalStateException if the class name does not follow the naming convention for BCE clients. */ private String computeServiceId() { String packageName = this.getClass().getPackage().getName(); String prefix = AbstractBceClient.class.getPackage().getName() + ".services."; if (!packageName.startsWith(prefix)) { throw new IllegalStateException("Unrecognized prefix for the client package : " + packageName + ", " + "'" + prefix + "' expected"); } String serviceId = packageName.substring(prefix.length()); if (serviceId.indexOf('.') != -1) { throw new IllegalStateException("The client class should be put in package like " + prefix + "XXX"); } String className = this.getClass().getName(); String expectedClassName = packageName + '.' + Character.toUpperCase(serviceId.charAt(0)) + serviceId.substring(1) + "Client"; /** * Comment out this verification for media services, since media service is a suit of * services, the media package contains multiple Client classes. * */ // if (!className.equals(expectedClassName)) { // throw new IllegalStateException("Invalid class name " // + className + ", " + expectedClassName + " expected"); // } return serviceId; } /** * Returns the default target service endpoint. * * <p> * The endpoint will be in the form of "http(s)://<Service ID>[.<Region>].baidubce.com". * * @return the computed service endpoint * @throws IllegalArgumentException if the endpoint specified in the client configuration is not a valid URI. */ private URI computeEndpoint() { String endpoint = this.config.getEndpoint(); try { if (endpoint == null) { if (this.isRegionSupported()) { endpoint = String.format("%s://%s.%s.%s", this.config.getProtocol(), this.serviceId, this.config.getRegion(), AbstractBceClient.DEFAULT_SERVICE_DOMAIN); } else { endpoint = String.format("%s://%s.%s", this.config.getProtocol(), this.serviceId, AbstractBceClient.DEFAULT_SERVICE_DOMAIN); } } return new URI(endpoint); } catch (URISyntaxException e) { // only if the endpoint specified in the client configuration is not a valid URI, which is not expected. throw new IllegalArgumentException("Invalid endpoint." + endpoint, e); } } }