treasure-data/embulk-input-jira

View on GitHub
src/main/java/org/embulk/input/jira/util/JiraUtil.java

Summary

Maintainability
C
7 hrs
Test Coverage
package org.embulk.input.jira.util;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.embulk.config.ConfigException;
import org.embulk.config.ConfigSource;
import org.embulk.input.jira.Issue;
import org.embulk.input.jira.JiraInputPlugin.PluginTask;
import org.embulk.spi.Column;
import org.embulk.spi.ColumnVisitor;
import org.embulk.spi.PageBuilder;
import org.embulk.spi.Schema;
import org.embulk.util.config.units.ColumnConfig;
import org.embulk.util.json.JsonParser;
import org.embulk.util.timestamp.TimestampFormatter;

import javax.ws.rs.core.UriBuilder;

import java.io.IOException;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static com.google.common.base.Strings.isNullOrEmpty;
import static org.embulk.input.jira.Constant.CREDENTIAL_URI_PATH;
import static org.embulk.input.jira.Constant.DEFAULT_TIMESTAMP_PATTERN;
import static org.embulk.input.jira.Constant.HTTP_TIMEOUT;
import static org.embulk.input.jira.Constant.SEARCH_URI_PATH;

public final class JiraUtil
{
    private JiraUtil() {}

    public static int calculateTotalPage(final int totalCount, final int resultPerPage)
    {
        return (int) Math.ceil((double) totalCount / resultPerPage);
    }

    public static String buildPermissionUrl(final String url)
    {
        return UriBuilder.fromUri(url).path(CREDENTIAL_URI_PATH).build().toString();
    }

    public static String buildSearchUrl(final String url)
    {
        return UriBuilder.fromUri(url).path(SEARCH_URI_PATH).build().toString();
    }

    public static void validateTaskConfig(final PluginTask task)
    {
        final String username = task.getUsername();
        if (isNullOrEmpty(username)) {
            throw new ConfigException("Username or email could not be empty");
        }
        final String password = task.getPassword();
        if (isNullOrEmpty(password)) {
            throw new ConfigException("Password could not be empty");
        }
        final String uri = task.getUri();
        if (isNullOrEmpty(uri)) {
            throw new ConfigException("JIRA API endpoint could not be empty");
        }
        try (CloseableHttpClient client = HttpClientBuilder.create()
                                            .setDefaultRequestConfig(RequestConfig.custom()
                                                                                .setConnectTimeout(HTTP_TIMEOUT)
                                                                                .setConnectionRequestTimeout(HTTP_TIMEOUT)
                                                                                .setSocketTimeout(HTTP_TIMEOUT)
                                                                                .setCookieSpec(CookieSpecs.STANDARD)
                                                                                .build())
                                            .build()) {
            final HttpGet request = new HttpGet(uri);
            try (CloseableHttpResponse response = client.execute(request)) {
                response.getStatusLine().getStatusCode();
            }
        }
        catch (IOException | IllegalArgumentException e) {
            throw new ConfigException("JIRA API endpoint is incorrect or not available");
        }
        final int retryInitialWaitSec = task.getInitialRetryIntervalMillis();
        if (retryInitialWaitSec < 1) {
            throw new ConfigException("Initial retry delay should be equal or greater than 1");
        }
        final int retryLimit = task.getRetryLimit();
        if (retryLimit < 0 || retryLimit > 10) {
            throw new ConfigException("Retry limit should between 0 and 10");
        }
    }

    /*
     * For getting the timestamp value of the node
     * Sometime if the parser could not parse the value then return null
     * */
    private static Instant getTimestampValue(final PluginTask task, final Column column, final String value)
    {
        final List<ColumnConfig> columnConfigs = task.getColumns().getColumns();
        String pattern = DEFAULT_TIMESTAMP_PATTERN;
        for (final ColumnConfig columnConfig : columnConfigs) {
            final ConfigSource columnConfigSource = columnConfig.getConfigSource();
            if (columnConfig.getName().equals(column.getName())
                    && columnConfigSource != null
                    && columnConfigSource.has("format")) {
                pattern = columnConfigSource.get(String.class, "format");
                break;
            }
        }
        final TimestampFormatter formatter = TimestampFormatter
                .builder(pattern, true)
                .setDefaultZoneFromString("UTC")
                .build();
        try {
            return formatter.parse(value);
        }
        catch (final Exception e) {
            return null;
        }
    }

    /*
     * For getting the Long value of the node
     * Sometime if error occurs (i.e a JSON value but user modified it as long) then return null
     * */
    private static Long getLongValue(final JsonElement value)
    {
        try {
            return value.getAsLong();
        }
        catch (final Exception e) {
            return null;
        }
    }

    /*
     * For getting the Double value of the node
     * Sometime if error occurs (i.e a JSON value but user modified it as double) then return null
     * */
    private static Double getDoubleValue(final JsonElement value)
    {
        try {
            return value.getAsDouble();
        }
        catch (final Exception e) {
            return null;
        }
    }

    /*
     * For getting the Boolean value of the node
     * Sometime if error occurs (i.e a JSON value but user modified it as boolean) then return null
     * */
    private static Boolean getBooleanValue(final JsonElement value)
    {
        try {
            return value.getAsBoolean();
        }
        catch (final Exception e) {
            return null;
        }
    }

    public static void addRecord(final Issue issue, final Schema schema, final PluginTask task, final PageBuilder pageBuilder)
    {
        schema.visitColumns(new ColumnVisitor() {
            @Override
            public void jsonColumn(final Column column)
            {
                final JsonElement data = issue.getValue(column.getName());
                if (data.isJsonNull() || data.isJsonPrimitive()) {
                    pageBuilder.setNull(column);
                }
                else {
                    pageBuilder.setJson(column, new JsonParser().parse(data.toString()));
                }
            }

            @Override
            public void stringColumn(final Column column)
            {
                final JsonElement data = issue.getValue(column.getName());
                if (data.isJsonNull()) {
                    pageBuilder.setNull(column);
                }
                else if (data.isJsonPrimitive()) {
                    pageBuilder.setString(column, data.getAsString());
                }
                else if (data.isJsonArray()) {
                    pageBuilder.setString(column, StreamSupport.stream(data.getAsJsonArray().spliterator(), false)
                            .map(obj -> {
                                if (obj.isJsonPrimitive()) {
                                    return obj.getAsString();
                                }
                                return obj.toString();
                            })
                            .collect(Collectors.joining(",")));
                }
                else {
                    pageBuilder.setString(column, data.toString());
                }
            }

            @Override
            public void timestampColumn(final Column column)
            {
                final JsonElement data = issue.getValue(column.getName());
                if (data.isJsonNull() || data.isJsonObject() || data.isJsonArray()) {
                    pageBuilder.setNull(column);
                }
                else {
                    final Instant value = getTimestampValue(task, column, data.getAsString());
                    if (value == null) {
                        pageBuilder.setNull(column);
                    }
                    else {
                        pageBuilder.setTimestamp(column, value);
                    }
                }
            }

            @Override
            public void booleanColumn(final Column column)
            {
                final Boolean value = getBooleanValue(issue.getValue(column.getName()));
                if (value == null) {
                    pageBuilder.setNull(column);
                }
                else {
                    pageBuilder.setBoolean(column, value);
                }
            }

            @Override
            public void longColumn(final Column column)
            {
                final Long value = getLongValue(issue.getValue(column.getName()));
                if (value == null) {
                    pageBuilder.setNull(column);
                }
                else {
                    pageBuilder.setLong(column, value);
                }
            }

            @Override
            public void doubleColumn(final Column column)
            {
                final Double value = getDoubleValue(issue.getValue(column.getName()));
                if (value == null) {
                    pageBuilder.setNull(column);
                }
                else {
                    pageBuilder.setDouble(column, value);
                }
            }
        });
        pageBuilder.addRecord();
    }

    public static LinkedHashMap<String, Object> toLinkedHashMap(final JsonObject flt)
    {
        final LinkedHashMap<String, Object> result = new LinkedHashMap<>();
        for (final String key : flt.keySet()) {
            final JsonElement elem = flt.get(key);
            if (elem.isJsonPrimitive()) {
                result.put(key, flt.get(key).getAsString());
            }
            else {
                result.put(key, elem);
            }
        }
        return result;
    }
}