diff options
-rw-r--r-- | README | 11 | ||||
-rw-r--r-- | application.rb | 210 | ||||
-rw-r--r-- | config.ru | 4 |
3 files changed, 164 insertions, 61 deletions
@@ -4,7 +4,8 @@ OpenTox Task * An OpenTox REST Webservice (http://www.opentox.org) * Does _not_ comply to the (incomplete) OpenTox API -REST operations: +REST operations +--------------- Get a list of all tasks GET / - Task URIs 200 Get the status of a task GET /{id}/status - created|started|completed|cancelled 200,404 @@ -17,10 +18,12 @@ Cancel a task PUT /{id}/cancelled "" - Delete a task DELETE /{id} - - 200, 404 Delete all tasks DELETE / - - 200 -IMPORTANT NOTE: My framework does not accept empty PUT requests. Please send an empty parameter (e.g. with -d '' for curl) or you will receive a "411 Length Required" error. +IMPORTANT NOTE: Our framework does not accept empty PUT requests. Please send an empty parameter (e.g. with -d '' for curl) or you will receive a "411 Length Required" error. -More documentation: Source code (application.rb) +API documentation +----------------- -Copyright (c) 2009 Christoph Helma. See LICENSE for details. +http://rdoc.info/github/opentox/task +Copyright (c) 2009-2011 Christoph Helma, Martin Guetlein, Micha Rautenberg, Andreas Maunz, David Vorgrimmler, Denis Gebele. See LICENSE for details. diff --git a/application.rb b/application.rb index fe3d593..673cc4d 100644 --- a/application.rb +++ b/application.rb @@ -1,53 +1,88 @@ require 'rubygems' -gem "opentox-ruby-api-wrapper", "= 1.6.5" -require 'opentox-ruby-api-wrapper' -#require "dm-is-tree" - -class Task - include DataMapper::Resource - property :id, Serial - property :uri, String, :length => 255 - property :created_at, DateTime - - property :finished_at, DateTime - property :due_to_time, DateTime - property :pid, Integer - - property :resultURI, String, :length => 255 - property :percentageCompleted, Float, :default => 0 - property :hasStatus, String, :default => "Running" #possible states are: "Cancelled", "Completed", "Running", "Error" - property :title, String, :length => 255 - property :creator, String, :length => 255 - property :description, Text +gem "opentox-ruby", "~> 1" +require 'opentox-ruby' + +set :lock, true + +class Task < Ohm::Model + + attribute :uri + attribute :created_at + + attribute :finished_at + attribute :due_to_time + attribute :pid + + attribute :resultURI + attribute :percentageCompleted + attribute :hasStatus + attribute :title + attribute :creator + attribute :description + + attribute :waiting_for + + attribute :errorReport + + def metadata + { + DC.creator => creator, + DC.title => title, + DC.date => created_at, + OT.hasStatus => hasStatus, + OT.resultURI => resultURI, + OT.percentageCompleted => percentageCompleted.to_f, + #text fields are lazy loaded, using member variable can cause description to be nil + DC.description => description + #:due_to_time => @due_to_timer + } + end + end -DataMapper.auto_upgrade! +#DataMapper.auto_upgrade! +# Get a list of all tasks +# @return [text/uri-list] List of all tasks get '/?' do - response['Content-Type'] = 'text/uri-list' - Task.all(params).collect{|t| t.uri}.join("\n") + "\n" + LOGGER.debug "list all tasks "+params.inspect + if request.env['HTTP_ACCEPT'] =~ /html/ + response['Content-Type'] = 'text/html' + OpenTox.text_to_html Task.all.collect{|t| t.uri}.join("\n") + "\n" + else + response['Content-Type'] = 'text/uri-list' + Task.all.collect{|t| t.uri}.join("\n") + "\n" + end end +# Get task representation +# @param [Header] Accept Mime type of accepted representation, may be one of `application/rdf+xml,application/x-yaml,text/uri-list` +# @return [application/rdf+xml,application/x-yaml,text/uri-list] Task representation in requested format, Accept:text/uri-list returns URI of the created resource if task status is "Completed" get '/:id/?' do - task = Task.get(params[:id]) + task = Task[params[:id]] halt 404, "Task '#{params[:id]}' not found." unless task - - task_content = {:creator => task.creator, :title => task.title, :date => task.created_at, :hasStatus => task.hasStatus, - :resultURI => task.resultURI, :percentageCompleted => task.percentageCompleted, :description => task.description, - :due_to_time => task.due_to_time } - code = task.hasStatus == "Running" ? 202 : 200 case request.env['HTTP_ACCEPT'] - when /application\/x-yaml|\*\/\*/ # matches 'application/x-yaml', '*/*' + when /yaml/ response['Content-Type'] = 'application/x-yaml' - task_content[:uri] = task.uri - halt code, task_content.to_yaml - when /application\/rdf\+xml|\*\/\*/ + metadata = task.metadata + metadata[OT.waitingFor] = task.waiting_for + metadata[OT.errorReport] = task.errorReport if task.errorReport + halt code, metadata.to_yaml + #halt code, task.created_at + when /html/ + response['Content-Type'] = 'text/html' + metadata = task.metadata + metadata[OT.waitingFor] = task.waiting_for + metadata[OT.errorReport] = task.errorReport if task.errorReport + halt code, OpenTox.text_to_html(metadata.to_yaml) + when /application\/rdf\+xml|\*\/\*/ # matches 'application/x-yaml', '*/*' response['Content-Type'] = 'application/rdf+xml' - owl = OpenTox::Owl.create 'Task', task.uri - task_content.each{ |k,v| owl.set(k.to_s,v)} - halt code, owl.rdf + t = OpenTox::Task.new task.uri + t.add_metadata task.metadata + t.add_error_report task.errorReport + halt t.to_rdfxml when /text\/uri\-list/ response['Content-Type'] = 'text/uri-list' halt code, task.resultURI @@ -56,32 +91,75 @@ get '/:id/?' do end end -# dynamic access to Task properties + +# Get Task properties. Works for +# - /task/id +# - /task/uri +# - /task/created_at +# - /task/finished_at +# - /task/due_to_time +# - /task/pid +# - /task/resultURI +# - /task/percentageCompleted +# - /task/hasStatus +# - /task/title +# - /task/creator +# - /task/description +# @return [String] Task property get '/:id/:property/?' do response['Content-Type'] = 'text/plain' - task = Task.get(params[:id]) + task = Task[params[:id]] halt 404,"Task #{params[:id]} not found." unless task - eval("task.#{params[:property]}").to_s + begin + eval("task.#{params[:property]}").to_s + rescue + halt 404,"Unknown task property #{params[:property]}." + end end +# Create a new task +# @param [optional,String] max_duration +# @param [optional,String] pid +# @param [optional,String] resultURI +# @param [optional,String] percentageCompleted +# @param [optional,String] hasStatus +# @param [optional,String] title +# @param [optional,String] creator +# @param [optional,String] description +# @return [text/uri-list] URI for new task post '/?' do LOGGER.debug "Creating new task with params "+params.inspect max_duration = params.delete(:max_duration.to_s) if params.has_key?(:max_duration.to_s) - task = Task.new(params) - task.save # needed to create id - task.uri = url_for("/#{task.id}", :full) - task.due_to_time = DateTime.parse((Time.parse(task.created_at.to_s) + max_duration.to_f).to_s) if max_duration - raise "could not save" unless task.save + params[:created_at] = Time.now + params[:hasStatus] = "Running" unless params[:hasStatus] + task = Task.create params + task.update :uri => url_for("/#{task.id}", :full) + #task.due_to_time = DateTime.parse((Time.parse(task.created_at.to_s) + max_duration.to_f).to_s) if max_duration + #raise "Could not save task #{task.uri}" unless task.save response['Content-Type'] = 'text/uri-list' task.uri + "\n" end +# Change task status. Possible URIs are: ` +# - /task/Cancelled +# - /task/Completed: requires taskURI argument +# - /task/Running +# - /task/Error +# - /task/pid: requires pid argument +# IMPORTANT NOTE: Rack does not accept empty PUT requests. Please send an empty parameter (e.g. with -d '' for curl) or you will receive a "411 Length Required" error. +# @param [optional, String] resultURI URI of created resource, required for /task/Completed +# @param [optional, String] pid Task PID, required for /task/pid +# @param [optional, String] description Task description +# @param [optional, String] percentageCompleted progress value, can only be set while running +# @return [] nil put '/:id/:hasStatus/?' do - task = Task.get(params[:id]) + task = Task[params[:id]] halt 404,"Task #{params[:id]} not found." unless task task.hasStatus = params[:hasStatus] unless /pid/ =~ params[:hasStatus] task.description = params[:description] if params[:description] + #task.errorReport = YAML.load(params[:errorReport]) if params[:errorReport] + task.errorReport = params[:errorReport] if params[:errorReport] case params[:hasStatus] when "Completed" @@ -89,43 +167,63 @@ put '/:id/:hasStatus/?' do halt 402,"no param resultURI when completing task" unless params[:resultURI] task.resultURI = params[:resultURI] task.finished_at = DateTime.now + task.percentageCompleted = 100 task.pid = nil when "pid" task.pid = params[:pid] + when "Running" + halt 400,"Task cannot be set to running after not running anymore" if task.hasStatus!="Running" + task.waiting_for = params[:waiting_for] if params.has_key?("waiting_for") + if params.has_key?("percentageCompleted") + task.percentageCompleted = params[:percentageCompleted].to_f + #LOGGER.debug "Task " + params[:id].to_s + " set percentage completed to: "+params[:percentageCompleted].to_s + end when /Cancelled|Error/ - Process.kill(9,task.pid) unless task.pid.nil? + if task.waiting_for and task.waiting_for.uri? + # try cancelling the child task + begin + w = OpenTox::Task.find(task.waiting_for) + w.cancel if w.running? + rescue + end + end + LOGGER.debug("Aborting task "+task.uri.to_s) + Process.kill(9,task.pid.to_i) unless task.pid.nil? task.pid = nil else halt 402,"Invalid value for hasStatus: '"+params[:hasStatus].to_s+"'" end halt 500,"could not save task" unless task.save - + end +# Delete a task +# @return [text/plain] Status message delete '/:id/?' do - task = Task.get(params[:id]) + task = Task[params[:id]] halt 404, "Task #{params[:id]} not found." unless task begin Process.kill(9,task.pid) unless task.pid.nil? + task.delete + response['Content-Type'] = 'text/plain' + "Task #{params[:id]} deleted." rescue halt 500,"Cannot kill task with pid #{task.pid}" end - task.destroy! - response['Content-Type'] = 'text/plain' - "Task #{params[:id]} deleted." end +# Delete all tasks +# @return [text/plain] Status message delete '/?' do Task.all.each do |task| begin - Process.kill(9,task.pid) unless task.pid.nil? + Process.kill(9,task.pid.to_i) unless task.pid.nil? + task.delete + response['Content-Type'] = 'text/plain' + "All tasks deleted." rescue "Cannot kill task with pid #{task.pid}" end - #task.destroy! end - Task.auto_migrate! - response['Content-Type'] = 'text/plain' - "All tasks deleted." end @@ -1,5 +1,7 @@ require 'rubygems' -require 'opentox-ruby-api-wrapper' +require 'opentox-ruby' require 'config/config_ru' run Sinatra::Application +set :raise_errors, false +set :show_exceptions, false |