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

com.marvelution.jira.plugins.hudson.streams.HudsonStreamsActivityProvider Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to Marvelution under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Marvelution 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 com.marvelution.jira.plugins.hudson.streams;

import static com.atlassian.streams.spi.StandardStreamsFilterOption.ACTIVITY_KEY;
import static com.atlassian.streams.spi.StandardStreamsFilterOption.USER;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.marvelution.jira.plugins.hudson.streams.HudsonStreamsFilterOptionProvider.HUDSON_ASSOCIATION_KEY;
import static com.marvelution.jira.plugins.hudson.streams.HudsonStreamsFilterOptionProvider.HUDSON_ACTIVITY_OBJECT_TYPE;
import static com.marvelution.jira.plugins.hudson.streams.HudsonStreamsFilterOptionProvider.HUDSON_BASE_ACTIVITY_OBJECT_TYPE;
import static com.marvelution.jira.plugins.hudson.streams.HudsonStreamsFilterOptionProvider.HUDSON_JOB_KEY;
import static com.marvelution.jira.plugins.hudson.streams.HudsonStreamsFilterOptionProvider.HUDSON_SERVER_KEY;

import java.net.URI;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;

import com.atlassian.jira.project.Project;
import com.atlassian.jira.project.ProjectManager;
import com.atlassian.plugin.webresource.UrlMode;
import com.atlassian.plugin.webresource.WebResourceUrlProvider;
import com.atlassian.sal.api.message.I18nResolver;
import com.atlassian.streams.api.ActivityRequest;
import com.atlassian.streams.api.ActivityVerb;
import com.atlassian.streams.api.StreamsEntry;
import com.atlassian.streams.api.StreamsException;
import com.atlassian.streams.api.StreamsFeed;
import com.atlassian.streams.api.UserProfile;
import com.atlassian.streams.api.common.ImmutableNonEmptyList;
import com.atlassian.streams.api.common.Option;
import com.atlassian.streams.spi.CancellableTask;
import com.atlassian.streams.spi.CancelledException;
import com.atlassian.streams.spi.Filters;
import com.atlassian.streams.spi.StandardStreamsFilterOption;
import com.atlassian.streams.spi.StreamsActivityProvider;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.marvelution.hudson.plugins.apiv2.client.ClientException;
import com.marvelution.hudson.plugins.apiv2.client.HudsonClient;
import com.marvelution.hudson.plugins.apiv2.client.services.ActivityQuery;
import com.marvelution.hudson.plugins.apiv2.resources.model.User;
import com.marvelution.hudson.plugins.apiv2.resources.model.activity.Activities;
import com.marvelution.hudson.plugins.apiv2.resources.model.activity.Activity;
import com.marvelution.hudson.plugins.apiv2.resources.model.activity.ActivityType;
import com.marvelution.jira.plugins.hudson.services.associations.HudsonAssociation;
import com.marvelution.jira.plugins.hudson.services.associations.HudsonAssociationManager;
import com.marvelution.jira.plugins.hudson.services.servers.HudsonClientFactory;
import com.marvelution.jira.plugins.hudson.services.servers.HudsonServer;
import com.marvelution.jira.plugins.hudson.services.servers.HudsonServerManager;
import com.marvelution.jira.plugins.hudson.utils.JiraPluginUtils;

/**
 * Hudson specific implementation of the {@link StreamsActivityProvider}
 * 
 * @author Mark Rekveld
 * @since 4.2.0
 */
public class HudsonStreamsActivityProvider implements StreamsActivityProvider {

	private final Logger logger = Logger.getLogger(HudsonStreamsActivityProvider.class);
	private final I18nResolver i18nResolver;
	private final ProjectManager projectManager;
	private final HudsonAssociationManager associationManager;
	private final HudsonServerManager serverManager;
	private final HudsonClientFactory clientFactory;
	private final WebResourceUrlProvider webResourceUrlProvider;

	/**
	 * Constructor
	 *
	 * @param i18nResolver the {@link I18nResolver} implementation
	 * @param projectManager the {@link ProjectManager} implementation
	 * @param associationManager the {@link HudsonAssociationManager} implementation
	 * @param serverManager the {@link HudsonServerManager} implementation
	 * @param clientFactory the {@link HudsonClientFactory} implementation
	 * @param webResourceUrlProvider the {@link WebResourceUrlProvider} implementation
	 */
	public HudsonStreamsActivityProvider(I18nResolver i18nResolver, ProjectManager projectManager,
											HudsonAssociationManager associationManager,
											HudsonServerManager serverManager, HudsonClientFactory clientFactory,
											WebResourceUrlProvider webResourceUrlProvider) {
			this.i18nResolver = checkNotNull(i18nResolver, "i18nResolver");
			this.projectManager = checkNotNull(projectManager, "projectManager");
			this.associationManager = checkNotNull(associationManager, "associationManager");
			this.serverManager = checkNotNull(serverManager, "serverManager");
			this.clientFactory = checkNotNull(clientFactory, "clientFactory");
			this.webResourceUrlProvider = checkNotNull(webResourceUrlProvider, "webResourceUrlProvider");
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public CancellableTask getActivityFeed(final ActivityRequest activityRequest) throws StreamsException {
		return new CancellableTask() {

			final AtomicBoolean cancelled = new AtomicBoolean(false);

			/**
			 * {@inheritDoc}
			 */
			@Override
			public StreamsFeed call() throws Exception {
				Set activityTypes = getActivityFilters(activityRequest);
				Set serverIds;
				Set jobNames;
				Activities activities = new Activities();
				Project project = null;
				if ((project = getProjectFromFilter(activityRequest)) != null) {
					logger.debug("Only getting the associations related to project with key: " + project.getKey());
					serverIds = Sets.newHashSet();
					jobNames = Sets.newHashSet();
					for (HudsonAssociation association : associationManager.getAssociations(project)) {
						serverIds.add(association.getServer().getID());
						jobNames.add(association.getJobName());
					}
				} else {
					if (!activityTypes.contains(ActivityType.JOB)
							&& activityRequest.getProviderFilters().containsKey(HUDSON_ASSOCIATION_KEY)) {
						logger.debug("Processing Association filters to get all the ServerIds and Job Name to get the action for");
						Set associationIds = getAssociationFilters(activityRequest);
						serverIds = Sets.newHashSet();
						jobNames = Sets.newHashSet();
						// Populate the serverIds and JobNames sets from the associations
						for (Integer associationId : associationIds) {
							HudsonAssociation association = associationManager.getAssociation(associationId);
							serverIds.add(association.getServer().getID());
							jobNames.add(association.getJobName());
						}
					} else {
						// Populate the serverIds and JobNames sets from the ActivityRequest
						logger.debug("Processing the Server and Jobs filters from the ActivityReqeust");
						serverIds = getServerFilters(activityRequest);
						jobNames = getJobnameFilters(activityRequest);
					}
				}
				ActivityQuery query = ActivityQuery.createForActivities(activityTypes).setJobs(jobNames)
					.setUserIds(getUsernameFilters(activityRequest)).setMaxResults(activityRequest.getMaxResults());
				logger.debug("Created activity query: " + query.getUrl());
				for (Integer serverId : serverIds) {
					HudsonServer server = serverManager.getServer(serverId);
					// Make sure we only have the servers that the administrator allows in the activity streams
					if (cancelled.get()) {
						throw new CancelledException();
					}
					if (server.isIncludeInStreams()) {
						HudsonClient client = clientFactory.create(server);
						try {
							logger.debug("Connecting to server " + server.getHost()
								+ " to get all the activities matching the query");
							activities.addAll(client.findAll(query));
						} catch (ClientException e) {
							logger.debug("Failed to execute query: " +server.getHost() + query.getUrl());
							throw new StreamsException("Failed to get activities from server " + server.getName(), e);
						}
					} else {
						logger.debug("Skipping server '" + server.getName() + "' in activity streams");
					}
				}
				return new StreamsFeed(i18nResolver.getText("streams.hudson.feed.title"), transformActivities(activities),
					Option.none());
			}

			/**
			 * {@inheritDoc}
			 */
			@Override
			public Result cancel() {
				cancelled.set(true);
				return Result.CANCELLED;
			}

		};
	}

	/**
	 * Transform the given {@link Activities} to {@link StreamsEntry} objects
	 * 
	 * @param activities the {@link Activities} to transform
	 * @return the {@link Iterable} with {@link StreamsEntry} objects
	 */
	private Iterable transformActivities(Activities activities) {
		Iterable entries = Iterables.transform(activities, new Function() {

			/**
			 * {@inheritDoc}
			 */
			@Override
			public StreamsEntry apply(Activity from) {
				return toStreamsEntry(from);
			}

		});
       return entries;
	}

	/**
	 * Transform a given {@link Activity} to a {@link StreamsEntry}
	 * 
	 * @param from the {@link Activity} to transform
	 * @return the {@link StreamsEntry}
	 */
	private StreamsEntry toStreamsEntry(final Activity from) {
		StreamsEntry.ActivityObject activityObject = new StreamsEntry.ActivityObject(StreamsEntry.ActivityObject
			.params().id("").alternateLinkUri(from.getUri()).activityObjectType(HUDSON_ACTIVITY_OBJECT_TYPE));
		ActivityVerb verb = HudsonStreamsFilterOptionProvider.getActivityVerbForActivity(from.getType());
		User user = from.getUser();
		UserProfile.Builder builder = new UserProfile.Builder(user.getUserId()).fullName(user.getUsername())
			.email(Option.option(user.getEmail()))
			.profilePictureUri(Option.option(
				URI.create(webResourceUrlProvider.getStaticPluginResourceUrl(JiraPluginUtils.getPluginKey()
				+ ":hudson-stream-resources", from.getSystem().name().toLowerCase() + "-useravatar.png",
				UrlMode.ABSOLUTE))));
		if (StringUtils.isNotBlank(user.getUrl())) {
			logger.debug(user.getUrl() + ": " + URI.create(user.getUrl()).isAbsolute());
			builder.profilePageUri(Option.option(URI.create(user.getUrl())));
		}
		final StreamsEntry.Renderer renderer = new HudsonStreamsEntryRenderer(i18nResolver, from);;
		return new StreamsEntry(StreamsEntry.params()
			.id(from.getUri())
			.postedDate(new DateTime(from.getTimestamp()))
			.authors(ImmutableNonEmptyList.of(builder.build()))
			.addActivityObject(activityObject).verb(verb)
			.addLink(URI.create(webResourceUrlProvider.getStaticPluginResourceUrl(JiraPluginUtils.getPluginKey()
				+ ":hudson-stream-resources", "puzzle-piece.gif", UrlMode.ABSOLUTE)),
				StreamsActivityProvider.ICON_LINK_REL, Option.none(String.class))
			.alternateLinkUri(from.getUri())
			.renderer(renderer)
			.applicationType(from.getSystem().getHumanName()), i18nResolver);
	}

	/**
	 * Get a single {@link Project} from the Standard Streams Filter
	 * 
	 * @param activityRequest the {@link ActivityRequest}
	 * @return the {@link Project}, may be null
	 */
	private Project getProjectFromFilter(ActivityRequest activityRequest) {
		Set keys =
			Filters.getIsValues(activityRequest.getStandardFilters().get(StandardStreamsFilterOption.PROJECT_KEY));
		if (keys != null && keys.size() == 1) {
			try {
				return projectManager.getProjectObjByKey(keys.toArray(new String[keys.size()])[0]);
			} catch (Exception e) {
				// Ignore this. Just invalid configuration
			}
		}
		return null;
	}

	/**
	 * Get all the active Association Ids from the {@link ActivityRequest}
	 * 
	 * @param activityRequest the {@link ActivityRequest} to get all the association Ids from
	 * @return the {@link Set} of association ids
	 */
	private Set getAssociationFilters(ActivityRequest activityRequest) {
		Set ids = Sets.newHashSet();
		for (HudsonAssociation association : associationManager.getAssociations()) {
			ids.add(association.getID());
		}
		return getFiltersFromActivityRequest(activityRequest, HUDSON_ASSOCIATION_KEY, ids, toInteger);
	}

	/**
	 * Get all the active Server Ids from the {@link ActivityRequest}
	 * 
	 * @param activityRequest the {@link ActivityRequest} to get all the server Ids from
	 * @return the {@link Set} of server ids
	 */
	private Set getServerFilters(ActivityRequest activityRequest) {
		Set ids = Sets.newHashSet();
		for (HudsonServer server : serverManager.getServers()) {
			ids.add(server.getID());
		}
		return getFiltersFromActivityRequest(activityRequest, HUDSON_SERVER_KEY, ids, toInteger);
	}

	/**
	 * Get all the active Job Names from the {@link ActivityRequest}
	 * 
	 * @param activityRequest the {@link ActivityRequest} to get all the Job Names from
	 * @return the {@link Set} of Job Names
	 */
	private Set getUsernameFilters(ActivityRequest activityRequest) {
		Set usernames = Sets.newHashSet(Filters.getIsValues(activityRequest.getProviderFilters().get(
			USER.getKey())));
		Set notValues = Filters.getNotValues(activityRequest.getProviderFilters().get(USER.getKey()));
		for (String value : notValues) {
			usernames.add("!" + value);
		}
		return usernames;
	}

	/**
	 * Get all the active Job Names from the {@link ActivityRequest}
	 * 
	 * @param activityRequest the {@link ActivityRequest} to get all the Job Names from
	 * @return the {@link Set} of Job Names
	 */
	private Set getJobnameFilters(ActivityRequest activityRequest) {
		Set jobs = Sets.newHashSet(Filters.getIsValues(activityRequest.getProviderFilters().get(
			HUDSON_JOB_KEY)));
		Set notValues = Filters.getNotValues(activityRequest.getProviderFilters().get(HUDSON_JOB_KEY));
		for (String value : notValues) {
			jobs.add("!" + value);
		}
		return jobs;
	}

	/**
	 * Get all the active {@link HudsonActivity} objects from the {@link ActivityRequest}
	 * 
	 * @param activityRequest the {@link ActivityRequest} to get the options from
	 * @return the {@link Set} of {@link HudsonActivity} objects
	 */
	private Set getActivityFilters(ActivityRequest activityRequest) {
		return getFiltersFromActivityRequest(activityRequest, ACTIVITY_KEY,
			Sets.newHashSet(ActivityType.values()), toHudsonActivity);
	}

	/**
	 * Get the Provider Filter values out of the {@link ActivityRequest}
	 * 
	 * @param activityRequest the {@link ActivityRequest}
	 * @param key the key of the Provider Filter
	 * @param allItems the default all items for the provider
	 * @param transformer the {@link Function} to use to transform the {@link String} value to the needed value
	 * @return {@link Set} of transformed values
	 */
	private  Set getFiltersFromActivityRequest(ActivityRequest activityRequest, String key, Set allItems,
			Function transformer) {
		Set isStringValues = Filters.getIsValues(activityRequest.getProviderFilters().get(key));
		Set notStringValues = Filters.getNotValues(activityRequest.getProviderFilters().get(key));
		Set isValues;
		if (isStringValues.isEmpty()) {
			isValues = ImmutableSet.copyOf(allItems);
		} else {
			isValues = ImmutableSet.copyOf(Iterables.transform(isStringValues, transformer));
		}
		Set notValues = ImmutableSet.copyOf(Iterables.transform(notStringValues, transformer));
		return Sets.difference(isValues, notValues);
	}

	/**
	 * Converts an activity option key (in the form of a String) to an {@link ActivityType}.
	 */
	private static final Function toHudsonActivity = new Function() {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public ActivityType apply(String option) {
			String hudsonActivity = option.substring((HUDSON_BASE_ACTIVITY_OBJECT_TYPE + ":").length());
			return ActivityType.valueOf(hudsonActivity.replace(" ", "_").toUpperCase());
		}

	};

	/**
	 * Converts an activity option key (in the form of a String) to an {@link Integer}.
	 */
	private static final Function toInteger = new Function() {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Integer apply(String option) {
			return Integer.parseInt(option);
		}

	};

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy