/*
* -------- -------- -------- GENERATED by Swagger -------- -------- --------
*/
package {{invokerPackage}};
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import {{invokerPackage}}.auth.ApiKeyAuth;
import {{invokerPackage}}.auth.HttpBasicAuth;
//import com.perforce.hwsclient.models.HWSStatus;
//import com.perforce.hwsclient.models.LoginResponse;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import retrofit.ErrorHandler;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.OkClient;
import retrofit.converter.ConversionException;
import retrofit.converter.Converter;
import retrofit.converter.GsonConverter;
import retrofit.mime.TypedByteArray;
import retrofit.mime.TypedInput;
import retrofit.mime.TypedOutput;
/**
* The Java client which fronts the HelixWebServices REST api.
* Note that this is generated from a mustache template and
* should not be edited directly.
*/
public class ApiClient {
/** Map of authorized accessors. */
private Map<String, Interceptor> apiAuthorizations;
/** Http request processor. */
private OkHttpClient okClient;
/** Rest adapter factory. */
private RestAdapter.Builder adapterBuilder;
/** Static /api path for requests. */
private static final String API_PATH = "/api";
/** Constant current version. */
private static final String SUPPORTED_VERSION = "v16.1";
/** Top level path for requests. */
private String basePath;
/**
* Apply configuration header overrides to our requests.
* <p>
* This method will provide the typical prefix to each configuration option,
* so keys in this map should just be the configuration value name. For
* example, <code>P4PORT</code>.
*
* @param overrides
* A map of configuration option to configuration value.
*/
public void addOverrides(final Map<String, String> overrides) {
if (overrides != null && !overrides.isEmpty()) {
adapterBuilder.setRequestInterceptor(request -> {
overrides.entrySet().forEach(e -> {
request.addHeader(
"X-Perforce-Helix-Web-Services-" + e.getKey(),
e.getValue());
});
});
}
}
/**
* The base URL to your HWS instance.
*
* @return The root to your HWS server, e.g.,
* https://perforce.mycompany.com/hws
*/
public String getBasePath() {
return basePath;
}
/**
* Change the base URL to the HWS instance.
*
* Changes will not be reflected until createDefaultAdapter is called again.
*
* @param basePath
* The HWS root URL
*/
public void setBasePath(final String basePath) {
this.basePath = basePath;
}
/**
* A special construction option that allows your client to trust all
* certificates.
*
* By default, all HWS instances start with a self-signed certificate. You
* may need to construct using this variation to validate your code is
* working in a non-production system.
*
* @param trustAllSsl
* When true, we do not validate SSL.
* @param basePath
* The HWS root URL
*/
public ApiClient(final boolean trustAllSsl, final String basePath) {
this.basePath = basePath;
apiAuthorizations = new LinkedHashMap<>();
createDefaultAdapter(trustAllSsl);
}
/**
* Construct an ApiClient with the indicated basePath.
*
* If you are testing out a new installation, this will likely not work due
* to the use of a self-signed certificate on the server.
*
* @param basePath
* The HWS root URL
*/
public ApiClient(final String basePath) {
this(false, basePath);
}
/**
* Construct an ApiClient, establishing a login session with the "project"
* login server.
*
* This will generate an ApiClient instance, and, establish the security
* header by calling the <code>POST /projects/v1/login</code> method.
*
* @param basePath
* The HWS root URL
* @param username
* The Perforce user to connect as
* @param password
* The Perforce password to authenticate with (discarded after
* ticket is acquired)
* @return The ApiClient handle ready to make authenticated requests.
*/
// public static ApiClient createWithTicket(
// final String basePath, final String username,
// final String password) {
// return createWithTicket(false, basePath, username, password);
// }
/**
* Construct an ApiClient, establishing a login session with the "project"
* login server.
*
* This will generate an ApiClient instance, and, establish the security
* header by calling the <code>POST /projects/v1/login</code> method.
*
* @param trustAllSsl
* When true, we do not validate SSL.
* @param basePath
* The HWS root URL
* @param username
* The Perforce user to connect as
* @param password
* The Perforce password to authenticate with (discarded after
* ticket is acquired)
* @return The ApiClient handle ready to make authenticated requests.
*/
// public static ApiClient createWithTicket(
// final boolean trustAllSsl,
// final String basePath, final String username,
// final String password) {
// ApiClient apiClient = new ApiClient(trustAllSsl, basePath);
// apiClient.setCredentials(username, password);
// DefaultApi api = apiClient.createDefaultService();
// LoginResponse loginResponse = api.login();
// apiClient.setApiKey(loginResponse.getTicket());
// return apiClient;
// }
/**
* Checks status of the API against the currently configured server.
*
* @return true if the server is not currently reporting any problems.
*/
// public boolean isOK() {
// try {
// HWSStatus status = getStatus();
// return status != null && "OK".equals(status.getStatus());
// } catch (Exception e) {
// return false;
// }
// }
/**
* Gets the status.
*
* @return the status
*/
// public HWSStatus getStatus() {
// return createDefaultService().getStatus();
// }
/**
* Will do a custom fetch of the URL at "/api", and will see if our
* API_PATH string pops up in the mix.
*
* @return False if the server does not tell us we're a valid version.
* (Might happen if you can't access the server too.)
*/
public boolean isSupported() {
try {
Request request = new Request.Builder().url(basePath
+ "/api/hws/version").method("GET", null)
.addHeader("Accept", "application/json").build();
Call call = okClient.newCall(request);
Response response = call.execute();
Gson gson = new Gson();
Type mapType = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> info = gson.fromJson(response.body().string(),
mapType);
@SuppressWarnings("unchecked")
List<String> versions = (List<String>) info.get("supportedVersions");
return versions.stream().anyMatch(v -> SUPPORTED_VERSION.equals(v));
} catch (Exception e) {
return false;
}
}
/**
* Initializes the adapterBuilder, typically called during construction.
*
* @param trustAllSsl
* when true will configure the adapter to trust all connections.
*/
public void createDefaultAdapter(final boolean trustAllSsl) {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();
okClient = new OkHttpClient();
if (trustAllSsl) {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(
final java.security.cert.X509Certificate[] chain,
final String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(
final java.security.cert.X509Certificate[] chain,
final String authType)
throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
} };
// Install the all-trusting trust manager
final SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts,
new java.security.SecureRandom());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
okClient.setSslSocketFactory(sslSocketFactory);
okClient.setHostnameVerifier((hostname, session) -> true);
}
adapterBuilder = new RestAdapter.Builder().setEndpoint(basePath + API_PATH)
.setClient(new OkClient(okClient))
.setErrorHandler(new ErrorHandler() {
@Override
public Throwable handleError(final RetrofitError arg0) {
return new HwsRestException(arg0);
}
})
.setConverter(new GsonConverterWrapper(gson));
}
/**
* Obtain a handle to the service object to interact with HWS.
*
* @return The primary API object to interact with HWS.
*/
public DefaultApi createDefaultService() {
return createService(DefaultApi.class);
}
/**
* Create a service object to interact with the server.
*
* In general, you'll probably just want the DefaultApi here.
*
* @param <S>
* The interface API (probably just DefaultApi.class)
* @param serviceClass
* The interface class indicating the API you want to use.
* @return The interface object to interact with the remote server.
*/
public <S> S createService(final Class<S> serviceClass) {
return adapterBuilder.build().create(serviceClass);
}
/**
* Helper method to configure the username/password for basic auth or
* password oauth.
*
* @param username
* The Perforce login
* @param ticket
* The Perforce ticket (not the user's password)
*/
public void setCredentials(final String username, final String ticket) {
HttpBasicAuth auth = new HttpBasicAuth();
auth.setUsername(username);
auth.setPassword(ticket);
updateAuthorization("ticket_auth", auth);
}
/**
* Helper method to set the API key as the "ticket_auth" scheme.
*
* @param apiKey the token to set for authorization
*/
public void setApiKey(final String apiKey) {
ApiKeyAuth auth = new ApiKeyAuth("header", "Authorization");
auth.setApiKey(apiKey);
updateAuthorization("ticket_auth", auth);
}
/**
* Add an authorization token.
* @param authName the name associated with a token
* @param authorization the token
*/
private void updateAuthorization(final String authName,
final Interceptor authorization) {
okClient.interceptors().clear();
okClient.interceptors().add(authorization);
apiAuthorizations.put(authName, authorization);
}
/**
* Get the adapter builder.
* @return the current builder of adapters.
*/
public RestAdapter.Builder getAdapterBuilder() {
return adapterBuilder;
}
/**
* Set a new adapter builder.
* @param adapterBuilder the new adapter builder to use
*/
public void setAdapterBuilder(final RestAdapter.Builder adapterBuilder) {
this.adapterBuilder = adapterBuilder;
}
/**
* Get the http client.
* @return the current http client
*/
public OkHttpClient getOkClient() {
return okClient;
}
/**
* Set the current authorizations in the http client.
* @param okClient the http client to be modified.
*/
public void addAuthsToOkClient(final OkHttpClient okClient) {
for (Interceptor apiAuthorization : apiAuthorizations.values()) {
okClient.interceptors().add(apiAuthorization);
}
}
/**
* Clones the okClient given in parameter, adds the auth interceptors and
* uses it to configure the RestAdapter.
*
* @param okClient
* The OKHttpClient to clone
*/
public void configureFromOkclient(final OkHttpClient okClient) {
OkHttpClient clone = okClient.clone();
addAuthsToOkClient(clone);
adapterBuilder.setClient(new OkClient(clone));
}
/**
* Wrapper class for the retrofit error to indicate that it was
* handled by a perforce api.
*/
public class HwsRestException extends RuntimeException {
/** Generated id, not expected to change. */
private static final long serialVersionUID = -8177702544598405834L;
/** The original retrofit error. */
private final RetrofitError retrofitError;
/**
* Instantiate a new exception to wrap the retrofit error.
* @param retrofitError the original rest error
*/
HwsRestException(final RetrofitError retrofitError) {
super(retrofitError.getLocalizedMessage());
this.retrofitError = retrofitError;
}
/**
* Get the original retrofit error, for further analysis.
* @return RetrofitError the original error
*/
public RetrofitError getRetrofitError() {
return retrofitError;
}
}
}
/**
* This wrapper is to take care of this case: when the deserialization fails due
* to JsonParseException and the expected type is String, then just return the
* body string.
*/
class GsonConverterWrapper implements Converter {
/** The actual converter instance. */
private GsonConverter converter;
/**
* Constructor with a converter instance.
* @param gson the java <-> json converter
*/
GsonConverterWrapper(final Gson gson) {
converter = new GsonConverter(gson);
}
@Override
public Object fromBody(final TypedInput body, final Type type)
throws ConversionException {
byte[] bodyBytes = readInBytes(body);
TypedByteArray newBody = new TypedByteArray(body.mimeType(), bodyBytes);
try {
return converter.fromBody(newBody, type);
} catch (ConversionException e) {
if (e.getCause() instanceof JsonParseException
&& type.equals(String.class)) {
return new String(bodyBytes);
} else {
throw e;
}
}
}
@Override
public TypedOutput toBody(final Object object) {
return converter.toBody(object);
}
/**
* Read a content body one byte at a time.
* @param body the content
* @return a byte array equivalent of the content
* @throws ConversionException if it cannot be converted
*/
private byte[] readInBytes(final TypedInput body)
throws ConversionException {
InputStream in = null;
try {
in = body.in();
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buffer = new byte[0xFFFF];
for (int len; (len = in.read(buffer)) != -1;) {
os.write(buffer, 0, len);
}
os.flush();
return os.toByteArray();
} catch (IOException e) {
throw new ConversionException(e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {
}
}
}
}
}