<commit_before>package com.atlassian.sal.jira.scheduling;

import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.quartz.JobExecutionException;

import com.atlassian.configurable.ObjectConfiguration;
import com.atlassian.configurable.ObjectConfigurationException;
import com.atlassian.configurable.ObjectConfigurationImpl;
import com.atlassian.configurable.StringObjectDescription;
import com.atlassian.jira.service.AbstractService;
import com.atlassian.jira.service.ServiceManager;
import com.atlassian.sal.api.component.ComponentLocator;
import com.atlassian.sal.api.scheduling.PluginJob;
import com.atlassian.sal.api.scheduling.PluginScheduler;
import com.opensymphony.module.propertyset.PropertySet;

public class JiraPluginScheduler implements PluginScheduler
{
    private static final Logger log = Logger.getLogger(JiraPluginScheduler.class);
    private static final String STUDIO_JOB_NAME = "pluginJobName";
    private Map<String, JiraPluginSchedulerServiceDescriptor> serviceMap;
    private ServiceManager serviceManager;

    public JiraPluginScheduler(ServiceManager serviceManager)
    {
        serviceMap = Collections.synchronizedMap(new HashMap<String, JiraPluginSchedulerServiceDescriptor>());
        this.serviceManager = serviceManager;
    }

    public void scheduleJob(String name, Class<? extends PluginJob> job, Map<String, Object> jobDataMap, Date startTime,
        long repeatInterval)
    {
        // Create a map to hold the configuration for the job
        Map serviceDataMap = new HashMap();
        serviceDataMap.put(STUDIO_JOB_NAME, new String[]{name});

        // Put a service descriptor in the map
        JiraPluginSchedulerServiceDescriptor sd = new JiraPluginSchedulerServiceDescriptor();
        sd.setJob(job);
        sd.setJobDataMap(jobDataMap);
        serviceMap.put(name, sd);

        long repeatMinutes = repeatInterval / 60000L;
        try
        {
            serviceManager.addService(name,
                "com.atlassian.sal.jira.scheduling.JiraPluginScheduler$JiraPluginSchedulerService",
                repeatInterval,
                serviceDataMap);
        }
        catch (Exception e)
        {
            log.error("Error adding service to jira", e);
        }
    }

    private JiraPluginSchedulerServiceDescriptor getServiceDescriptor(String name)
    {
        return serviceMap.get(name);
    }

    /**
     * Holds information about a PluginJob for storing in a String to descriptor Map.  This is needed because JIRA
     * services won't allow anything but Strings to be stored in its descriptor map, but we need the Map stored.
     */
    private static class JiraPluginSchedulerServiceDescriptor
    {
        private Class<? extends PluginJob> job;
        private Map jobDataMap;

        public Class<? extends PluginJob> getJob()
        {
            return job;
        }

        public void setJob(Class<? extends PluginJob> job)
        {
            this.job = job;
        }

        public Map getJobDataMap()
        {
            return jobDataMap;
        }

        public void setJobDataMap(Map jobDataMap)
        {
            this.jobDataMap = jobDataMap;
        }
    }

    /**
     * JIRA service that executes a PluginJob
     */
    public static class JiraPluginSchedulerService extends AbstractService
    {
        private static final Logger log = Logger.getLogger(JiraPluginSchedulerService.class);
        private static final Map params = new HashMap();

        static
        {
            params.put(STUDIO_JOB_NAME, null);
        }

        public void run()
        {
            PropertySet props;
            try
            {
                props = getProperties();
            }
            catch (ObjectConfigurationException oce)
            {
                log.error("Error getting properties", oce);
                return;
            }

            String jobName = props.getString(STUDIO_JOB_NAME);

            // Find the descriptor
            JiraPluginScheduler scheduler = (JiraPluginScheduler) ComponentLocator.getComponent(PluginScheduler.class);
            JiraPluginSchedulerServiceDescriptor sd = scheduler.getServiceDescriptor(jobName);

            Class<? extends PluginJob> jobClass = sd.getJob();
            Map jobMap = sd.getJobDataMap();
            PluginJob job;
            try
            {
                job = jobClass.newInstance();
            }
            catch (InstantiationException ie)
            {
                log.error("Error instantiating job", ie);
                return;
            }
            catch (IllegalAccessException iae)
            {
                log.error("Cannot access job class", iae);
                return;
            }
            job.execute(jobMap);
        }

        public ObjectConfiguration getObjectConfiguration() throws ObjectConfigurationException
        {
            ObjectConfiguration oc = new ObjectConfigurationImpl(params, new StringObjectDescription(
                "Plugin Scheduler Service"));
            return oc;
        }

    }
}<commit_msg>JST-821 Fixed multiple plugin job existance and errors when viewing services page<commit_after>package com.atlassian.sal.jira.scheduling;

import java.util.*;

import org.apache.log4j.Logger;

import com.atlassian.configurable.*;
import com.atlassian.jira.service.AbstractService;
import com.atlassian.jira.service.ServiceManager;
import com.atlassian.jira.service.JiraServiceContainer;
import com.atlassian.sal.api.component.ComponentLocator;
import com.atlassian.sal.api.scheduling.PluginJob;
import com.atlassian.sal.api.scheduling.PluginScheduler;
import com.opensymphony.module.propertyset.PropertySet;

public class JiraPluginScheduler implements PluginScheduler
{
    private static final Logger log = Logger.getLogger(JiraPluginScheduler.class);
    private static final String PLUGIN_JOB_NAME = "pluginJobName";
    private Map<String, JiraPluginSchedulerServiceDescriptor> serviceMap;
    private ServiceManager serviceManager;

    public JiraPluginScheduler(ServiceManager serviceManager)
    {
        serviceMap = Collections.synchronizedMap(new HashMap<String, JiraPluginSchedulerServiceDescriptor>());
        this.serviceManager = serviceManager;
    }

    public void scheduleJob(String name, Class<? extends PluginJob> job, Map<String, Object> jobDataMap, Date startTime,
        long repeatInterval)
    {
        // Create a map to hold the configuration for the job
        Map serviceDataMap = new HashMap();
        serviceDataMap.put(PLUGIN_JOB_NAME, new String[]{name});

        // Put a service descriptor in the map
        JiraPluginSchedulerServiceDescriptor sd = new JiraPluginSchedulerServiceDescriptor();
        sd.setJob(job);
        sd.setJobDataMap(jobDataMap);
        serviceMap.put(name, sd);

        long repeatMinutes = repeatInterval / 60000L;
        try
        {
            // Remove the service if it exists.  We use getServices() rather than getServiceWithName() because there was
            // a bug where multiple services with the same name were being created.  getServiceWithName() will throw an
            // exception in that circumstance, so we'll just iterate through them all and delete all the ones that have
            // a matching name.
            Collection<JiraServiceContainer> services = serviceManager.getServices();
            // We have to copy the services into a second map, otherwise after deleting one, we get a
            // ConcurrentModificationException
            services = new HashSet(services);
            for (JiraServiceContainer service : services)
            {
                if (name.equals(service.getName()))
                {
                    serviceManager.removeService(service.getId());
                }
            }
            serviceManager.addService(name,
                "com.atlassian.sal.jira.scheduling.JiraPluginScheduler$JiraPluginSchedulerService",
                repeatInterval,
                serviceDataMap);
        }
        catch (Exception e)
        {
            log.error("Error adding service to jira", e);
        }
    }

    private JiraPluginSchedulerServiceDescriptor getServiceDescriptor(String name)
    {
        return serviceMap.get(name);
    }

    /**
     * Holds information about a PluginJob for storing in a String to descriptor Map.  This is needed because JIRA
     * services won't allow anything but Strings to be stored in its descriptor map, but we need the Map stored.
     */
    private static class JiraPluginSchedulerServiceDescriptor
    {
        private Class<? extends PluginJob> job;
        private Map jobDataMap;

        public Class<? extends PluginJob> getJob()
        {
            return job;
        }

        public void setJob(Class<? extends PluginJob> job)
        {
            this.job = job;
        }

        public Map getJobDataMap()
        {
            return jobDataMap;
        }

        public void setJobDataMap(Map jobDataMap)
        {
            this.jobDataMap = jobDataMap;
        }
    }

    /**
     * JIRA service that executes a PluginJob
     */
    public static class JiraPluginSchedulerService extends AbstractService
    {
        private static final Logger log = Logger.getLogger(JiraPluginSchedulerService.class);
        private static final Map params = new HashMap();

        static
        {
            params.put(PLUGIN_JOB_NAME, new JiraPluginSchedulerServiceProperty());
        }

        public void run()
        {
            PropertySet props;
            try
            {
                props = getProperties();
            }
            catch (ObjectConfigurationException oce)
            {
                log.error("Error getting properties", oce);
                return;
            }

            String jobName = props.getString(PLUGIN_JOB_NAME);

            // Find the descriptor
            JiraPluginScheduler scheduler = (JiraPluginScheduler) ComponentLocator.getComponent(PluginScheduler.class);
            JiraPluginSchedulerServiceDescriptor sd = scheduler.getServiceDescriptor(jobName);

            Class<? extends PluginJob> jobClass = sd.getJob();
            Map jobMap = sd.getJobDataMap();
            PluginJob job;
            try
            {
                job = jobClass.newInstance();
            }
            catch (InstantiationException ie)
            {
                log.error("Error instantiating job", ie);
                return;
            }
            catch (IllegalAccessException iae)
            {
                log.error("Cannot access job class", iae);
                return;
            }
            job.execute(jobMap);
        }

        public ObjectConfiguration getObjectConfiguration() throws ObjectConfigurationException
        {
            ObjectConfiguration oc = new ObjectConfigurationImpl(params, new StringObjectDescription(
                "Plugin Scheduler Service"));
            return oc;
        }

    }

    /**
     * A hidden type, needed because you can't extend an ObjectConfigurationPropertyImpl
     */
    private static class JiraPluginSchedulerServiceProperty extends HashMap implements ObjectConfigurationProperty
    {
        public void init(Map map)
        {
        }

        public String getName()
        {
            return null;
        }

        public String getDescription()
        {
            return null;
        }

        public String getDefault()
        {
            return null;
        }

        public int getType()
        {
            return ObjectConfigurationTypes.HIDDEN;
        }

        public boolean isI18nValues()
        {
            return false;
        }

        public void setI18nValues(boolean b)
        {
        }

        public String getCascadeFrom()
        {
            return null;
        }

        public void setCascadeFrom(String s)
        {
        }

        public boolean isEnabled()
        {
            return false;
        }
    }
}
{'fraction_non_alphanumeric': 0.0705435321328267, 'fraction_numerical': 0.0015694696844539898, 'mean_word_length': 2.121970087674059, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4268490', 'n_tokens_mistral': 3097, 'n_tokens_neox': 2964, 'n_words': 782}