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
-~----------~----~----~----~------~----~------~--~---

Attachment: ArchitectureAndDevelopment.sb.d
Description: MS-Word document

Reply via email to