/********************************************************************++ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Management.Automation.Runspaces; using System.IO; using System.Collections; using System.Runtime.Serialization; // Stops compiler from warning about unknown warnings #pragma warning disable 1634, 1691 namespace System.Management.Automation { /// /// Contains the definition of a job which is defined in a /// job store /// /// The actual implementation of this class will /// happen in M2 [Serializable] public class JobDefinition : ISerializable { private string _name; /// /// A friendly Name for this definition /// public String Name { get { return _name; } set { _name = value; } } /// /// The type that derives from JobSourceAdapter /// that contains the logic for invocation and /// management of this type of job. /// public Type JobSourceAdapterType { get; } private string _moduleName; /// /// Module name for the module containing /// the source adapter implementation. /// public string ModuleName { get { return _moduleName; } set { _moduleName = value; } } private string _jobSourceAdapterTypeName; /// /// Job source adapter type name. /// public string JobSourceAdapterTypeName { get { return _jobSourceAdapterTypeName; } set { _jobSourceAdapterTypeName = value; } } /// /// Name of the job that needs to be loaded /// from the specified module /// public String Command { get; } private Guid _instanceId; /// /// Unique Guid for this job definition /// public Guid InstanceId { get { return _instanceId; } set { _instanceId = value; } } /// /// Save this definition to the specified /// file on disk /// /// stream to save to public virtual void Save(Stream stream) { throw new NotImplementedException(); } /// /// Load this definition from the specified /// file on disk /// /// public virtual void Load(Stream stream) { throw new NotImplementedException(); } /// /// Returns information about this job like /// name, definition, parameters etc /// public CommandInfo CommandInfo { get { return null; } } /// /// Public constructor for testing. /// /// Type of adapter to use to create a job. /// the command string. /// the job name. public JobDefinition(Type jobSourceAdapterType, string command, string name) { JobSourceAdapterType = jobSourceAdapterType; if (jobSourceAdapterType != null) { _jobSourceAdapterTypeName = jobSourceAdapterType.Name; } Command = command; _name = name; _instanceId = Guid.NewGuid(); } /// /// /// /// /// protected JobDefinition(SerializationInfo info, StreamingContext context) { throw new NotImplementedException(); } /// /// /// /// /// public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { throw new NotImplementedException(); } } /// /// Class that helps define the parameters to /// be passed to a job so that the job can be /// instantiated without having to specify /// the parameters explicitly. Helps in /// passing job parameters to disk /// /// This class is not required if /// CommandParameterCollection adds a public /// constructor.The actual implementation of /// this class will happen in M2 [Serializable] public class JobInvocationInfo : ISerializable { /// /// Friendly name associated with this specification /// public String Name { get { return _name; } set { if (value == null) throw new PSArgumentNullException("value"); _name = value; } } private string _name = string.Empty; private string _command; /// /// Command string to execute. /// public string Command { get { return _command ?? _definition.Command; } set { _command = value; } } private JobDefinition _definition; /// /// Definition associated with the job /// public JobDefinition Definition { get { return _definition; } set { _definition = value; } } private List _parameters; /// /// Parameters associated with this specification /// public List Parameters { get { return _parameters ?? (_parameters = new List()); } } /// /// Unique identifies for this specification /// public Guid InstanceId { get; } = Guid.NewGuid(); /// /// Save this specification to a file /// /// stream to save to public virtual void Save(Stream stream) { throw new NotImplementedException(); } /// /// Load this specification from a file /// /// stream to load from public virtual void Load(Stream stream) { throw new NotImplementedException(); } /// /// Constructor. /// protected JobInvocationInfo() { } /// /// Create a new job definition with a single set of parameters. /// /// The job definition /// The parameter collection to use public JobInvocationInfo(JobDefinition definition, Dictionary parameters) { _definition = definition; var convertedCollection = ConvertDictionaryToParameterCollection(parameters); if (convertedCollection != null) { Parameters.Add(convertedCollection); } } /// /// Create a new job definition with a multiple sets of parameters. This allows /// different parameters for different machines. /// /// The job definition /// Collection of sets of parameters to use for the child jobs [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is forced by the interaction of PowerShell and Workflow.")] public JobInvocationInfo(JobDefinition definition, IEnumerable> parameterCollectionList) { _definition = definition; if (parameterCollectionList == null) return; foreach (var parameterCollection in parameterCollectionList) { if (parameterCollection == null) continue; CommandParameterCollection convertedCollection = ConvertDictionaryToParameterCollection(parameterCollection); if (convertedCollection != null) { Parameters.Add(convertedCollection); } } } /// /// /// /// /// public JobInvocationInfo(JobDefinition definition, CommandParameterCollection parameters) { _definition = definition; Parameters.Add(parameters ?? new CommandParameterCollection()); } /// /// /// /// /// public JobInvocationInfo(JobDefinition definition, IEnumerable parameters) { _definition = definition; if (parameters == null) return; foreach (var parameter in parameters) { Parameters.Add(parameter); } } /// /// /// /// /// protected JobInvocationInfo(SerializationInfo info, StreamingContext context) { throw new NotImplementedException(); } /// /// /// /// /// public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { throw new NotImplementedException(); } /// /// Utility function to turn a dictionary of name/value pairs into a parameter collection /// /// The dictionary to convert /// The converted collection private static CommandParameterCollection ConvertDictionaryToParameterCollection(IEnumerable> parameters) { if (parameters == null) return null; CommandParameterCollection paramCollection = new CommandParameterCollection(); foreach (CommandParameter paramItem in parameters.Select(param => new CommandParameter(param.Key, param.Value))) { paramCollection.Add(paramItem); } return paramCollection; } } /// /// Abstract class for a job store which will /// contain the jobs of a specific type. /// public abstract class JobSourceAdapter { /// /// Name for this store /// public String Name { get; set; } = String.Empty; /// /// Get a token that allows for construction of a job with a previously assigned /// Id and InstanceId. This is only possible if this JobSourceAdapter is the /// creator of the original job. /// The original job must have been saved using "SaveJobIdForReconstruction" /// /// Instance Id of the job to recreate /// JobIdentifier to be used in job construction protected JobIdentifier RetrieveJobIdForReuse(Guid instanceId) { return JobManager.GetJobIdentifier(instanceId, this.GetType().Name); } /// /// Saves the Id information for a job so that it can be constructed at a later time. /// This will only allow this job source adapter type to recreate the job. /// /// The job whose id information to store. /// Recurse to save child job Ids. [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Only jobs that derive from Job2 should have reusable IDs.")] public void StoreJobIdForReuse(Job2 job, bool recurse) { if (job == null) { PSTraceSource.NewArgumentNullException("job", RemotingErrorIdStrings.JobSourceAdapterCannotSaveNullJob); } JobManager.SaveJobId(job.InstanceId, job.Id, this.GetType().Name); if (recurse && job.ChildJobs != null && job.ChildJobs.Count > 0) { Hashtable duplicateDetector = new Hashtable(); duplicateDetector.Add(job.InstanceId, job.InstanceId); foreach (Job child in job.ChildJobs) { Job2 childJob = child as Job2; if (childJob == null) continue; StoreJobIdForReuseHelper(duplicateDetector, childJob, true); } } } private void StoreJobIdForReuseHelper(Hashtable duplicateDetector, Job2 job, bool recurse) { if (duplicateDetector.ContainsKey(job.InstanceId)) return; duplicateDetector.Add(job.InstanceId, job.InstanceId); JobManager.SaveJobId(job.InstanceId, job.Id, this.GetType().Name); if (!recurse || job.ChildJobs == null) return; foreach (Job child in job.ChildJobs) { Job2 childJob = child as Job2; if (childJob == null) continue; StoreJobIdForReuseHelper(duplicateDetector, childJob, recurse); } } /// /// Create a new job with the specified definition /// /// job definition to use /// job object public Job2 NewJob(JobDefinition definition) { return NewJob(new JobInvocationInfo(definition, new Dictionary())); } /// /// Creates a new job with the definition as specified by /// the provided definition name and path. If path is null /// then a default location will be used to find the job /// definition by name. /// /// Job definition name /// Job definition file path /// Job2 object public virtual Job2 NewJob(string definitionName, string definitionPath) { return null; } /// /// Create a new job with the specified JobSpecification /// /// specification /// job object public abstract Job2 NewJob(JobInvocationInfo specification); /// /// Get the list of jobs that are currently available in this /// store /// /// collection of job objects public abstract IList GetJobs(); /// /// Get list of jobs that matches the specified names /// /// names to match, can support /// wildcard if the store supports /// /// collection of jobs that match the specified /// criteria public abstract IList GetJobsByName(string name, bool recurse); /// /// Get list of jobs that run the specified command /// /// command to match /// /// collection of jobs that match the specified /// criteria public abstract IList GetJobsByCommand(string command, bool recurse); /// /// Get list of jobs that has the specified id /// /// Guid to match /// /// job with the specified guid public abstract Job2 GetJobByInstanceId(Guid instanceId, bool recurse); /// /// Get job that has specific session id /// /// Id to match /// /// Job with the specified id public abstract Job2 GetJobBySessionId(int id, bool recurse); /// /// Get list of jobs that are in the specified state /// /// state to match /// /// collection of jobs with the specified /// state public abstract IList GetJobsByState(JobState state, bool recurse); /// /// Get list of jobs based on the adapter specific /// filter parameters /// /// dictionary containing name value /// pairs for adapter specific filters /// /// collection of jobs that match the /// specified criteria public abstract IList GetJobsByFilter(Dictionary filter, bool recurse); /// /// Remove a job from the store /// /// job object to remove public abstract void RemoveJob(Job2 job); /// /// Saves the job to a persisted store. /// /// Job2 type job to persist public virtual void PersistJob(Job2 job) { // Implemented only if job needs to be told when to persist. } } }