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

com.marvelution.hudson.plugins.apiv2.APIv2Plugin 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.hudson.plugins.apiv2;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.servlet.Filter;
import javax.servlet.ServletException;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import com.google.common.collect.Lists;
import com.marvelution.hudson.plugins.apiv2.cache.activity.ActivitiesCache;
import com.marvelution.hudson.plugins.apiv2.cache.activity.BuildActivityCache;
import com.marvelution.hudson.plugins.apiv2.cache.activity.JobActivityCache;
import com.marvelution.hudson.plugins.apiv2.cache.issue.IssueCache;
import com.marvelution.hudson.plugins.apiv2.cache.issue.IssueKey;
import com.marvelution.hudson.plugins.apiv2.cache.issue.IssuesCache;
import com.marvelution.hudson.plugins.apiv2.servlet.filter.HudsonAPIV2ServletFilter;
import com.marvelution.hudson.plugins.apiv2.threads.IssueIndexingThread;
import com.marvelution.hudson.plugins.apiv2.utils.JiraKeyUtils;
import com.thoughtworks.xstream.XStream;

import hudson.Plugin;
import hudson.model.Hudson;
import hudson.model.Descriptor.FormException;
import hudson.util.CopyOnWriteList;
import hudson.util.FormValidation;
import hudson.util.PluginServletFilter;

/**
 * Main Plugin implementation of the Hudson REST plugin.
 * This class is responsible for the registration of the
 * Wink Application implementation
 * 
 * @author Mark Rekveld
 */
public class APIv2Plugin extends Plugin {

	private static final Logger LOGGER = Logger.getLogger(APIv2Plugin.class.getName());
	private static final XStream XSTREAM = new XStream();
	private static final String APIV2_DIRECTORY_NAME = "APIv2";
	private static final String ACTIVITIES_CACHE_FILE = "activities-cache.xml";
	private static final String ISSUES_CACHE_FILE = "issues-cache.xml";
	private static final String APIV2_ISSUE_KEY_PATTERN = "apiv2.issue.key.pattern";
	private static final String APIV2_PATTERN_KEY = "apiv2.pattern";

	private static APIv2Plugin plugin;

	private transient List filters = Lists.newArrayList();
	private transient ActivitiesCache activitiesCache = new ActivitiesCache();
	private transient IssuesCache issuesCache = new IssuesCache();
	private final CopyOnWriteList patterns = new CopyOnWriteList();

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void start() throws Exception {
		super.start();
		plugin = this;
		load();
		LOGGER.info("Adding the APIv2 Filters");
		filters.add(new HudsonAPIV2ServletFilter());
		for (Filter filter : filters) {
			PluginServletFilter.addFilter(filter);
		}
		LOGGER.info("Loading the Activity Cache");
		File activityCacheFile = getFile(ACTIVITIES_CACHE_FILE);
		if (activityCacheFile.exists()) {
			try {
				activitiesCache = (ActivitiesCache) XSTREAM.fromXML(new FileInputStream(activityCacheFile));
			} catch (Exception e) {
				activitiesCache = new ActivitiesCache();
				LOGGER.severe("Failed to load the " + ACTIVITIES_CACHE_FILE
					+ " and will thus not be available for the REST APIs");
			}
		}
		LOGGER.info("Loading the Issues Cache");
		File issuesCacheFile = getFile(ISSUES_CACHE_FILE);
		if (issuesCacheFile.exists()) {
			try {
				issuesCache = (IssuesCache) XSTREAM.fromXML(new FileInputStream(issuesCacheFile));
			} catch (Exception e) {
				issuesCache = new IssuesCache();
				LOGGER.severe("Failed to load the " + ISSUES_CACHE_FILE
					+ " and will thus not be available for the REST APIs");
			}
		}
		if (StringUtils.isBlank(issuesCache.getIssueKeyRegex())) {
			// Make sure the pattern is set
			issuesCache.setIssueKeyRegex(JiraKeyUtils.DEFAULT_JIRA_ISSUE_KEY_PATTERN.pattern());
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void stop() throws Exception {
		super.stop();
		LOGGER.info("Removing the APIv2 Filters");
		for (Filter filter : filters) {
			PluginServletFilter.removeFilter(filter);
		}
		filters.clear();
		LOGGER.info("Storing the Activity Cache");
		XSTREAM.toXML(activitiesCache, new FileOutputStream(getFile(ACTIVITIES_CACHE_FILE)));
		LOGGER.info("Storing the Issue Cache");
		XSTREAM.toXML(issuesCache, new FileOutputStream(getFile(ISSUES_CACHE_FILE)));
		save();
		plugin = null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void configure(StaplerRequest req, JSONObject formData) throws IOException, ServletException,
					FormException {
		if (req.hasParameter(APIV2_ISSUE_KEY_PATTERN)
				&& StringUtils.isNotBlank(req.getParameter(APIV2_ISSUE_KEY_PATTERN))) {
			issuesCache.setIssueKeyRegex(req.getParameter(APIV2_ISSUE_KEY_PATTERN));
			IssueIndexingThread.invoke();
		}
		String[] newPatterns = req.getParameterValues(APIV2_PATTERN_KEY);
		if (newPatterns != null && !Arrays.equals(newPatterns, patterns.toArray(new String[patterns.size()]))) {
			// TODO Also trigger a full index rescan
			patterns.replaceBy(newPatterns);
			save();
		}
	}

	/**
	 * Web Method to validate a given {@link Pattern}
	 * 
	 * @param value the {@link Pattern} to validate
	 * @return validation result
	 * @throws IOException in case of errors
	 * @throws ServletException in case of errors
	 */
	public FormValidation doCheckPattern(@QueryParameter final String value) throws IOException, ServletException {
		if (!Hudson.getInstance().hasPermission(Hudson.ADMINISTER) || StringUtils.isBlank(value)) {
			return FormValidation.ok();
		}
		try {
			Pattern.compile(value);
			return FormValidation.ok();
		} catch (PatternSyntaxException e) {
			StringBuilder builder = new StringBuilder(e.getDescription());
			if (e.getIndex() >= 0) {
				builder.append(" near index ").append(e.getIndex());
			}
			builder.append("
");
			builder.append(e.getPattern()).append(System.getProperty("line.separator"));
			if (e.getIndex() >= 0) {
				for (int i = 0; i < e.getIndex(); ++i) {
					builder.append(' ');
				}
				builder.append('^');
			}
			builder.append("
"); return FormValidation.errorWithMarkup(builder.toString()); } } /** * Getter for the plugin instance * * @return the {@link APIv2Plugin} plugin instance */ public static APIv2Plugin getPlugin() { return plugin; } /** * Getter for patterns * * @return the patterns */ public String[] getPatterns() { return patterns.toArray(new String[patterns.size()]); } /** * Getter for the pattern used to index issue key * * @return the Issue Key pattern * @since 4.5.0 */ public String getIssueKeyPattern() { return issuesCache.getIssueKeyRegex(); } /** * Getter for the {@link ActivitiesCache} * * @return the {@link ActivitiesCache} */ public static ActivitiesCache getActivitiesCache() { return getPlugin().activitiesCache; } /** * Getter for the {@link IssuesCache} * * @return the {@link IssuesCache} */ public static IssuesCache getIssuesCache() { return getPlugin().issuesCache; } /** * Getter for a {@link File} by name * * @param filename the file name to get * @return the {@link File} */ public File getFile(String filename) { File dir = new File(getConfigXml().getFile().getParent(), APIV2_DIRECTORY_NAME); if (!dir.exists()) { dir.mkdirs(); } return new File(dir, filename); } /** * Initialize the {@link XStream} object */ static { XSTREAM.autodetectAnnotations(true); XSTREAM.processAnnotations(ActivitiesCache.class); XSTREAM.processAnnotations(JobActivityCache.class); XSTREAM.processAnnotations(BuildActivityCache.class); XSTREAM.processAnnotations(IssuesCache.class); XSTREAM.processAnnotations(IssueCache.class); XSTREAM.processAnnotations(IssueKey.class); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy