diff --git a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/ApacheAsyncHttpClient.java b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/ApacheAsyncHttpClient.java index fa1178a6f..f5172ff5c 100644 --- a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/ApacheAsyncHttpClient.java +++ b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/ApacheAsyncHttpClient.java @@ -50,7 +50,6 @@ import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.ProxyAuthenticationStrategy; -import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.http.impl.conn.DefaultRoutePlanner; import org.apache.http.impl.conn.DefaultSchemePortResolver; import org.apache.http.impl.conn.SystemDefaultDnsResolver; @@ -85,7 +84,6 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; @@ -182,6 +180,8 @@ protected void finalize() throws Throwable } }; + connectionManager.setDefaultMaxPerRoute(options.getMaxConnectionsPerHost()); + final RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout((int) options.getConnectionTimeout()) .setConnectionRequestTimeout((int) options.getLeaseTimeout()) @@ -189,8 +189,6 @@ protected void finalize() throws Throwable .setSocketTimeout((int) options.getSocketTimeout()) .build(); - connectionManager.setDefaultMaxPerRoute(options.getMaxConnectionsPerHost()); - final HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom() .setThreadFactory(ThreadFactories.namedThreadFactory(options.getThreadPrefix() + "-io", ThreadFactories.Type.DAEMON)) .setDefaultIOReactorConfig(reactorConfig) @@ -199,26 +197,25 @@ protected void finalize() throws Throwable .setUserAgent(getUserAgent(options)) .setDefaultRequestConfig(requestConfig); - - ProxyConfiguration proxyConfiguration = Jenkins.getInstance().proxy; - if(proxyConfiguration!=null) - { - final HttpHost proxy = new HttpHost( proxyConfiguration.name, proxyConfiguration.port ); - //clientBuilder.setProxy( proxy ); - if(StringUtils.isNotBlank( proxyConfiguration.getUserName())) - { - clientBuilder.setProxyAuthenticationStrategy( ProxyAuthenticationStrategy.INSTANCE ); - CredentialsProvider credsProvider = new BasicCredentialsProvider(); - credsProvider.setCredentials( new AuthScope( proxyConfiguration.name, proxyConfiguration.port), - new UsernamePasswordCredentials(proxyConfiguration.getUserName(), - proxyConfiguration.getPassword()) ); - clientBuilder.setDefaultCredentialsProvider( credsProvider ); + if(Jenkins.getInstance() != null) { + ProxyConfiguration proxyConfiguration = Jenkins.getInstance().proxy; + if ( proxyConfiguration != null ) { + final HttpHost proxy = new HttpHost( proxyConfiguration.name, proxyConfiguration.port ); + //clientBuilder.setProxy( proxy ); + if ( StringUtils.isNotBlank( proxyConfiguration.getUserName() ) ) { + clientBuilder.setProxyAuthenticationStrategy( ProxyAuthenticationStrategy.INSTANCE ); + CredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials( new AuthScope( proxyConfiguration.name, proxyConfiguration.port ), + new UsernamePasswordCredentials( proxyConfiguration.getUserName(), + proxyConfiguration.getPassword() ) ); + clientBuilder.setDefaultCredentialsProvider( credsProvider ); + } + + clientBuilder.setRoutePlanner( + new JenkinsProxyRoutePlanner( proxy, proxyConfiguration.getNoProxyHostPatterns() ) ); } - - clientBuilder.setRoutePlanner(new JenkinsProxyRoutePlanner(proxy, proxyConfiguration.getNoProxyHostPatterns())); } - /* ProxyConfigFactory.getProxyHost(options).foreach(new Effect() { diff --git a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultHttpClientFactory.java b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultHttpClientFactory.java index 41e5d751a..4d150631e 100644 --- a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultHttpClientFactory.java +++ b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultHttpClientFactory.java @@ -9,11 +9,11 @@ import com.google.common.annotations.VisibleForTesting; import org.springframework.beans.factory.DisposableBean; +import javax.annotation.Nonnull; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; -import javax.annotation.Nonnull; -import static com.google.common.base.Preconditions.*; +import static com.google.common.base.Preconditions.checkNotNull; public final class DefaultHttpClientFactory implements HttpClientFactory, DisposableBean { diff --git a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultRequest.java b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultRequest.java index 1e14c82b3..a38c52c81 100644 --- a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultRequest.java +++ b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultRequest.java @@ -128,7 +128,7 @@ public DefaultRequestBuilder(final HttpClient httpClient) { this.httpClient = httpClient; this.attributes = new HashMap<>(); - commonBuilder = new CommonBuilder(); + commonBuilder = new CommonBuilder<>(); setAccept("*/*"); contentLength = Option.none(); } diff --git a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultResponse.java b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultResponse.java index 34b2825cc..af0bdc977 100644 --- a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultResponse.java +++ b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/DefaultResponse.java @@ -2,11 +2,9 @@ import com.atlassian.fugue.Option; import com.atlassian.httpclient.api.Response; -import com.google.common.base.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; import java.io.InputStream; import java.util.Map; @@ -163,12 +161,7 @@ public Option getContentLength() try { Option parsedLength = Option.some(Long.parseLong(lengthString)); - return parsedLength.flatMap( - new Function>() - { - @Override - public Option apply(Long aLong) - { + return parsedLength.flatMap( aLong -> { if (aLong < 0) { log.warn("Unable to parse content length. Received out of range value {}", aLong); @@ -178,7 +171,6 @@ public Option apply(Long aLong) { return Option.some(aLong); } - } }); } catch (NumberFormatException e) diff --git a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/Headers.java b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/Headers.java index 88fd2784c..188b8cb03 100644 --- a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/Headers.java +++ b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/Headers.java @@ -6,10 +6,9 @@ import java.nio.charset.Charset; import java.util.Collections; +import java.util.HashMap; import java.util.Map; -import static com.google.common.collect.Maps.newHashMap; - public class Headers { private final Map headers; @@ -35,7 +34,7 @@ public String getContentType() public Map getHeaders() { - Map headers = newHashMap(this.headers); + Map headers = new HashMap( this.headers); if (contentType != null) { headers.put(Names.CONTENT_TYPE, buildContentType()); @@ -69,7 +68,7 @@ private String buildContentType() public static class Builder implements Buildable { - private final Map headers = newHashMap(); + private final Map headers = new HashMap(); private String contentType; private String contentCharset; diff --git a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/SettableFuturePromiseHttpPromiseAsyncClient.java b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/SettableFuturePromiseHttpPromiseAsyncClient.java index 14b09a49f..afd3aa1a7 100644 --- a/src/main/java/com/atlassian/httpclient/apache/httpcomponents/SettableFuturePromiseHttpPromiseAsyncClient.java +++ b/src/main/java/com/atlassian/httpclient/apache/httpcomponents/SettableFuturePromiseHttpPromiseAsyncClient.java @@ -14,7 +14,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; -import static com.google.common.base.Preconditions.*; +import static com.google.common.base.Preconditions.checkNotNull; final class SettableFuturePromiseHttpPromiseAsyncClient implements PromiseHttpAsyncClient { @@ -38,41 +38,20 @@ public Promise execute(HttpUriRequest request, HttpContext context @Override void doCompleted(final HttpResponse httpResponse) { - executor.execute(new Runnable() - { - @Override - public void run() - { - future.set(httpResponse); - } - }); + executor.execute( () -> future.set(httpResponse)); } @Override void doFailed(final Exception ex) { - executor.execute(new Runnable() - { - @Override - public void run() - { - future.setException(ex); - } - }); + executor.execute(() -> future.setException(ex)); } @Override void doCancelled() { final TimeoutException timeoutException = new TimeoutException(); - executor.execute(new Runnable() - { - @Override - public void run() - { - future.setException(timeoutException); - } - }); + executor.execute(() -> future.setException(timeoutException)); } }); return Promises.forListenableFuture(future); @@ -118,40 +97,19 @@ private ThreadLocalContextAwareFutureCallback(ThreadLocalContextManager threa @Override public final void completed(final HttpResponse response) { - runInContext(threadLocalContextManager, threadLocalContext, contextClassLoader, new Runnable() - { - @Override - public void run() - { - doCompleted(response); - } - }); + runInContext(threadLocalContextManager, threadLocalContext, contextClassLoader, () -> doCompleted(response)); } @Override public final void failed(final Exception ex) { - runInContext(threadLocalContextManager, threadLocalContext, contextClassLoader, new Runnable() - { - @Override - public void run() - { - doFailed(ex); - } - }); + runInContext(threadLocalContextManager, threadLocalContext, contextClassLoader, () -> doFailed(ex)); } @Override public final void cancelled() { - runInContext(threadLocalContextManager, threadLocalContext, contextClassLoader, new Runnable() - { - @Override - public void run() - { - doCancelled(); - } - }); + runInContext(threadLocalContextManager, threadLocalContext, contextClassLoader, () -> doCancelled()); } } @@ -189,14 +147,7 @@ private static final class ThreadLocalDelegateRunnable implements Runnable public void run() { - runInContext(manager, context, contextClassLoader, new Runnable() - { - @Override - public void run() - { - delegate.run(); - } - }); + runInContext(manager, context, contextClassLoader, () -> delegate.run()); } } } diff --git a/src/main/java/hudson/plugins/jira/JiraBuildAction.java b/src/main/java/hudson/plugins/jira/JiraBuildAction.java index b40ca76f5..bbb87c102 100644 --- a/src/main/java/hudson/plugins/jira/JiraBuildAction.java +++ b/src/main/java/hudson/plugins/jira/JiraBuildAction.java @@ -1,10 +1,9 @@ package hudson.plugins.jira; import java.net.URL; +import java.util.HashSet; import java.util.Set; -import com.google.common.base.Objects; -import com.google.common.collect.Sets; import hudson.model.Action; import hudson.model.Run; import hudson.plugins.jira.model.JiraIssue; @@ -27,7 +26,7 @@ public class JiraBuildAction implements Action { public JiraBuildAction(@Nonnull Run owner, @Nonnull Set issues) { this.owner = owner; - this.issues = Sets.newHashSet(issues); + this.issues = new HashSet( issues); } public String getIconFileName() { diff --git a/src/main/java/hudson/plugins/jira/JiraCreateIssueNotifier.java b/src/main/java/hudson/plugins/jira/JiraCreateIssueNotifier.java index fc8aa8b9a..3e79d9377 100644 --- a/src/main/java/hudson/plugins/jira/JiraCreateIssueNotifier.java +++ b/src/main/java/hudson/plugins/jira/JiraCreateIssueNotifier.java @@ -25,11 +25,13 @@ import org.kohsuke.stapler.StaplerRequest; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.IOException; -import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.logging.Logger; import static hudson.plugins.jira.JiraRestService.BUG_ISSUE_TYPE_ID; @@ -242,12 +244,13 @@ private void addComment(AbstractBuild build, BuildListener listener, Strin * @throws InterruptedException */ private String getIssue(String filename) throws IOException, InterruptedException { - String issueId = ""; - BufferedReader br = null; - try { + Path path = Paths.get(filename); + if(Files.notExists(path)){ + return null; + } + try (BufferedReader br = Files.newBufferedReader(path)) { String issue; - br = new BufferedReader(new FileReader(filename)); while ((issue = br.readLine()) != null) { issueId = issue; @@ -255,12 +258,7 @@ private String getIssue(String filename) throws IOException, InterruptedExceptio return issueId; } catch (FileNotFoundException e) { return null; - } finally { - if (br != null) { - br.close(); - } } - } JiraSite getSiteForProject(AbstractProject project) { @@ -303,14 +301,17 @@ private void deleteFile(String filename) { /** * write's the issue id in the file, which is stored in the Job's directory * - * @param Filename + * @param filename * @param issue * @throws FileNotFoundException */ - private void writeInFile(String Filename, Issue issue) throws FileNotFoundException { - PrintWriter writer = new PrintWriter(Filename); - writer.println(issue.getKey()); - writer.close(); + private void writeInFile(String filename, Issue issue) throws IOException { + // olamy really weird to write an empty file especially with null + // but backward compat and unit tests assert that..... + // can't believe such stuff has been merged...... + try(BufferedWriter bw =Files.newBufferedWriter( Paths.get( filename ) )) { + bw.write(issue.getKey()==null?"null":issue.getKey()); + } } /** diff --git a/src/main/java/hudson/plugins/jira/JiraCreateReleaseNotes.java b/src/main/java/hudson/plugins/jira/JiraCreateReleaseNotes.java index b550f72ee..805cf0e41 100644 --- a/src/main/java/hudson/plugins/jira/JiraCreateReleaseNotes.java +++ b/src/main/java/hudson/plugins/jira/JiraCreateReleaseNotes.java @@ -4,7 +4,6 @@ import hudson.Extension; import hudson.FilePath; import hudson.Launcher; -import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.Job; @@ -14,7 +13,6 @@ import hudson.tasks.BuildStepMonitor; import hudson.tasks.BuildWrapperDescriptor; import jenkins.tasks.SimpleBuildWrapper; - import org.kohsuke.stapler.DataBoundConstructor; import java.io.IOException; diff --git a/src/main/java/hudson/plugins/jira/JiraFolderProperty.java b/src/main/java/hudson/plugins/jira/JiraFolderProperty.java index ba0d9488a..b1401cba9 100644 --- a/src/main/java/hudson/plugins/jira/JiraFolderProperty.java +++ b/src/main/java/hudson/plugins/jira/JiraFolderProperty.java @@ -22,7 +22,7 @@ public class JiraFolderProperty extends AbstractFolderProperty /** * Hold the JIRA sites configuration. */ - private final CopyOnWriteList sites = new CopyOnWriteList(); + private final CopyOnWriteList sites = new CopyOnWriteList<>(); /** * Constructor. diff --git a/src/main/java/hudson/plugins/jira/JiraIssueUpdater.java b/src/main/java/hudson/plugins/jira/JiraIssueUpdater.java index 92aa3e631..b6dac58df 100644 --- a/src/main/java/hudson/plugins/jira/JiraIssueUpdater.java +++ b/src/main/java/hudson/plugins/jira/JiraIssueUpdater.java @@ -132,7 +132,7 @@ public boolean isApplicable(Class jobType) { } public boolean hasIssueSelectors() { - return Jenkins.getActiveInstance().getDescriptorList(AbstractIssueSelector.class).size() > 1; + return Jenkins.getInstance().getDescriptorList(AbstractIssueSelector.class).size() > 1; } } diff --git a/src/main/java/hudson/plugins/jira/JiraProjectProperty.java b/src/main/java/hudson/plugins/jira/JiraProjectProperty.java index e4ab61eb9..0083a9742 100644 --- a/src/main/java/hudson/plugins/jira/JiraProjectProperty.java +++ b/src/main/java/hudson/plugins/jira/JiraProjectProperty.java @@ -10,8 +10,6 @@ import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; -import java.util.logging.Logger; - /** * Associates {@link Job} with {@link JiraSite}. * @@ -67,7 +65,7 @@ public DescriptorImpl getDescriptor() { public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); public static final class DescriptorImpl extends JobPropertyDescriptor { - private final CopyOnWriteList sites = new CopyOnWriteList(); + private final CopyOnWriteList sites = new CopyOnWriteList<>(); public DescriptorImpl() { super(JiraProjectProperty.class); diff --git a/src/main/java/hudson/plugins/jira/JiraRestService.java b/src/main/java/hudson/plugins/jira/JiraRestService.java index de86a5e22..d5b5a65ac 100644 --- a/src/main/java/hudson/plugins/jira/JiraRestService.java +++ b/src/main/java/hudson/plugins/jira/JiraRestService.java @@ -17,7 +17,21 @@ import com.atlassian.jira.rest.client.api.JiraRestClient; import com.atlassian.jira.rest.client.api.RestClientException; -import com.atlassian.jira.rest.client.api.domain.*; +import com.atlassian.jira.rest.client.api.domain.BasicIssue; +import com.atlassian.jira.rest.client.api.domain.BasicProject; +import com.atlassian.jira.rest.client.api.domain.BasicUser; +import com.atlassian.jira.rest.client.api.domain.Comment; +import com.atlassian.jira.rest.client.api.domain.Component; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.IssueFieldId; +import com.atlassian.jira.rest.client.api.domain.IssueType; +import com.atlassian.jira.rest.client.api.domain.Permissions; +import com.atlassian.jira.rest.client.api.domain.Priority; +import com.atlassian.jira.rest.client.api.domain.SearchResult; +import com.atlassian.jira.rest.client.api.domain.Status; +import com.atlassian.jira.rest.client.api.domain.Transition; +import com.atlassian.jira.rest.client.api.domain.User; +import com.atlassian.jira.rest.client.api.domain.Version; import com.atlassian.jira.rest.client.api.domain.input.IssueInput; import com.atlassian.jira.rest.client.api.domain.input.IssueInputBuilder; import com.atlassian.jira.rest.client.api.domain.input.TransitionInput; @@ -47,7 +61,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import static java.util.logging.Level.FINE; import static java.util.logging.Level.WARNING; public class JiraRestService { @@ -177,7 +194,7 @@ public List getIssuesFromJqlSearch(String jqlSearch, Integer maxResults) .get(timeout, TimeUnit.SECONDS); return Lists.newArrayList(searchResult.getIssues()); } catch(TimeoutException e) { - LOGGER.log(WARNING, "jira rest client get issue from jql search error. cause: " + e.getMessage(), e); + LOGGER.log(WARNING, "jira rest client timeout from jql search error. cause: " + e.getMessage(), e); throw e; } catch (Exception e) { LOGGER.log(WARNING, "jira rest client get issue from jql search error. cause: " + e.getMessage(), e); @@ -202,15 +219,13 @@ public List getVersions(String projectKey) { LOGGER.log(WARNING, "jira rest client get versions error. cause: " + e.getMessage(), e); } - final List versions = new ArrayList<>(); - for (Map decodedVersion : decoded) { + return decoded.stream().map( decodedVersion -> { final DateTime releaseDate = decodedVersion.containsKey("releaseDate") ? DATE_TIME_FORMATTER.parseDateTime((String) decodedVersion.get("releaseDate")) : null; - final Version version = new Version(URI.create((String) decodedVersion.get("self")), Long.parseLong((String) decodedVersion.get("id")), - (String) decodedVersion.get("name"), (String) decodedVersion.get("description"), (Boolean) decodedVersion.get("archived"), - (Boolean) decodedVersion.get("released"), releaseDate); - versions.add(version); - } - return versions; + return new Version(URI.create((String) decodedVersion.get("self")), Long.parseLong((String) decodedVersion.get("id")), + (String) decodedVersion.get("name"), (String) decodedVersion.get("description"), (Boolean) decodedVersion.get("archived"), + (Boolean) decodedVersion.get("released"), releaseDate); + } ).collect( Collectors.toList() ); + } diff --git a/src/main/java/hudson/plugins/jira/JiraSession.java b/src/main/java/hudson/plugins/jira/JiraSession.java index 5b6a4fa7a..9be2f0f6a 100644 --- a/src/main/java/hudson/plugins/jira/JiraSession.java +++ b/src/main/java/hudson/plugins/jira/JiraSession.java @@ -1,24 +1,31 @@ package hudson.plugins.jira; -import com.atlassian.jira.rest.client.api.domain.*; -import com.google.common.collect.Lists; +import com.atlassian.jira.rest.client.api.domain.BasicIssue; +import com.atlassian.jira.rest.client.api.domain.Component; +import com.atlassian.jira.rest.client.api.domain.Issue; +import com.atlassian.jira.rest.client.api.domain.IssueType; +import com.atlassian.jira.rest.client.api.domain.Permissions; +import com.atlassian.jira.rest.client.api.domain.Priority; +import com.atlassian.jira.rest.client.api.domain.Status; +import com.atlassian.jira.rest.client.api.domain.Transition; +import com.atlassian.jira.rest.client.api.domain.Version; +import hudson.plugins.jira.model.JiraIssueField; +import org.apache.commons.lang.StringUtils; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import hudson.plugins.jira.model.JiraIssueField; -import java.util.concurrent.TimeoutException; -import org.apache.commons.lang.StringUtils; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import static org.apache.commons.lang.StringUtils.isNotEmpty; /** @@ -39,14 +46,11 @@ public class JiraSession { */ private Set projectKeys; - /** - * This session is created for this site. - */ - private final JiraSite site; + private final String jiraSiteName; /* package */JiraSession(JiraSite site, JiraRestService jiraRestService) { - this.site = site; this.service = jiraRestService; + this.jiraSiteName = site.getName(); } /** @@ -56,10 +60,9 @@ public class JiraSession { */ public Set getProjectKeys() { if (projectKeys == null) { - LOGGER.fine("Fetching remote project key list from " + site.getName()); + LOGGER.fine("Fetching remote project key list from " + jiraSiteName); final List keys = service.getProjectsKeys(); - projectKeys = new HashSet<>(keys.size()); - projectKeys.addAll(keys); + projectKeys = new HashSet<>(keys); LOGGER.fine("Project list=" + projectKeys); } return projectKeys; @@ -84,7 +87,7 @@ public void addComment(String issueId, String comment, * @param labels New labels to add. */ public void addLabels(String issueId, List labels) { - List newLabels = Lists.newArrayList(); + List newLabels = new ArrayList(); Issue existingIssue = service.getIssue(issueId); if(existingIssue.getLabels() != null) { newLabels.addAll(existingIssue.getLabels()); @@ -140,7 +143,6 @@ public List getIssuesFromJqlSearch(final String jqlSearch) throws Timeout */ public List getVersions(String projectKey) { LOGGER.fine("Fetching versions from project: " + projectKey); - return service.getVersions(projectKey); } @@ -229,10 +231,10 @@ public void migrateIssuesToFixVersion(String projectKey, String version, String } LOGGER.fine("Found issues: " + issues.size()); - for (Issue issue : issues) { + issues.stream().forEach( issue -> { LOGGER.fine("Migrating issue: " + issue.getKey()); - service.updateIssue(issue.getKey(), Lists.newArrayList(newVersion)); - } + service.updateIssue( issue.getKey(), Collections.singletonList(newVersion)); + } ); } /** @@ -285,7 +287,7 @@ public void replaceFixVersion(String projectKey, String fromVersion, String toVe } LOGGER.fine("Replacing version in issue: " + issue.getKey()); - service.updateIssue(issue.getKey(), Lists.newArrayList(newVersions)); + service.updateIssue(issue.getKey(), new ArrayList(newVersions)); } } @@ -313,7 +315,8 @@ public void addFixVersion(String projectKey, String version, String query) throw for (Issue issue : issues) { LOGGER.fine("Adding version: " + newVersion.getName() + " to issue: " + issue.getKey()); - List fixVersions = Lists.newArrayList(issue.getFixVersions()); + List fixVersions = new ArrayList<>(); + issue.getFixVersions().forEach(fixVersions::add); fixVersions.add(newVersion); service.updateIssue(issue.getKey(), fixVersions); } @@ -384,9 +387,7 @@ private Map getKnownStatuses() { if (knownStatuses == null) { List statuses = service.getStatuses(); knownStatuses = new HashMap<>(statuses.size()); - for (Status status : statuses) { - knownStatuses.put(status.getId(), status.getName()); - } + statuses.stream().forEach( status -> knownStatuses.put(status.getId(), status.getName())); } return knownStatuses; } @@ -458,4 +459,6 @@ public Version addVersion(String version, String projectKey) { */ public Permissions getMyPermissions(){ return service.getMyPermissions(); } + + } diff --git a/src/main/java/hudson/plugins/jira/JiraSite.java b/src/main/java/hudson/plugins/jira/JiraSite.java index 7f6388706..4853113ac 100644 --- a/src/main/java/hudson/plugins/jira/JiraSite.java +++ b/src/main/java/hudson/plugins/jira/JiraSite.java @@ -1,10 +1,22 @@ package hudson.plugins.jira; +import com.atlassian.event.api.EventPublisher; +import com.atlassian.httpclient.apache.httpcomponents.DefaultHttpClientFactory; +import com.atlassian.httpclient.api.HttpClient; +import com.atlassian.httpclient.api.factory.HttpClientOptions; +import com.atlassian.jira.rest.client.api.AuthenticationHandler; import com.atlassian.jira.rest.client.api.JiraRestClient; +import com.atlassian.jira.rest.client.api.JiraRestClientFactory; import com.atlassian.jira.rest.client.api.RestClientException; import com.atlassian.jira.rest.client.api.domain.Issue; import com.atlassian.jira.rest.client.api.domain.Version; -import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory; +import com.atlassian.jira.rest.client.auth.BasicHttpAuthenticationHandler; +import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClient; +import com.atlassian.jira.rest.client.internal.async.AtlassianHttpClientDecorator; +import com.atlassian.jira.rest.client.internal.async.DisposableHttpClient; +import com.atlassian.sal.api.ApplicationProperties; +import com.atlassian.sal.api.UrlMode; +import com.atlassian.sal.api.executor.ThreadLocalContextManager; import com.cloudbees.hudson.plugins.folder.AbstractFolder; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardUsernameListBoxModel; @@ -25,8 +37,6 @@ import hudson.plugins.jira.model.JiraIssue; import hudson.security.ACL; import hudson.security.AccessControlled; -import hudson.security.AccessDeniedException2; -import hudson.security.Permission; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import hudson.util.Secret; @@ -38,7 +48,9 @@ import org.kohsuke.stapler.interceptor.RequirePOST; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.net.MalformedURLException; @@ -46,21 +58,25 @@ import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; -import static hudson.model.Item.CONFIGURE; import static org.apache.commons.lang.StringUtils.isEmpty; import static org.apache.commons.lang.StringUtils.isNotEmpty; @@ -87,6 +103,10 @@ public class JiraSite extends AbstractDescribableImpl { * See issue JENKINS-31113 */ public static final int DEFAULT_TIMEOUT = 10; + + public static final int DEFAULT_READ_TIMEOUT = 30; + + public static final int DEFAULT_THREAD_EXECUTOR_NUMBER = 10; /** * URL of JIRA for Jenkins access, like http://jira.codehaus.org/. @@ -108,7 +128,7 @@ public class JiraSite extends AbstractDescribableImpl { /** * The id of the credentials to use. Optional. */ - public final String credentialsId; + public String credentialsId; /** * Transient stash of the credentials to use, mostly just for providing floating user object. @@ -175,9 +195,21 @@ public class JiraSite extends AbstractDescribableImpl { public final boolean updateJiraIssueForAllStatus; /** - * timeout used when calling jira rest api, in seconds + * connection timeout used when calling jira rest api, in seconds + */ + public int timeout = DEFAULT_TIMEOUT; + + /** + * response timeout for jira rest call + * @since 3.0.3 */ - public Integer timeout; + private int readTimeout = DEFAULT_READ_TIMEOUT; + + /** + * thread pool number + * @since 3.0.3 + */ + private int threadExecutorNumber = DEFAULT_THREAD_EXECUTOR_NUMBER; /** * Configuration for formatting (date -> text) in jira comments. @@ -207,7 +239,10 @@ public class JiraSite extends AbstractDescribableImpl { private transient JiraSession jiraSession; - @DataBoundConstructor + private transient ExecutorService executorService; + + // Deprecate the previous constructor but leave it in place for Java-level compatibility. + @Deprecated public JiraSite(URL url, @CheckForNull URL alternativeUrl, @CheckForNull String credentialsId, boolean supportsWikiStyleComment, boolean recordScmChanges, @CheckForNull String userPattern, boolean updateJiraIssueForAllStatus, @CheckForNull String groupVisibility, @CheckForNull String roleVisibility, boolean useHTTPAuth) { this(url, alternativeUrl, CredentialsHelper.lookupSystemCredentials(credentialsId, url), supportsWikiStyleComment, recordScmChanges, userPattern, @@ -222,8 +257,23 @@ public JiraSite(URL url, @CheckForNull URL alternativeUrl, String userName, Stri updateJiraIssueForAllStatus, groupVisibility, roleVisibility, useHTTPAuth); } + // Deprecate the previous constructor but leave it in place for Java-level compatibility. + @Deprecated public JiraSite(URL url, URL alternativeUrl, StandardUsernamePasswordCredentials credentials, boolean supportsWikiStyleComment, boolean recordScmChanges, String userPattern, boolean updateJiraIssueForAllStatus, String groupVisibility, String roleVisibility, boolean useHTTPAuth) { + this( url, alternativeUrl, credentials, supportsWikiStyleComment, recordScmChanges, userPattern, updateJiraIssueForAllStatus, + groupVisibility, roleVisibility, useHTTPAuth, DEFAULT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_THREAD_EXECUTOR_NUMBER); + } + + @DataBoundConstructor + public JiraSite(URL url, URL alternativeUrl, String credentialsId, boolean supportsWikiStyleComment, boolean recordScmChanges, String userPattern, + boolean updateJiraIssueForAllStatus, String groupVisibility, String roleVisibility, boolean useHTTPAuth, int timeout, int readTimeout, int threadExecutorNumber){ + this(url, alternativeUrl, CredentialsHelper.lookupSystemCredentials(credentialsId, url), supportsWikiStyleComment, recordScmChanges, userPattern, + updateJiraIssueForAllStatus, groupVisibility, roleVisibility, useHTTPAuth, timeout, readTimeout, threadExecutorNumber); + } + + public JiraSite(URL url, URL alternativeUrl, StandardUsernamePasswordCredentials credentials, boolean supportsWikiStyleComment, boolean recordScmChanges, String userPattern, + boolean updateJiraIssueForAllStatus, String groupVisibility, String roleVisibility, boolean useHTTPAuth, int timeout, int readTimeout, int threadExecutorNumber) { if (url != null && !url.toExternalForm().endsWith("/")) try { url = new URL(url.toExternalForm() + "/"); @@ -239,7 +289,9 @@ public JiraSite(URL url, URL alternativeUrl, StandardUsernamePasswordCredentials } this.url = url; - this.timeout = JiraSite.DEFAULT_TIMEOUT; + this.timeout = timeout; + this.readTimeout = readTimeout; + this.threadExecutorNumber = threadExecutorNumber; this.alternativeUrl = alternativeUrl; this.credentials = credentials; @@ -271,20 +323,56 @@ public boolean getDisableChangelogAnnotations() { } /** - * Sets request timeout (in seconds). + * Sets connect timeout (in seconds). * If not specified, a default timeout will be used. * @param timeoutSec Timeout in seconds */ @DataBoundSetter - public void setTimeout(Integer timeoutSec) { + public void setTimeout(int timeoutSec) { this.timeout = timeoutSec; } - + + public int getTimeout() { + return timeout; + } + + /** + * Sets read timeout (in seconds). + * If not specified, a default timeout will be used. + * @param readTimeout Timeout in seconds + */ + @DataBoundSetter + public void setReadTimeout( int readTimeout ) { + this.readTimeout = readTimeout; + } + + public int getReadTimeout() { + return readTimeout; + } + + public String getCredentialsId() { + return credentialsId; + } + + @DataBoundSetter + public void setCredentialsId(String credentialsId) { + this.credentialsId = credentialsId; + } + @DataBoundSetter public void setDateTimePattern(String dateTimePattern) { this.dateTimePattern = dateTimePattern; } - + + @DataBoundSetter + public void setThreadExecutorNumber( int threadExecutorNumber ) { + this.threadExecutorNumber = threadExecutorNumber; + } + + public int getThreadExecutorNumber() { + return threadExecutorNumber; + } + @DataBoundSetter public void setAppendChangeTimestamp(Boolean appendChangeTimestamp) { this.appendChangeTimestamp = appendChangeTimestamp; @@ -305,7 +393,7 @@ protected Object readResolve() { updateJiraIssueForAllStatus, groupVisibility, roleVisibility, useHTTPAuth); } return new JiraSite(url, alternativeUrl, credentialsId, supportsWikiStyleComment, recordScmChanges, userPattern, - updateJiraIssueForAllStatus, groupVisibility, roleVisibility, useHTTPAuth); + updateJiraIssueForAllStatus, groupVisibility, roleVisibility, useHTTPAuth, timeout, readTimeout, threadExecutorNumber); } private static Cache> makeIssueCache() { @@ -353,12 +441,198 @@ protected JiraSession createSession() { String userName = credentials.getUsername(); Secret password = credentials.getPassword(); + final HttpClientOptions options = new HttpClientOptions(); + options.setRequestTimeout(readTimeout, TimeUnit.SECONDS); + options.setSocketTimeout(timeout, TimeUnit.SECONDS); + + if (executorService==null){ + executorService = Executors.newFixedThreadPool( + threadExecutorNumber, // + new ThreadFactory() + { + final AtomicInteger threadNumber = new AtomicInteger( 0 ); + + @Override + public Thread newThread( Runnable r ) + { + return new Thread( r, "jira-plugin-http-request-" + threadNumber.getAndIncrement() + "-thread" ); + } + } ); + } + + options.setCallbackExecutor(executorService); + final JiraRestClient jiraRestClient = new AsynchronousJiraRestClientFactory() - .createWithBasicHttpAuthentication(uri, userName, password.getPlainText()); - int usedTimeout = timeout != null ? timeout : JiraSite.DEFAULT_TIMEOUT; - return new JiraSession(this, new JiraRestService(uri, jiraRestClient, userName, password.getPlainText(), usedTimeout)); + .create(uri, new BasicHttpAuthenticationHandler( userName, password.getPlainText()),options); + return new JiraSession(this, new JiraRestService(uri, jiraRestClient, userName, password.getPlainText(), readTimeout)); + } + + //----------------------------------------------------------------------------------- + // internal classes we want to override + //----------------------------------------------------------------------------------- + + private static class AsynchronousJiraRestClientFactory implements JiraRestClientFactory + { + + public JiraRestClient create(final URI serverUri, final AuthenticationHandler authenticationHandler, HttpClientOptions options) { + final DisposableHttpClient httpClient = createClient(serverUri, authenticationHandler, options); + return new AsynchronousJiraRestClient( serverUri, httpClient); + } + + @Override + public JiraRestClient create(final URI serverUri, final AuthenticationHandler authenticationHandler) { + final DisposableHttpClient httpClient = createClient(serverUri, authenticationHandler, new HttpClientOptions()); + return new AsynchronousJiraRestClient( serverUri, httpClient); + } + + @Override + public JiraRestClient createWithBasicHttpAuthentication(final URI serverUri, final String username, final String password) { + return create(serverUri, new BasicHttpAuthenticationHandler( username, password)); + } + + @Override + public JiraRestClient createWithAuthenticationHandler(final URI serverUri, final AuthenticationHandler authenticationHandler) { + return create(serverUri, authenticationHandler); + } + + @Override + public JiraRestClient create(final URI serverUri, final HttpClient httpClient) { + final DisposableHttpClient disposableHttpClient = createClient(httpClient); + return new AsynchronousJiraRestClient(serverUri, disposableHttpClient); + } } + private static DisposableHttpClient createClient(final URI serverUri, final AuthenticationHandler authenticationHandler, HttpClientOptions options) { + + final DefaultHttpClientFactory + defaultHttpClientFactory = new DefaultHttpClientFactory( new NoOpEventPublisher(), + new RestClientApplicationProperties( serverUri), + new ThreadLocalContextManager() { + @Override + public Object getThreadLocalContext() { + return null; + } + + @Override + public void setThreadLocalContext(Object context) { + } + + @Override + public void clearThreadLocalContext() { + } + }); + + final HttpClient httpClient = defaultHttpClientFactory.create(options); + + return new AtlassianHttpClientDecorator( httpClient, authenticationHandler) { + @Override + public void destroy() throws Exception { + defaultHttpClientFactory.dispose(httpClient); + } + }; + } + + private static DisposableHttpClient createClient(final HttpClient client) { + return new AtlassianHttpClientDecorator(client, null) { + @Override + public void destroy() throws Exception { + // This should never be implemented. This is simply creation of a wrapper + // for AtlassianHttpClient which is extended by a destroy method. + // Destroy method should never be called for AtlassianHttpClient coming from + // a client! Imagine you create a RestClient, pass your own HttpClient there + // and it gets destroy. + } + }; + } + + private static class NoOpEventPublisher implements EventPublisher + { + @Override + public void publish(Object o) { + } + + @Override + public void register(Object o) { + } + + @Override + public void unregister(Object o) { + } + + @Override + public void unregisterAll() { + } + } + + @SuppressWarnings("deprecation") + private static class RestClientApplicationProperties implements ApplicationProperties + { + + private final String baseUrl; + + private RestClientApplicationProperties(URI jiraURI) { + this.baseUrl = jiraURI.getPath(); + } + + @Override + public String getBaseUrl() { + return baseUrl; + } + + /** + * We'll always have an absolute URL as a client. + */ + @Nonnull + @Override + public String getBaseUrl( UrlMode urlMode) { + return baseUrl; + } + + @Nonnull + @Override + public String getDisplayName() { + return "Atlassian JIRA Rest Java Client"; + } + + @Nonnull + @Override + public String getPlatformId() { + return ApplicationProperties.PLATFORM_JIRA; + } + + @Nonnull + @Override + public String getVersion() { + return ""; + } + + @Nonnull + @Override + public Date getBuildDate() { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public String getBuildNumber() { + return String.valueOf(0); + } + + @Override + public File getHomeDirectory() { + return new File("."); + } + + @Override + public String getPropertyValue(final String s) { + throw new UnsupportedOperationException("Not implemented"); + } + } + + //----------------------------------------------------------------------------------- + // + //----------------------------------------------------------------------------------- + /** * @return the server URL */ @@ -704,6 +978,16 @@ public boolean progressMatchingIssues(String jqlSearch, String workflowActionNam return success; } + public void destroy() { + try { + if(this.executorService!=null&&!this.executorService.isShutdown()){ + this.executorService.shutdownNow(); + } + } catch ( Exception e ) { + LOGGER.log(Level.INFO, "skip error stopping executorService:" + e.getMessage(), e ); + } + } + @Extension public static class DescriptorImpl extends Descriptor { @Override @@ -721,7 +1005,9 @@ public FormValidation doValidate(@QueryParameter String url, @QueryParameter String roleVisibility, @QueryParameter boolean useHTTPAuth, @QueryParameter String alternativeUrl, - @QueryParameter Integer timeout, + @QueryParameter int timeout, + @QueryParameter int readTimeout, + @QueryParameter int threadExecutorNumber, @AncestorInPath Item item) { if (item == null) { @@ -761,13 +1047,20 @@ public FormValidation doValidate(@QueryParameter String url, .withUseHTTPAuth(useHTTPAuth) .build(); - site.setTimeout(timeout); + site.setTimeout(timeout==0?DEFAULT_TIMEOUT:timeout); + site.setReadTimeout(readTimeout==0?DEFAULT_READ_TIMEOUT:readTimeout); + site.setThreadExecutorNumber(threadExecutorNumber==0?DEFAULT_THREAD_EXECUTOR_NUMBER:threadExecutorNumber); + try { JiraSession session = site.createSession(); session.getMyPermissions(); return FormValidation.ok("Success"); } catch (RestClientException e) { LOGGER.log(Level.WARNING, "Failed to login to JIRA at " + url, e); + } finally { + if(site!=null){ + site.destroy(); + } } return FormValidation.error("Failed to login to JIRA"); diff --git a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java index 21e0185f1..0aff4131a 100644 --- a/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java +++ b/src/main/java/hudson/plugins/jira/JiraVersionCreatorBuilder.java @@ -14,8 +14,6 @@ import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; -import java.io.IOException; - /** * A build step which creates new JIRA version. It has the same functionality as * {@link JiraVersionCreator} but can be used multiple times in the same build diff --git a/src/main/java/hudson/plugins/jira/Updater.java b/src/main/java/hudson/plugins/jira/Updater.java index f2b05a09b..5645434b6 100755 --- a/src/main/java/hudson/plugins/jira/Updater.java +++ b/src/main/java/hudson/plugins/jira/Updater.java @@ -244,7 +244,6 @@ private String createComment(Run build, boolean wikiStyle, String jenkinsR private String getScmComments(boolean wikiStyle, Run run, boolean recordScmChanges, JiraIssue jiraIssue) { StringBuilder comment = new StringBuilder(); - RepositoryBrowser repoBrowser = getRepositoryBrowser(run); for (ChangeLogSet set : RunScmChangeExtractor.getChanges(run)) { for (Entry change : set) { if (jiraIssue != null && !StringUtils.containsIgnoreCase(change.getMsg(), jiraIssue.getKey())) { diff --git a/src/main/java/hudson/plugins/jira/pipeline/IssueFieldUpdateStep.java b/src/main/java/hudson/plugins/jira/pipeline/IssueFieldUpdateStep.java index 24af07dbb..b1f77c077 100644 --- a/src/main/java/hudson/plugins/jira/pipeline/IssueFieldUpdateStep.java +++ b/src/main/java/hudson/plugins/jira/pipeline/IssueFieldUpdateStep.java @@ -1,7 +1,6 @@ package hudson.plugins.jira.pipeline; import com.atlassian.jira.rest.client.api.RestClientException; -import com.google.common.collect.Lists; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; @@ -26,6 +25,7 @@ import javax.servlet.ServletException; import java.io.IOException; import java.io.PrintStream; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -115,7 +115,7 @@ public void perform(Run run, FilePath workspace, Launcher launcher, TaskLi return; } - List fields = Lists.newArrayList(); + List fields = new ArrayList(); fields.add(new JiraIssueField(prepareFieldId(fieldId), fieldValue)); for (String issue : issues) { diff --git a/src/main/java/hudson/plugins/jira/pipeline/IssueSelectorStep.java b/src/main/java/hudson/plugins/jira/pipeline/IssueSelectorStep.java index 09ebe01e8..adbaf0a7f 100644 --- a/src/main/java/hudson/plugins/jira/pipeline/IssueSelectorStep.java +++ b/src/main/java/hudson/plugins/jira/pipeline/IssueSelectorStep.java @@ -51,7 +51,7 @@ public DescriptorImpl() { } public Collection> getApplicableDescriptors() { - return Jenkins.getInstance().>getDescriptorList(AbstractIssueSelector.class); + return Jenkins.getInstance().getDescriptorList(AbstractIssueSelector.class); } @Override diff --git a/src/main/java/hudson/plugins/jira/selector/ExplicitIssueSelector.java b/src/main/java/hudson/plugins/jira/selector/ExplicitIssueSelector.java index 6290433f3..6a111defa 100644 --- a/src/main/java/hudson/plugins/jira/selector/ExplicitIssueSelector.java +++ b/src/main/java/hudson/plugins/jira/selector/ExplicitIssueSelector.java @@ -1,23 +1,21 @@ package hudson.plugins.jira.selector; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import javax.annotation.CheckForNull; - import hudson.Extension; import hudson.model.Descriptor; +import hudson.model.Run; +import hudson.model.TaskListener; +import hudson.plugins.jira.JiraSite; import hudson.plugins.jira.Messages; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import hudson.model.Run; -import hudson.model.TaskListener; -import hudson.plugins.jira.JiraSite; +import javax.annotation.CheckForNull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class ExplicitIssueSelector extends AbstractIssueSelector { @@ -27,7 +25,7 @@ public class ExplicitIssueSelector extends AbstractIssueSelector { @DataBoundConstructor public ExplicitIssueSelector(String issueKeys) { - this.jiraIssueKeys = StringUtils.isNotBlank(issueKeys) ? Lists.newArrayList(issueKeys.split(",")) : Collections.emptyList(); + this.jiraIssueKeys = StringUtils.isNotBlank(issueKeys) ? Arrays.asList(issueKeys.split(",")) : Collections.emptyList(); this.issueKeys = issueKeys; } @@ -36,12 +34,12 @@ public ExplicitIssueSelector(List jiraIssueKeys) { } public ExplicitIssueSelector(){ - this.jiraIssueKeys = Collections.emptyList(); + this.jiraIssueKeys = Collections.emptyList(); } public void setIssueKeys(String issueKeys){ this.issueKeys = issueKeys; - this.jiraIssueKeys = Lists.newArrayList(issueKeys.split(",")); + this.jiraIssueKeys = StringUtils.isNotBlank(issueKeys) ? Arrays.asList(issueKeys.split( ",")):new ArrayList<>( ); } public String getIssueKeys(){ @@ -50,7 +48,7 @@ public String getIssueKeys(){ @Override public Set findIssueIds(Run run, JiraSite site, TaskListener listener) { - return Sets.newHashSet(jiraIssueKeys); + return new HashSet( jiraIssueKeys); } @Extension diff --git a/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterDefinition.java b/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterDefinition.java index eb0babe26..d9bab8b92 100644 --- a/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterDefinition.java +++ b/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterDefinition.java @@ -3,7 +3,6 @@ import com.atlassian.jira.rest.client.api.domain.Version; import hudson.Extension; import hudson.cli.CLICommand; -import hudson.model.AbstractProject; import hudson.model.Job; import hudson.model.ParameterDefinition; import hudson.model.ParameterValue; @@ -16,10 +15,12 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class JiraVersionParameterDefinition extends ParameterDefinition { private static final long serialVersionUID = 4232979892748310160L; @@ -69,17 +70,11 @@ public List getVersions() throws IOExcept JiraSession session = site.getSession(); if (session == null) throw new IllegalStateException("Remote access for JIRA isn't configured in Jenkins"); - List versions = session.getVersions(projectKey); - SortedSet orderedVersions = new TreeSet<>(new VersionComparator()); - orderedVersions.addAll(versions); - - List projectVersions = new ArrayList<>(); - - for (Version version : orderedVersions) { - if (match(version)) projectVersions.add(new Result(version)); - } - - return projectVersions; + return session.getVersions(projectKey).stream(). + sorted( VersionComparator.INSTANCE ). + filter( version -> match( version ) ). + map( version -> new Result( version )). + collect( Collectors.toList() ); } private boolean match(Version version) { diff --git a/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterValue.java b/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterValue.java index 62202cb03..f80e71942 100644 --- a/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterValue.java +++ b/src/main/java/hudson/plugins/jira/versionparameter/JiraVersionParameterValue.java @@ -30,11 +30,7 @@ public void buildEnvironment(final Run run, final EnvVars env) { @Override public VariableResolver createVariableResolver(final AbstractBuild build) { - return new VariableResolver() { - public String resolve(final String name) { - return JiraVersionParameterValue.this.name.equals(name) ? getVersion() : null; - } - }; + return name -> JiraVersionParameterValue.this.name.equals(name) ? getVersion() : null; } public void setVersion(final String version) { diff --git a/src/main/java/hudson/plugins/jira/versionparameter/VersionComparator.java b/src/main/java/hudson/plugins/jira/versionparameter/VersionComparator.java index d1d78a5c8..ed3503e2d 100644 --- a/src/main/java/hudson/plugins/jira/versionparameter/VersionComparator.java +++ b/src/main/java/hudson/plugins/jira/versionparameter/VersionComparator.java @@ -19,6 +19,8 @@ */ public class VersionComparator implements Comparator { + public static VersionComparator INSTANCE = new VersionComparator(); + public int compare(Version rev1, Version rev2) { ComparableVersion comparableVersion1 = new ComparableVersion(getNumberVersion(rev1.getName())); ComparableVersion comparableVersion2 = new ComparableVersion(getNumberVersion(rev2.getName())); diff --git a/src/main/resources/hudson/plugins/jira/JiraSite/config.jelly b/src/main/resources/hudson/plugins/jira/JiraSite/config.jelly index c9370ae70..65dc6f9ca 100644 --- a/src/main/resources/hudson/plugins/jira/JiraSite/config.jelly +++ b/src/main/resources/hudson/plugins/jira/JiraSite/config.jelly @@ -30,6 +30,12 @@ + + + + + + diff --git a/src/main/resources/hudson/plugins/jira/JiraSite/help-readTimeout.html b/src/main/resources/hudson/plugins/jira/JiraSite/help-readTimeout.html new file mode 100644 index 000000000..03ec04502 --- /dev/null +++ b/src/main/resources/hudson/plugins/jira/JiraSite/help-readTimeout.html @@ -0,0 +1,3 @@ +
+Read timeout for JIRA REST API calls (in seconds). +
diff --git a/src/main/resources/hudson/plugins/jira/JiraSite/help-threadExecutorNumber.html b/src/main/resources/hudson/plugins/jira/JiraSite/help-threadExecutorNumber.html new file mode 100644 index 000000000..f58828ec1 --- /dev/null +++ b/src/main/resources/hudson/plugins/jira/JiraSite/help-threadExecutorNumber.html @@ -0,0 +1,3 @@ +
+Size of the thread executor to query Jira. +
diff --git a/src/test/java/JiraTester.java b/src/test/java/JiraTester.java index 89c4993cb..ce03ce3b9 100644 --- a/src/test/java/JiraTester.java +++ b/src/test/java/JiraTester.java @@ -84,5 +84,30 @@ public static void main(String[] args) throws Exception { // final Issue updatedIssue = restService.progressWorkflowAction(issueId, actionId); // System.out.println("Updated issue:" + updatedIssue); + + + for(int i=0;i<10;i++){ + callUniq( restService ); + } + + for(int i=0;i<10;i++){ + callDuplicate( restService ); + } + } + + private static void callUniq(final JiraRestService restService) throws Exception { + long start = System.currentTimeMillis(); + List issues = restService.getIssuesFromJqlSearch( "key in ('JENKINS-53320','JENKINS-51057')", Integer.MAX_VALUE ); + long end = System.currentTimeMillis(); + System.out.println( "time uniq " + (end -start) ); + } + + private static void callDuplicate(final JiraRestService restService) throws Exception { + long start = System.currentTimeMillis(); + List issues = restService.getIssuesFromJqlSearch( "key in ('JENKINS-53320','JENKINS-53320','JENKINS-53320','JENKINS-53320','JENKINS-53320','JENKINS-51057','JENKINS-51057','JENKINS-51057','JENKINS-51057','JENKINS-51057')", Integer.MAX_VALUE ); + long end = System.currentTimeMillis(); + System.out.println( "time duplicate " + (end -start) ); + } + } diff --git a/src/test/java/hudson/plugins/jira/DescriptorImpl2Test.java b/src/test/java/hudson/plugins/jira/DescriptorImpl2Test.java index 8a7f1d051..82b810510 100644 --- a/src/test/java/hudson/plugins/jira/DescriptorImpl2Test.java +++ b/src/test/java/hudson/plugins/jira/DescriptorImpl2Test.java @@ -58,7 +58,10 @@ public void prepareMocks() { @Test public void testValidateConnectionError() throws Exception { when(jiraSession.getMyPermissions()).thenThrow(RestClientException.class); - FormValidation validation = descriptor.doValidate("http://localhost:8080", null, null, null, false, null, JiraSite.DEFAULT_TIMEOUT, r.createFreeStyleProject()); + FormValidation validation = descriptor.doValidate("http://localhost:8080", null, null, + null, false, null, + JiraSite.DEFAULT_TIMEOUT, JiraSite.DEFAULT_READ_TIMEOUT, JiraSite.DEFAULT_THREAD_EXECUTOR_NUMBER, + r.createFreeStyleProject()); verify(descriptor).getJiraSiteBuilder(); verify(builder).build(); @@ -69,7 +72,10 @@ public void testValidateConnectionError() throws Exception { @Test public void testValidateConnectionOK() throws Exception { when(jiraSession.getMyPermissions()).thenReturn(mock(Permissions.class)); - FormValidation validation = descriptor.doValidate("http://localhost:8080", null, null, null, false, null, JiraSite.DEFAULT_TIMEOUT, r.createFreeStyleProject()); + FormValidation validation = descriptor.doValidate("http://localhost:8080", null, null, + null, false, null, + JiraSite.DEFAULT_TIMEOUT, JiraSite.DEFAULT_READ_TIMEOUT, JiraSite.DEFAULT_THREAD_EXECUTOR_NUMBER, + r.createFreeStyleProject()); verify(descriptor).getJiraSiteBuilder(); verify(builder).build(); diff --git a/src/test/java/hudson/plugins/jira/DescriptorImplTest.java b/src/test/java/hudson/plugins/jira/DescriptorImplTest.java index cad678a3f..be8b73a1e 100644 --- a/src/test/java/hudson/plugins/jira/DescriptorImplTest.java +++ b/src/test/java/hudson/plugins/jira/DescriptorImplTest.java @@ -42,16 +42,28 @@ public class DescriptorImplTest { @Test public void testDoValidate() throws Exception { - FormValidation validation = descriptor.doValidate(null, null, null, null, false, null, JiraSite.DEFAULT_TIMEOUT,r.createFreeStyleProject()); + FormValidation validation = descriptor.doValidate(null, null, null, null, + false, null, + JiraSite.DEFAULT_TIMEOUT, JiraSite.DEFAULT_READ_TIMEOUT, JiraSite.DEFAULT_THREAD_EXECUTOR_NUMBER, + r.createFreeStyleProject()); assertEquals(FormValidation.Kind.ERROR, validation.kind); - validation = descriptor.doValidate("invalid", null, null, null, false, null, JiraSite.DEFAULT_TIMEOUT,r.createFreeStyleProject()); + validation = descriptor.doValidate("invalid", null, null, null, + false, null, + JiraSite.DEFAULT_TIMEOUT, JiraSite.DEFAULT_READ_TIMEOUT, JiraSite.DEFAULT_THREAD_EXECUTOR_NUMBER, + r.createFreeStyleProject()); assertEquals(FormValidation.Kind.ERROR, validation.kind); - validation = descriptor.doValidate("http://valid/", null, null, null, false, "invalid", JiraSite.DEFAULT_TIMEOUT,r.createFreeStyleProject()); + validation = descriptor.doValidate("http://valid/", null, null, null, + false, "invalid", + JiraSite.DEFAULT_TIMEOUT, JiraSite.DEFAULT_READ_TIMEOUT, JiraSite.DEFAULT_THREAD_EXECUTOR_NUMBER, + r.createFreeStyleProject()); assertEquals(FormValidation.Kind.ERROR, validation.kind); - validation = descriptor.doValidate("http://valid/", null, null, null, false, " ", JiraSite.DEFAULT_TIMEOUT,r.createFreeStyleProject()); + validation = descriptor.doValidate("http://valid/", null, null, null, + false, " ", + JiraSite.DEFAULT_TIMEOUT, JiraSite.DEFAULT_READ_TIMEOUT, JiraSite.DEFAULT_THREAD_EXECUTOR_NUMBER, + r.createFreeStyleProject()); assertEquals(FormValidation.Kind.ERROR, validation.kind); } diff --git a/src/test/java/hudson/plugins/jira/JiraCreateIssueNotifierTest.java b/src/test/java/hudson/plugins/jira/JiraCreateIssueNotifierTest.java index 496d63e7c..79e0bc5c5 100644 --- a/src/test/java/hudson/plugins/jira/JiraCreateIssueNotifierTest.java +++ b/src/test/java/hudson/plugins/jira/JiraCreateIssueNotifierTest.java @@ -39,7 +39,7 @@ public class JiraCreateIssueNotifierTest { private static final String ASSIGNEE = "user.name"; private static final String DESCRIPTION = "Some description"; - List jiraComponents = new ArrayList(); + List jiraComponents = new ArrayList<>(); Launcher launcher = mock(Launcher.class); BuildListener buildListener = mock(BuildListener.class);