Skip to content

Commit

Permalink
feat(cloud): add organizationUnitId input (#9)
Browse files Browse the repository at this point in the history
* adapt all definition to have an organizationUnitId input for cloud
authentication
* update definition version
* improve error management
  • Loading branch information
rbioteau authored Feb 25, 2021
1 parent bed4d63 commit eeca542
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 45 deletions.
14 changes: 7 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<groupId>org.bonitasoft.connectors</groupId>
<artifactId>bonita-connector-uipath</artifactId>
<version>2.1.2-SNAPSHOT</version>
<version>2.2.0-SNAPSHOT</version>

<name>Bonita UIPath Connector</name>
<description>UIPath Connector for Bonita</description>
Expand Down Expand Up @@ -39,21 +39,21 @@

<!--Add Queue Item Connector -->
<uipath-add-queueItem.def.id>uipath-add-queueItem</uipath-add-queueItem.def.id>
<uipath-add-queueItem.def.version>2.0.0</uipath-add-queueItem.def.version>
<uipath-add-queueItem.def.version>2.1.0</uipath-add-queueItem.def.version>
<uipath-add-queueItem.impl.id>${uipath-add-queueItem.def.id}-impl</uipath-add-queueItem.impl.id>
<uipath-add-queueItem.impl.version>${project.version}</uipath-add-queueItem.impl.version>
<uipath-add-queueItem.main-class>org.bonitasoft.engine.connector.uipath.UIPathAddToQueueConnector</uipath-add-queueItem.main-class>

<!--Get Job Connector -->
<uipath-getjob.def.id>uipath-getjob</uipath-getjob.def.id>
<uipath-getjob.def.version>2.0.0</uipath-getjob.def.version>
<uipath-getjob.def.version>2.1.0</uipath-getjob.def.version>
<uipath-getjob.impl.id>${uipath-getjob.def.id}-impl</uipath-getjob.impl.id>
<uipath-getjob.impl.version>${project.version}</uipath-getjob.impl.version>
<uipath-getjob.main-class>org.bonitasoft.engine.connector.uipath.UIPathGetJobConnector</uipath-getjob.main-class>

<!--Start Job Connector -->
<uipath-startjob.def.id>uipath-startjob</uipath-startjob.def.id>
<uipath-startjob.def.version>2.0.0</uipath-startjob.def.version>
<uipath-startjob.def.version>2.1.0</uipath-startjob.def.version>
<uipath-startjob.impl.id>${uipath-startjob.def.id}-impl</uipath-startjob.impl.id>
<uipath-startjob.impl.version>${project.version}</uipath-startjob.impl.version>
<uipath-startjob.main-class>org.bonitasoft.engine.connector.uipath.UIPathStartJobsConnector</uipath-startjob.main-class>
Expand Down Expand Up @@ -82,7 +82,7 @@
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven-assembly-plugin.version>3.1.1</maven-assembly-plugin.version>
<groovy-maven-plugin.version>2.1.1</groovy-maven-plugin.version>
<groovy-all.version>2.4.16</groovy-all.version>
<groovy.version>3.0.7</groovy.version>
<maven-surefire-plugin.version>3.0.0-M4</maven-surefire-plugin.version>
<nexus-staging-maven-plugin.version>1.6.8</nexus-staging-maven-plugin.version>
<maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
Expand Down Expand Up @@ -219,8 +219,8 @@
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>${groovy-all.version}</version>
<artifactId>groovy</artifactId>
<version>${groovy.version}</version>
</dependency>
</dependencies>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ Optional<String> getDeferDate() {
QueueItem addToQueue(String token, AddToQueueRequest request) throws IOException, ConnectorException {
Response<QueueItem> response = getService().addQueueItem(createAuthenticationHeaders(token), request).execute();
if (!response.isSuccessful()) {
throw new ConnectorException(response.errorBody().string());
throw new ConnectorException(String.format("Failed to add item to queue: %s -%s",
response.code(),
getErrorMessage(response)));
}
return response.body();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

import com.fasterxml.jackson.databind.ObjectMapper;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Response;
import retrofit2.Retrofit;
Expand All @@ -25,27 +27,35 @@
public abstract class UIPathConnector extends AbstractConnector {

private static final Logger LOGGER = LoggerFactory.getLogger(UIPathConnector.class.getName());
private static final String CLOUD_ORCHESTRATOR_BASE_URL = "https://platform.uipath.com";
private static final String HEADER_TENANT_NAME = "X-UIPATH-TenantName";
private static final String HEADER_AUTHORIZATION_NAME = "Authorization";

static final String CLOUD = "cloud";

// classic parameters
static final String URL = "url";
static final String USER = "user";
static final String PASSWORD = "password";
static final String TENANT = "tenant";

// cloud parameters
static final String ACCOUNT_LOGICAL_NAME = "accountLogicalName";
static final String TENANT_LOGICAL_NAME = "tenantLogicalName";
static final String USER_KEY = "userKey";
static final String CLIENT_ID = "clientId";
static final String ORGANIZATION_UNIT_ID = "organizationUnitId";

private static final String CONTENT_TYPE = "Content-Type";
private static final String APPLICATION_JSON = "application/json";

private static final String CLOUD_ORCHESTRATOR_BASE_URL = "https://cloud.uipath.com";
private static final String TENANT_NAME_HEADER = "X-UIPATH-TenantName";
private static final String X_UIPATH_ORGANIZATION_UNIT_ID_HEADER = "X-UIPATH-OrganizationUnitId";
private static final String AUTHORIZATION_NAME_HEADER = "Authorization";

protected UIPathService service;
protected ObjectMapper mapper = new ObjectMapper();

private static String appendTraillingSlash(String url) {
return url.endsWith("/") ? url : url + "/";
}

@Override
public void validateInputParameters() throws ConnectorValidationException {
checkCloudInput();
Expand All @@ -54,6 +64,7 @@ public void validateInputParameters() throws ConnectorValidationException {
checkMandatoryStringInput(TENANT_LOGICAL_NAME);
checkMandatoryStringInput(USER_KEY);
checkMandatoryStringInput(CLIENT_ID);
checkMandatoryStringInput(ORGANIZATION_UNIT_ID);
} else {
checkMandatoryStringInput(URL);
checkMandatoryStringInput(TENANT);
Expand Down Expand Up @@ -106,8 +117,8 @@ String authenticate() throws ConnectorException {
try {
if (isCloud()) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(HEADER_TENANT_NAME, getTenantLogicalName());
headers.put(CONTENT_TYPE, APPLICATION_JSON);
headers.put(TENANT_NAME_HEADER, getTenantLogicalName());
CloudAuthentication cloudAuthentication = new CloudAuthentication("refresh_token", getClientId(),
getUserKey());
response = service.authenticateInCloud(headers, cloudAuthentication).execute();
Expand All @@ -121,44 +132,58 @@ String authenticate() throws ConnectorException {
e);
}
if (!response.isSuccessful()) {
try {
throw new ConnectorException(response.errorBody().string());
} catch (IOException e) {
throw new ConnectorException("Failed to read response body.", e);
}
throw new ConnectorException(String.format("Authentication failed: %s - %s",
response.code(),
getErrorMessage(response)));
}
return isCloud()
? response.body().get("access_token")
: response.body().get("result");
}

protected String getErrorMessage(Response<?> response) {
try {
return response.errorBody().string();
} catch (IOException e) {
return null;
}
}

protected Map<String, String> createAuthenticationHeaders(String token) {
Map<String, String> headers = new HashMap<>();
headers.put(HEADER_AUTHORIZATION_NAME, buildTokenHeader(token));
headers.put(AUTHORIZATION_NAME_HEADER, buildTokenHeader(token));
if (isCloud()) {
headers.put(HEADER_TENANT_NAME, getTenantLogicalName());
headers.put(TENANT_NAME_HEADER, getTenantLogicalName());
}
return headers;
}

protected UIPathService createService() {
if (service == null) {
OkHttpClient client = null;
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
Interceptor jsonHeaderInterceptor = chain -> {
Request.Builder requestBuilder = chain.request().newBuilder();
requestBuilder.header(CONTENT_TYPE, APPLICATION_JSON);
if (isCloud()) {
requestBuilder.header(X_UIPATH_ORGANIZATION_UNIT_ID_HEADER, getOrganizationUnitId());
}
return chain.proceed(requestBuilder.build());
};
clientBuilder.addInterceptor(jsonHeaderInterceptor);
if (LOGGER.isDebugEnabled()) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
HttpLoggingInterceptor loggerInterceptor = new HttpLoggingInterceptor();
loggerInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
clientBuilder.addInterceptor(loggerInterceptor);
}

OkHttpClient client = clientBuilder.build();
Builder retrofitBuilder = new Retrofit.Builder()
.client(client)
.addConverterFactory(new WrappedAttributeConverter(mapper))
.addConverterFactory(JacksonConverterFactory.create())
.baseUrl(getUrl());

if (client != null) {
retrofitBuilder.client(client);
}

service = retrofitBuilder.build().create(UIPathService.class);
}
return service;
Expand All @@ -174,8 +199,8 @@ protected Map<Object, Object> toMap(Object inputParameter) {
return result;
}

private static String appendTraillingSlash(String url) {
return url.endsWith("/") ? url : url + "/";
String getOrganizationUnitId() {
return (String) getInputParameter(ORGANIZATION_UNIT_ID);
}

String getTenant() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ String getJobId() {
Job job(long id, String token) throws IOException, ConnectorException {
Response<Job> response = getService().job(createAuthenticationHeaders(token), id).execute();
if (!response.isSuccessful()) {
throw new ConnectorException(response.errorBody().string());
throw new ConnectorException(String.format("Failed to retrieve Job with id='%s': %s - %s:", id, response.code(), getErrorMessage(response)) );
}
return response.body();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public class UIPathStartJobsConnector extends UIPathConnector {
static final String STRATEGY = "strategy";
static final String INPUT_ARGS = "inputArguments";
static final String STARTED_JOBS_OUTPUT = "startedJobs";
static final String RUNTIME_TYPE = "runtimeType";
static final String SOURCE = "source";

@Override
public void validateInputParameters() throws ConnectorValidationException {
Expand All @@ -61,7 +63,7 @@ public void validateInputParameters() throws ConnectorValidationException {
checkArgsInput();
}

void checkJobsCountIfJobsCountStrategy() throws ConnectorValidationException {
void checkRobotsIfSpecific() throws ConnectorValidationException {
Optional<String> strategy = getStrategy();
if (strategy.filter(Strategy.SPECIFIC.toString()::equals).isPresent()) {
Optional<List<String>> robots = getRobots();
Expand All @@ -71,7 +73,7 @@ void checkJobsCountIfJobsCountStrategy() throws ConnectorValidationException {
}
}

void checkRobotsIfSpecific() throws ConnectorValidationException {
void checkJobsCountIfJobsCountStrategy() throws ConnectorValidationException {
Optional<String> strategy = getStrategy();
if (strategy.filter(Strategy.JOBS_COUNT.toString()::equals).isPresent()) {
Optional<Integer> jobsCount = getJobsCount();
Expand Down Expand Up @@ -102,6 +104,18 @@ Optional<String> getStrategy() {
return Optional.ofNullable((String) getInputParameter(STRATEGY));
}

Optional<String> getRuntimeType() {
String runtimeType = (String) getInputParameter(RUNTIME_TYPE);
if(runtimeType == null || runtimeType.isEmpty()) {
return Optional.empty();
}
return Optional.ofNullable(runtimeType);
}

Optional<String> getSource() {
return Optional.ofNullable((String) getInputParameter(SOURCE));
}

Optional<Map<Object, Object>> getInputArguments() {
Object inputParameter = getInputParameter(INPUT_ARGS);
if (inputParameter instanceof List) {
Expand Down Expand Up @@ -146,11 +160,14 @@ List<Job> startJobs(String token, Release release, List<Integer> robotIds)
.setSource(Source.MANUAL.toString())
.setReleaseKey(release.getKey());

getRuntimeType().ifPresent(startInfo::setRuntimeType);
getStrategy().ifPresent(startInfo::setStrategy);

if (Objects.equals(startInfo.getStrategy(), Strategy.SPECIFIC.toString())) {
startInfo.setRobotIds(robotIds);
}
if (Objects.equals(startInfo.getStrategy(), Strategy.JOBS_COUNT.toString())) {
if (Objects.equals(startInfo.getStrategy(), Strategy.JOBS_COUNT.toString())
|| Objects.equals(startInfo.getStrategy(), Strategy.MODERN_JOBS_COUNT.toString())) {
getJobsCount().ifPresent(startInfo::setJobsCount);
}
try {
Expand All @@ -170,7 +187,8 @@ List<Job> startJobs(String token, Release release, List<Integer> robotIds)
if (LOGGER.isErrorEnabled()) {
LOGGER.error(response.toString());
}
throw new ConnectorException("Failed to start job: " + response.message());
throw new ConnectorException(
String.format("Failed to start job: %s - %s", response.code(), getErrorMessage(response)));
}
return response.body();
}
Expand Down Expand Up @@ -222,7 +240,9 @@ List<Release> releases(String token) throws ConnectorException {
throw new ConnectorException("Failed to retrieve releases.", e);
}
if (!response.isSuccessful()) {
throw new ConnectorException("Failed to retrieve releases: " + response.message());
throw new ConnectorException(String.format("Failed to retrieve releases: %s - %s",
response.code(),
getErrorMessage(response)));
}
return response.body();
}
Expand All @@ -235,7 +255,9 @@ List<Robot> robots(String token) throws ConnectorException {
throw new ConnectorException("Failed to retrieve robots.", e);
}
if (!response.isSuccessful()) {
throw new ConnectorException("Failed to retrieve robots: " + response.message());
throw new ConnectorException(String.format("Failed to retrieve robots: %s - %s",
response.code(),
getErrorMessage(response)));
}
return response.body();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,9 @@ public class StartInfo {
@JsonProperty("InputArguments")
@JsonInclude(Include.NON_EMPTY)
private String args;
@JsonProperty("RuntimeType")
@JsonInclude(Include.NON_NULL)
private String runtimeType;


}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

public enum Strategy {

ALL("All"), SPECIFIC("Specific"), JOBS_COUNT("JobsCount");
ALL("All"), SPECIFIC("Specific"), JOBS_COUNT("JobsCount"), MODERN_JOBS_COUNT("ModernJobsCount");

private final String value;

Expand Down
2 changes: 2 additions & 0 deletions src/main/resources-filtered/uipath-add-queueItem.def
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<input name="tenantLogicalName" type="java.lang.String"/>
<input name="userKey" type="java.lang.String"/>
<input name="clientId" type="java.lang.String"/>
<input name="organizationUnitId" type="java.lang.String"/>

<input name="queueName" type="java.lang.String"/>
<input name="reference" type="java.lang.String"/>
Expand All @@ -31,6 +32,7 @@
<widget xsi:type="definition:Password" id="passwordWidget" inputName="password"/>
<widget xsi:type="definition:Text" id="accountLogicalNameWidget" inputName="accountLogicalName"/>
<widget xsi:type="definition:Text" id="tenantLogicalNameWidget" inputName="tenantLogicalName"/>
<widget xsi:type="definition:Text" id="organizationUnitIdWidget" inputName="organizationUnitId"/>
<widget xsi:type="definition:Text" id="userKeyWidget" inputName="userKey"/>
<widget xsi:type="definition:Password" id="clientIdWidget" inputName="clientId"/>
</page>
Expand Down
10 changes: 9 additions & 1 deletion src/main/resources-filtered/uipath-getjob.def
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<input name="tenantLogicalName" type="java.lang.String"/>
<input name="userKey" type="java.lang.String"/>
<input name="clientId" type="java.lang.String"/>
<input name="organizationUnitId" type="java.lang.String"/>

<input mandatory="true" name="jobId" type="java.lang.String"/>

Expand All @@ -25,6 +26,13 @@
<widget xsi:type="definition:Text" id="tenantWidget" inputName="tenant"/>
<widget xsi:type="definition:Text" id="userWidget" inputName="user"/>
<widget xsi:type="definition:Password" id="passwordWidget" inputName="password"/>
<widget xsi:type="definition:Text" id="jobIdWidget" inputName="jobId"/>
<widget xsi:type="definition:Text" id="accountLogicalNameWidget" inputName="accountLogicalName"/>
<widget xsi:type="definition:Text" id="tenantLogicalNameWidget" inputName="tenantLogicalName"/>
<widget xsi:type="definition:Text" id="organizationUnitIdWidget" inputName="organizationUnitId"/>
<widget xsi:type="definition:Text" id="userKeyWidget" inputName="userKey"/>
<widget xsi:type="definition:Password" id="clientIdWidget" inputName="clientId"/>
</page>
<page id="configurationPage">
<widget xsi:type="definition:Text" id="jobIdWidget" inputName="jobId"/>
</page>
</definition:ConnectorDefinition>
Loading

0 comments on commit eeca542

Please sign in to comment.