At 7:05 PM -0400 5/16/07, Anthony Perritano wrote: >stephen, i would like a primer on the SDS for the munich trip. where do i >start? -Tony
Hi Tony, I'll have some more overview documents up soon but here are some suggestions: I've attached a word doc which is part of a tech section I wrote for a proposal. It doesn't talk about the SDS much but it gives you an overview of where I see all the pieces fitting. There's the documentation for the SDS REST api here: http://www.telscenter.org/confluence/display/SAIL/REST+protocol+for+SAIL+Data+Services+%28SDS%29 It's a bit out of date and it doesn't provide much of a medium or high-level overview -- that's what I've promised to write before your meeting. There's the: "Using the SDS from Wise" page. Not a great deal of info here but it's a simple example of the workflow a portal has to go through to get something up an running in the SDS. http://www.telscenter.org/confluence/display/TCS/Using+the+SDS+from+Wise Aaron put together a page: "Setting up a local SDS". This would be a great thing for you to setup. Also take a look at Aaron and Cynic's recent conversations on sail dev for more suggestions. I don't know if Aaron or Cynic have updated the page after Cynic's work. I'll bet there there are some points that could be made more clear. http://www.telscenter.org/confluence/display/SAIL/Setting+up+a+local+SDS I don't know what state the Java portal is in but the Rails-based DIY portals work quite well with the SDS. If you can get the SDS running locally then setting up a DIY instance will be easy. It comes with two activities already installed. Whether you ever use rails it's still a good working example and I think the code is quite easy to read. If you are interested we can put a doc together on how to get a local DIY up and working and talking to your local SDS. You could use this as just another reference implementation that you could play with and inspect. Here is a very quick overview of how the DIY works with an SDS. I'm going to explain by describing how an object I just added to the DIY was integrated into the SDS. This object has the unfortunate name of "Model" -- unfortunate because the word has other overlapping means that could be confusing. But realize that I mean a simple activity which is just used to display an embedded model like Molecular workbench or NetLogo. This page has an example of the attributes of a DIY Model: http://rails.dev.concord.org/teemss2/models/1 You can run it as a SAIL application by clicking the "Test" link. After passing though the browser and back to the server this request gets routed to the controller models_controller.rb When this specific model was created an SDS offering was also created. The code is in the Rails "model" code for the DIY object called Model: http://svn.concord.org/svn/teemss2/branches/teemss2diy-plus-sail/app/models/model.rb Rails "models" are the code that connects Ruby objects to ActiveRecord models of persistence. The key code here is this filter: before_save :check_sds_attributes Normally this would just be a before_create filter but sometimes in development I switch from one SDS to another and then the SDS attributes need to be cleared and regenerated. That filter makes sure this instance method is called when a Model object is being saved: def check_sds_attributes if sds_offering_id.blank? sds = SdsConnect::Connect.new jnlp_id = SdsConnect::Connect.config['jnlp_id'] curnit_id = SdsConnect::Connect.config['curnit_id'] self.sds_offering_id = sds.create_offering(self.name, jnlp_id, curnit_id) end end The DIY uses a fixed jnlp and curnit (the curnit says get the author data from a url passed in as a parameter on the jnlp url instead of from the curnit). With these data an offering is created using the SdsConnect::Connect object as the api. The SdsConnect::Connect class is defined here: http://svn.concord.org/svn/teemss2/branches/teemss2diy-plus-sail/lib/sds_connect.rb The Test and Run links for models look like this when rendered as html: http://rails.dev.concord.org/teemss2/models/1;sail_jnlp After passing through the router this sends control to the sail_jnlp method in this class: http://svn.concord.org/svn/teemss2/branches/teemss2diy-plus-sail/app/controllers/models_controller.rb There are only a couple of key sds-related code sections in that method. Here's the first: @learner = @model.learners.find_or_initialize_by_user_id(@user.id) @learner.resource = @model @learner.save A learner object is either found or created that relates that user with the running of that model. Here's the complete Learner class; http://svn.concord.org/svn/teemss2/branches/teemss2diy-plus-sail/app/models/learner.rb class Learner < ActiveRecord::Base set_table_name "#{RAILS_APPLICATION_PREFIX}learners" belongs_to :user belongs_to :resource, :polymorphic => true has_many :activity_sessions before_save :check_sds_attributes def check_sds_attributes if self.sds_workgroup_id.blank? sds = SdsConnect::Connect.new self.sds_workgroup_id = sds.create_workgroup(self.user.name, self.resource.sds_offering_id) sds.create_workgroup_membership(self.sds_workgroup_id, self.user.sds_sail_user_id) end end end So when a Learner object is created it uses an SdsConnect::Connect object to make a new workgroup and an initial workgroup membership (in this case it is a membership of just one user). A Learner has a one-to-one relationship with a User but it can refer to a polymorhic collection of objects it references as resources. In the current DIY Activities, Models, and ExternalOtrunkActivities are all resources that can be related to a user through the Learner object. OK -- we've created an Offering and a Workgroup (the jnlp and curnit were already setup when we started) -- here's the other important parts of the sail_jnlp method. I'm constructing an url for the sds which will generate the jnlp and also pass in as url parameters a bunch of variables that dynamically configures both the sds and the SAIL application through the config process. In a simpler interface most of this doesn't need to happen. sds_url = "#{SdsConnect::Connect.config['host']}/offering/[EMAIL PROTECTED]/jnlp/[EMAIL PROTECTED]" sds_url << '/view' unless savedata otml_url = url_for(:only_path => false, :controller => "models", :action => "otml") jnlp_url = "#{sds_url}?sailotrunk.otmlurl=#{otml_url}" jnlp_filename = "[EMAIL PROTECTED]" jnlp_url = jnlp_url << "&jnlp_filename=#{jnlp_filename}" if authoring jnlp_properties = URI.escape("otrunk.view.author=true&otrunk.view.hide_tree=true&otrunk.view.frame_title=#{APP_PROPERTIES[:application_name]}", /[#{URI::REGEXP::PATTERN::RESERVED}]/) jnlp_url << "&jnlp_properties=#{jnlp_properties}" end # jnlp_url << "&otrunk.view.no_user=true" unless savedata redirect_to URI.escape(jnlp_url) After constructing a long complicated url I end with a redirection. I explained the functional results of this last bit of code about a week ago. Here's a copy of he explanation: adding two more optional parameters which can be added onto the end of the the url which generates the jnlp. - jnlp_filename The value of this parameter is used by the sds when it constructs the Content-Disposition header. By setting this a portal can determine what is the filename of the jnlp when it is saved onto a client computer. This is mainly useful for debugging. - jnlp_properties The value for jnlp_properties is a string of key-value pairs in a url query-string format in which the reserved characters are escaped. Here is an example: http://saildataservice.concord.org/7/offering/662/jnlp/855/view?sailotrunk.otmlurl=http://itsidiy.concord.org/page/otml/6/16/247/view&jnlp_filename=itsidiy_relative_humidity_graph_vernier_goio.jnlp&jnlp_properties=otrunk.view.author%253Dtrue%2526otrunk.view.hide_tree%253Dtrue%2526otrunk.view.frame_title%253DITSI%20Do%20It%20Yourself Deconstructing that url the parameters passed after the main url: http://saildataservice.concord.org/7/offering/662/jnlp/855/view are: 1) sailotrunk.otmlurl=http://itsidiy.concord.org/page/otml/6/16/247/view This is used to create properties loaded by sail in the config system. This particular property is used to tell an OTunk curnit to get it's author data from the url: http://itsidiy.concord.org/page/otml/6/16/247/view 2) jnlp_filename=itsidiy_relative_humidity_graph_vernier_goio.jnlp This is used by the sds to set the Content-Disposition header when the jnlp is downloaded to a client to: itsidiy_relative_humidity_graph_vernier_goio.jnlp 3) jnlp_properties=otrunk.view.author%253Dtrue%2526otrunk.view.hide_tree%253Dtrue%2526otrunk.view.frame_title%253DITSI%20Do%20It%20Yourself The value of jnlp_properties is set to: otrunk.view.author%253Dtrue%2526otrunk.view.hide_tree%253Dtrue%2526otrunk.view.frame_title%253DITSI%20Do%20It%20Yourself Unescaping that once using Ruby: URI.unescape("otrunk.view.author%253Dtrue%2526otrunk.view.hide_tree%253Dtrue%2526otrunk.view.frame_title%253DITSI%20Do%20It%20Yourself") => "otrunk.view.author%3Dtrue%26otrunk.view.hide_tree%3Dtrue%26otrunk.view.frame_title%3DITSI Do It Yourself" %3D = '&' %26 = '=' decomposing this one level further these three properties will end up in the jnlp itself like this: <property name="otrunk.view.author" value="true"/> <property name="otrunk.view.hide_tree" value="true"/> <property name="otrunk.view.frame_title" value="ITSI Do It Yourself"/> --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "SAIL-Dev" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/SAIL-Dev?hl=en -~----------~----~----~----~------~----~------~--~---
ArchitectureAndDevelopment.sb.d
Description: MS-Word document
