All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.component.jira.JiraEndpoint Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.camel.component.jira;

import java.net.URI;
import java.util.Map;

import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
import org.apache.camel.Category;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.component.jira.consumer.AbstractJiraConsumer;
import org.apache.camel.component.jira.consumer.NewCommentsConsumer;
import org.apache.camel.component.jira.consumer.NewIssuesConsumer;
import org.apache.camel.component.jira.consumer.WatchUpdatesConsumer;
import org.apache.camel.component.jira.oauth.JiraOAuthAuthenticationHandler;
import org.apache.camel.component.jira.oauth.OAuthAsynchronousJiraRestClientFactory;
import org.apache.camel.component.jira.producer.AddCommentProducer;
import org.apache.camel.component.jira.producer.AddIssueLinkProducer;
import org.apache.camel.component.jira.producer.AddIssueProducer;
import org.apache.camel.component.jira.producer.AddWorkLogProducer;
import org.apache.camel.component.jira.producer.AttachFileProducer;
import org.apache.camel.component.jira.producer.DeleteIssueProducer;
import org.apache.camel.component.jira.producer.FetchCommentsProducer;
import org.apache.camel.component.jira.producer.FetchIssueProducer;
import org.apache.camel.component.jira.producer.TransitionIssueProducer;
import org.apache.camel.component.jira.producer.UpdateIssueProducer;
import org.apache.camel.component.jira.producer.WatcherProducer;
import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.Registry;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriPath;
import org.apache.camel.support.ScheduledPollEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.apache.camel.component.jira.JiraConstants.JIRA_REST_CLIENT_FACTORY;

/**
 * Interact with JIRA issue tracker.
 * 

* The endpoint encapsulates portions of the JIRA API, relying on the jira-rest-java-client SDK. Available endpoint URIs * include: *

* CONSUMERS jira://newIssues (retrieve only new issues after the route is started) jira://newComments (retrieve only * new comments after the route is started) jira://watchChanges (retrieve only defined changes in issues picked base on * provided jql) *

* PRODUCERS jira://addIssue (add an issue) jira://addComment (add a comment on a given issue) jira://attach (add an * attachment on a given issue) jira://deleteIssue (delete a given issue) jira://updateIssue (update fields of a given * issue) jira://transitionIssue (transition a status of a given issue) jira://watchers (add/remove watchers of a given * issue) *

* The endpoints will respond with jira-rest-java-client POJOs (Issue, Comment, etc.) *

* Note: Rather than webhooks, this endpoint relies on simple polling. Reasons include: - concerned about * reliability/stability if this somehow relied on an exposed, embedded server (Jetty?) - the types of payloads we're * polling aren't typically large (plus, paging is available in the API) - need to support apps running somewhere not * publicly accessible where a webhook would fail */ @UriEndpoint(firstVersion = "3.0", scheme = "jira", title = "Jira", syntax = "jira:type", category = { Category.DOCUMENT }, headersClass = JiraConstants.class) public class JiraEndpoint extends ScheduledPollEndpoint implements EndpointServiceLocation { private static final Logger LOG = LoggerFactory.getLogger(JiraEndpoint.class); @UriPath @Metadata(required = true) private JiraType type; @UriParam(label = "consumer") private String jql; @UriParam(label = "consumer", defaultValue = "Status,Priority") private String watchedFields = "Status,Priority"; @UriParam(label = "consumer", defaultValue = "true") private boolean sendOnlyUpdatedField = true; @UriParam(label = "consumer", defaultValue = "50") private Integer maxResults = 50; @UriParam private JiraConfiguration configuration; private transient JiraRestClient client; public JiraEndpoint(String uri, JiraComponent component, JiraConfiguration configuration) { super(uri, component); this.configuration = configuration; } @Override public String getServiceUrl() { return configuration.getJiraUrl(); } @Override public String getServiceProtocol() { return "rest"; } @Override public Map getServiceMetadata() { if (configuration.getUsername() != null) { return Map.of("username", configuration.getUsername()); } return null; } public JiraConfiguration getConfiguration() { return configuration; } @Override public void doStart() throws Exception { super.doStart(); connect(); } @Override protected void doStop() throws Exception { super.doStop(); disconnect(); } public void connect() { lock.lock(); try { if (client == null) { Registry registry = getCamelContext().getRegistry(); JiraRestClientFactory factory = registry.lookupByNameAndType(JIRA_REST_CLIENT_FACTORY, JiraRestClientFactory.class); if (factory == null) { factory = new OAuthAsynchronousJiraRestClientFactory(); } final URI jiraServerUri = URI.create(configuration.getJiraUrl()); if (configuration.getUsername() != null) { LOG.debug("Connecting to JIRA with Basic authentication with username/password"); client = factory.createWithBasicHttpAuthentication(jiraServerUri, configuration.getUsername(), configuration.getPassword()); } else if (configuration.getAccessToken() != null && configuration.getVerificationCode() == null && configuration.getPrivateKey() == null && configuration.getConsumerKey() == null) { client = factory.create(jiraServerUri, builder -> { builder.setHeader("Authorization", "Bearer " + configuration.getAccessToken()); }); } else { LOG.debug("Connecting to JIRA with OAuth authentication"); JiraOAuthAuthenticationHandler oAuthHandler = new JiraOAuthAuthenticationHandler( configuration.getConsumerKey(), configuration.getVerificationCode(), configuration.getPrivateKey(), configuration.getAccessToken(), configuration.getJiraUrl()); client = factory.create(jiraServerUri, oAuthHandler); } } } finally { lock.unlock(); } } public void disconnect() throws Exception { lock.lock(); try { if (client != null) { LOG.debug("Disconnecting from JIRA"); client.close(); client = null; } } finally { lock.unlock(); } } @Override public Producer createProducer() { return switch (type) { case ADDISSUE -> new AddIssueProducer(this); case ATTACH -> new AttachFileProducer(this); case ADDCOMMENT -> new AddCommentProducer(this); case WATCHERS -> new WatcherProducer(this); case DELETEISSUE -> new DeleteIssueProducer(this); case UPDATEISSUE -> new UpdateIssueProducer(this); case TRANSITIONISSUE -> new TransitionIssueProducer(this); case ADDISSUELINK -> new AddIssueLinkProducer(this); case ADDWORKLOG -> new AddWorkLogProducer(this); case FETCHISSUE -> new FetchIssueProducer(this); case FETCHCOMMENTS -> new FetchCommentsProducer(this); default -> throw new IllegalArgumentException("Producer does not support type: " + type); }; } @Override public Consumer createConsumer(Processor processor) throws Exception { AbstractJiraConsumer consumer; if (type == JiraType.NEWCOMMENTS) { consumer = new NewCommentsConsumer(this, processor); } else if (type == JiraType.NEWISSUES) { consumer = new NewIssuesConsumer(this, processor); } else if (type == JiraType.WATCHUPDATES) { consumer = new WatchUpdatesConsumer(this, processor); } else { throw new IllegalArgumentException("Consumer does not support type: " + type); } consumer.setMaxMessagesPerPoll(getMaxResults()); configureConsumer(consumer); return consumer; } public JiraType getType() { return type; } /** * Operation to perform. Consumers: NewIssues, NewComments. Producers: AddIssue, AttachFile, DeleteIssue, * TransitionIssue, UpdateIssue, Watchers. See this class javadoc description for more information. */ public void setType(JiraType type) { this.type = type; } /** * JQL is the query language from JIRA which allows you to retrieve the data you want. For example * jql=project=MyProject Where MyProject is the product key in Jira. It is important to use the RAW() and * set the JQL inside it to prevent camel parsing it, example: RAW(project in (MYP, COM) AND resolution = * Unresolved) */ public String getJql() { return jql; } public void setJql(String jql) { this.jql = jql; } public long getDelay() { return configuration.getDelay(); } public JiraRestClient getClient() { // ensure connected connect(); return client; } public void setClient(JiraRestClient client) { this.client = client; } public Integer getMaxResults() { return maxResults; } /** * Max number of issues to search for */ public void setMaxResults(Integer maxResults) { this.maxResults = maxResults; } /** * Comma separated list of fields to watch for changes. "Status,Priority" are the defaults. */ public String getWatchedFields() { return watchedFields; } public void setWatchedFields(String watchChange) { this.watchedFields = watchChange; } /** * Indicator for sending only changed fields in exchange body or issue object. By default consumer sends only * changed fields. */ public boolean isSendOnlyUpdatedField() { return sendOnlyUpdatedField; } public void setSendOnlyUpdatedField(boolean sendOnlyUpdatedField) { this.sendOnlyUpdatedField = sendOnlyUpdatedField; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy