com.finbourne.drive.extensions.ApiFactory Maven / Gradle / Ivy
package com.finbourne.drive.extensions;
import com.finbourne.drive.ApiClient;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
/**
* Utility class that builds pre-configured drive API instances to access drive.
*
*/
public class ApiFactory {
/**
* The unique package that hosts all the drive API classes
*/
public static final String API_PACKAGE = "com.finbourne.drive.api";
private final ApiClient apiClient;
private final Map initialisedApis;
/**
* Create a API factory based on an {@link ApiClient}
*
* @param apiClient configured to a specific application
*/
public ApiFactory(ApiClient apiClient) {
this.apiClient = apiClient;
initialisedApis = new HashMap<>();
}
/**
* Builds an instance of a drive API
*
* For each instance of an {@link ApiFactory} only a singleton instance of each drive API class exist. The APIs
* are lazily initialised on request.
*
*
* @param apiClass - class of the drive API to create
* @param drive API type
* @return instance of the drive API type configured as per the {@link ApiClient}
*
* @throws UnsupportedOperationException is the apiClass does not belong to the import com.finbourne.drive.api package or
* if the class has no constructor that accepts an {@link ApiClient} parameter.
*/
public synchronized T build(Class apiClass) {
@SuppressWarnings (value="unchecked")
T apiInstance = (T) initialisedApis.get(apiClass);
if (apiInstance == null) {
checkIsSupportedApiClass(apiClass);
Constructor constructor = getApiConstructor(apiClass);
apiInstance = createInstance(constructor);
initialisedApis.put(apiClass, apiInstance);
}
return apiInstance;
};
/*
* Create an instance of a drive API configured by an {@link ApiClient}
*
* @throws UnsupportedOperationException on any reflection related issues on constructing the drive API object
*/
private T createInstance(Constructor constructor){
try {
return constructor.newInstance(apiClient);
} catch (ReflectiveOperationException e) {
throw new UnsupportedOperationException("Construction of " + constructor.getClass().getName() + " failed " +
"due to an invalid instantiation call.",e);
}
}
/*
* Retrieves the constructor for the drive API that accepts an {@link ApiClient}
*
* @throws UnsupportedOperationException if the class doesn't have a valid constructor that takes
* an {@link ApiClient} as an argument to ensure proper construction of a drive API instance.
*/
private Constructor getApiConstructor(Class apiClass){
try {
return apiClass.getDeclaredConstructor(ApiClient.class);
} catch (NoSuchMethodException e) {
throw new UnsupportedOperationException(apiClass.getName() + " has no single argument constructor taking " +
"in " + ApiClient.class.getName());
}
}
/*
* Checks the class lives in the set package for drive API classes.
*
* @throws UnsupportedOperationException if API class does not live in drive API package
*/
private void checkIsSupportedApiClass(Class apiClass){
if (!isInApiPackage(apiClass)) {
throw new UnsupportedOperationException(apiClass.getName() + " class is not a supported API class. " +
"Supported API classes live in the " + ApiFactory.API_PACKAGE + " package.");
}
}
private boolean isInApiPackage(Class clazz){
return API_PACKAGE.equals(clazz.getPackage().getName());
}
}