Module: Dor::WorkflowService

Defined in:
lib/dor/services/workflow_service.rb

Overview

Methods to create and update workflow

Constant Summary collapse

@@resource =
nil
@@dor_services_url =
nil

Class Method Summary collapse

Class Method Details

.add_priority_to_workflow_xml(priority, wf_xml) ⇒ String

Adds priority attributes to each process of workflow xml



41
42
43
44
45
46
# File 'lib/dor/services/workflow_service.rb', line 41

def add_priority_to_workflow_xml(priority, wf_xml)
  return wf_xml if(priority.to_i == 0)
  doc = Nokogiri::XML(wf_xml)
  doc.xpath('/workflow/process').each { |proc| proc['priority'] = priority }
  doc.to_xml
end

.archive_workflow(repo, druid, wf_name, version_num = nil) ⇒ Object



251
252
253
254
255
256
257
258
# File 'lib/dor/services/workflow_service.rb', line 251

def archive_workflow(repo, druid, wf_name, version_num=nil)
  raise "Please call Dor::WorkflowService.configure(workflow_service_url, :dor_services_url => DOR_SERVIES_URL) once before archiving workflow" if(@@dor_services_url.nil?)

  dor_services = RestClient::Resource.new(@@dor_services_url)
  url = "/v1/objects/#{druid}/workflows/#{wf_name}/archive"
  url << "/#{version_num}" if(version_num)
  dor_services[url].post ''
end

.configure(url, opts = {}) ⇒ Object

Options Hash (opts):

  • :client_cert_file (String)

    path to an SSL client certificate

  • :client_key_file (String)

    path to an SSL key file

  • :client_key_pass (String)

    password for the key file

  • :dor_services_uri (String)

    uri to the DOR REST service



271
272
273
274
275
276
277
# File 'lib/dor/services/workflow_service.rb', line 271

def configure(url, opts={})
  params = {}
  @@dor_services_url = opts[:dor_services_url] if opts[:dor_services_url]
  #params[:ssl_client_cert] = OpenSSL::X509::Certificate.new(File.read(opts[:client_cert_file])) if opts[:client_cert_file]
  #params[:ssl_client_key]  = OpenSSL::PKey::RSA.new(File.read(opts[:client_key_file]), opts[:client_key_pass]) if opts[:client_key_file]
  @@resource = RestClient::Resource.new(url, params)
end

.create_process_xml(params) ⇒ Object



236
237
238
239
240
241
242
# File 'lib/dor/services/workflow_service.rb', line 236

def create_process_xml(params)
  builder = Nokogiri::XML::Builder.new do |xml|
    attrs = params.reject { |k,v| v.nil? }
    xml.process(attrs)
  end
  return builder.to_xml
end

.create_workflow(repo, druid, workflow_name, wf_xml, opts = {:create_ds => true}) ⇒ Object

Creates a workflow for a given object in the repository. If this particular workflow for this objects exists, it will replace the old workflow with wf_xml passed to this method. You have the option of creating a datastream or not. Returns true on success. Caller must handle any exceptions

Parameters

Options Hash (opts):

  • :create_ds (Boolean)

    if true, a workflow datastream will be created in Fedora. Set to false if you do not want a datastream to be created If you do not pass in an opts Hash, then :create_ds is set to true by default

  • :priority (Integer)

    adds priority to all process elements in the wf_xml workflow xml



28
29
30
31
32
33
34
# File 'lib/dor/services/workflow_service.rb', line 28

def create_workflow(repo, druid, workflow_name, wf_xml, opts = {:create_ds => true})
  xml = wf_xml
  xml = add_priority_to_workflow_xml(opts[:priority], wf_xml) if(opts[:priority])
  workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow_name}"].put(xml, :content_type => 'application/xml',
                                                                               :params => {'create-ds' => opts[:create_ds] })
  return true
end

.delete_workflow(repo, druid, workflow) ⇒ Object

Deletes a workflow from a particular repository and druid



130
131
132
133
# File 'lib/dor/services/workflow_service.rb', line 130

def delete_workflow(repo, druid, workflow)
  workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow}"].delete
  return true
end

.get_active_lifecycle(repo, druid, milestone) ⇒ Time

Returns the Date for a requested milestone ONLY FROM THE ACTIVE workflow table

Examples:

An example lifecycle xml from the workflow service.

<lifecycle objectId="druid:ct011cv6501">
  <milestone date="2010-04-27T11:34:17-0700">registered</milestone>
  <milestone date="2010-04-29T10:12:51-0700">inprocess</milestone>
  <milestone date="2010-06-15T16:08:58-0700">released</milestone>
</lifecycle>


167
168
169
170
171
172
173
174
175
# File 'lib/dor/services/workflow_service.rb', line 167

def get_active_lifecycle(repo, druid, milestone)
  doc = self.query_lifecycle(repo, druid, true)
  milestone = doc.at_xpath("//lifecycle/milestone[text() = '#{milestone}']")
  if(milestone)
    return Time.parse(milestone['date'])
  end

  nil
end

.get_errored_objects_for_workstep(workflow, step, repository = 'dor') ⇒ hash

Get a list of druids that have errored out in a particular workflow and step

e.g. Dor::WorkflowService.get_errored_objects_for_workstep(‘accessionWF’,‘content-metadata’)

> - Item error; caused by #<Rubydora::FedoraInvalidRequest: Error modifying datastream contentMetadata for druid:qd556jq0580. See logger for details>”



226
227
228
229
230
231
232
233
234
# File 'lib/dor/services/workflow_service.rb', line 226

def get_errored_objects_for_workstep workflow, step, repository='dor'
  result = {}
  uri_string = "workflow_queue?repository=#{repository}&workflow=#{workflow}&error=#{step}"
  resp = workflow_resource[uri_string].get
  objs = Nokogiri::XML(resp).xpath('//object').collect do |node|
    result.merge!(node['id'] => node['errorMessage'])
  end
  result
end

.get_lifecycle(repo, druid, milestone) ⇒ Time

Returns the Date for a requested milestone from workflow lifecycle

Examples:

An example lifecycle xml from the workflow service.

<lifecycle objectId="druid:ct011cv6501">
  <milestone date="2010-04-27T11:34:17-0700">registered</milestone>
  <milestone date="2010-04-29T10:12:51-0700">inprocess</milestone>
  <milestone date="2010-06-15T16:08:58-0700">released</milestone>
</lifecycle>


146
147
148
149
150
151
152
153
154
# File 'lib/dor/services/workflow_service.rb', line 146

def get_lifecycle(repo, druid, milestone)
  doc = self.query_lifecycle(repo, druid)
  milestone = doc.at_xpath("//lifecycle/milestone[text() = '#{milestone}']")
  if(milestone)
    return Time.parse(milestone['date'])
  end

  nil
end

.get_milestones(repo, druid) ⇒ Object



177
178
179
180
181
182
# File 'lib/dor/services/workflow_service.rb', line 177

def get_milestones(repo, druid)
  doc = self.query_lifecycle(repo, druid)
  doc.xpath("//lifecycle/milestone").collect do |node|
    { :milestone => node.text, :at => Time.parse(node['date']), :version => node['version'] }
  end
end

.get_objects_for_workstep(completed, waiting, repository = nil, workflow = nil) ⇒ Object

Returns a list of druids from the WorkflowService that meet the criteria of the passed in completed and waiting params



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/dor/services/workflow_service.rb', line 199

def get_objects_for_workstep completed, waiting, repository=nil, workflow=nil
  result = nil
  if(completed)
    uri_string = "workflow_queue?waiting=#{qualify_step(repository,workflow,waiting)}"
    Array(completed).each do |step|
      uri_string << "&completed=#{qualify_step(repository,workflow,step)}"
    end
  else
    uri_string = "workflow_queue?waiting=#{qualify_step(repository,workflow,waiting)}"
  end
  workflow_resource.options[:timeout] = 5 * 60 unless(workflow_resource.options.include?(:timeout))
  resp = workflow_resource[uri_string].get
  result = Nokogiri::XML(resp).xpath('//object[@id]').collect { |node| node['id'] }

  result || []
end

.get_workflow_status(repo, druid, workflow, process) ⇒ Object

Retrieves the process status of the given workflow for the given object identifier

Raises:

  • (Exception)


75
76
77
78
79
80
81
82
83
84
85
# File 'lib/dor/services/workflow_service.rb', line 75

def get_workflow_status(repo, druid, workflow, process)
  workflow_md = workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow}"].get
  doc = Nokogiri::XML(workflow_md)
  raise Exception.new("Unable to parse response:\n#{workflow_md}") if(doc.root.nil?)

  status = doc.root.at_xpath("//process[@name='#{process}']/@status")
  if status
    status=status.content
  end
  return status
end

.get_workflow_xml(repo, druid, workflow) ⇒ Object



87
88
89
# File 'lib/dor/services/workflow_service.rb', line 87

def get_workflow_xml(repo, druid, workflow)
  workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow}"].get
end

.get_workflows(pid) ⇒ array

Get workflow names into an array for given PID This method only works when this gem is used in a project that is configured to connect to DOR

e.g. Dor::WorkflowService.get_workflows(‘druid:sr100hp0609’)

> [“accessionWF”, “assemblyWF”, “disseminationWF”]



100
101
102
103
# File 'lib/dor/services/workflow_service.rb', line 100

def get_workflows(pid)
  xml_doc=Nokogiri::XML(get_workflow_xml('dor',pid,''))
  return xml_doc.xpath('//workflow').collect {|workflow| workflow['id']}
end

.qualify_step(default_repository, default_workflow, step) ⇒ Object



184
185
186
187
188
189
# File 'lib/dor/services/workflow_service.rb', line 184

def qualify_step(default_repository, default_workflow, step)
  current = step.split(/:/,3)
  current.unshift(default_workflow) if current.length < 3
  current.unshift(default_repository) if current.length < 3
  current.join(':')
end

.query_lifecycle(repo, druid, active_only = false) ⇒ Object



244
245
246
247
248
249
# File 'lib/dor/services/workflow_service.rb', line 244

def query_lifecycle(repo, druid, active_only = false)
  req = "#{repo}/objects/#{druid}/lifecycle"
  req << '?active-only=true' if active_only
  lifecycle_xml = workflow_resource[req].get
  return Nokogiri::XML(lifecycle_xml)
end

.update_workflow_error_status(repo, druid, workflow, process, error_msg, opts = {}) ⇒ Object

Updates the status of one step in a workflow to error. Returns true on success. Caller must handle any exceptions

Http Call

The method does an HTTP PUT to the URL defined in Dor::WF_URI. As an example:

PUT "/dor/objects/pid:123/workflows/GoogleScannedWF/convert"
<process name=\"convert\" status=\"error\" />"

Options Hash (opts):

  • :error_txt (String)

    A slot to hold more information about the error, like a full stacktrace



119
120
121
122
123
124
# File 'lib/dor/services/workflow_service.rb', line 119

def update_workflow_error_status(repo, druid, workflow, process, error_msg, opts = {})
  opts = {:error_txt => nil}.merge!(opts)
  xml = create_process_xml({:name => process, :status => 'error', :errorMessage => error_msg}.merge!(opts))
  workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow}/#{process}"].put(xml, :content_type => 'application/xml')
  return true
end

.update_workflow_status(repo, druid, workflow, process, status, opts = {}) ⇒ Object

Updates the status of one step in a workflow. Returns true on success. Caller must handle any exceptions

Http Call

The method does an HTTP PUT to the URL defined in Dor::WF_URI. As an example:

PUT "/dor/objects/pid:123/workflows/GoogleScannedWF/convert"
<process name=\"convert\" status=\"completed\" />"

Options Hash (opts):

  • :elapsed (Float)

    The number of seconds it took to complete this step. Can have a decimal. Is set to 0 if not passed in.

  • :lifecycle (String)

    Bookeeping label for this particular workflow step. Examples are: ‘registered’, ‘shelved’

  • :note (String)

    Any kind of string annotation that you want to attach to the workflow

  • :priority (Integer)

    Processing priority, 0-100, 100 being the highest priority. Workflow queues are returned in order of highest to lowest priority. Stored in the system as 0 by default



64
65
66
67
68
69
70
# File 'lib/dor/services/workflow_service.rb', line 64

def update_workflow_status(repo, druid, workflow, process, status, opts = {})
  opts = {:elapsed => 0, :lifecycle => nil, :note => nil}.merge!(opts)
  opts[:elapsed] = opts[:elapsed].to_s
  xml = create_process_xml({:name => process, :status => status}.merge!(opts))
  workflow_resource["#{repo}/objects/#{druid}/workflows/#{workflow}/#{process}"].put(xml, :content_type => 'application/xml')
  return true
end

.workflow_resourceObject



260
261
262
263
# File 'lib/dor/services/workflow_service.rb', line 260

def workflow_resource
  raise "Please call Dor::WorkflowService.configure(url) once before calling any WorkflowService methods" if(@@resource.nil?)
  @@resource
end