Hi

This is a proposal for a new way to add methods to Fedora objects. It is
designed to be much simpler than the current system, and content model
centric.

I have chosen to call them datastream methods, because they are methods
on the object datastreams, not on the object themselves. This, of
course, adds further to the discussion about whether or not datastreams
are first class objects (which I feel they are)



DATASTREAM METHODS:
Bound to datastreams in DS-COMPOSITEMODEL, via the extension mechanism.
The extension mechanism was introduced with Enhanced Content Models, and
will hopefully be a part of Fedora.

There will be two kinds of methods, for now called getters and setters.
Both invoke some service, and both return the return value from the
service. But the setter methods additionally stores the return value in
the datastream. As such, we now finally have fedora methods that can
modify objects. 

SECURITY
But policy and authentication, I hear you say. These have always been
the problem of methods in Fedora. Well, these methods handles that
elegantly. To invoke any method, you need to be able to disseminate the
datastream, so the policy for getDatastreamDissemination blocks methods
overall. Secondly, to use a setter, you need to have the rights for
modifyDatastream, so the datastreams are further protected from changes
by that policy. 
All of this is done with the user credentials you used to invoke the
method, so it is also done as the correct user (for logging purposes).


There will be two new api methods for Fedora, here shown in the REST
syntax. The same two methods will exist in the SOAP api.

GET /ecm/{pid}/datastreams/{datastream}/methods

GET/POST /ecm/{pid}/datastreams/{datastream}/methods/{method}?Param=value...



The DS-COMPOSITE-MODEL datastream will now look like this


<dsCompositeModel>

    <dsTypeModel ID="DC">
        <form MIME="text/xml"/>
        <extensions name="METHODS">
            <eom:methods xmlns:eom="somenamespace">
                <eom:method name="dumpAsJSON" redirect="false">
                    <eom:public>
                        <eom:docs>
                            Parses the dc terms from this datastream and
                            returns it as JSON.
                        </eom:docs>
                        <eom:type>getter</eom:type>
                        <eom:httpVerb>GET</eom:httpVerb>
                    </eom:public>
                    <eom:resource
                       url="http://${local.fedora.server}/jsondumper";
                       httpmethod="POST"/>
                    <eom:messagebody kind="datastream"/>
                    <eom:downloadName>
                          ${pid}.${datastream}.json
                    </eom:downloadName>
                </eom:method>
            </eom:methods>
        </extensions>
    </dsTypeModel>
</dsCompositeModel>




So, reading this:
1. The DC datastream has one method, dumpAsJSON.
2. It is a getter method, so the datastream will not be updated
3. For REST invokation, you should use the GET verb
4. It takes no parameters (more about this later)
5. The service is invoked by POST'in to
http://${local.fedora.server}/jsondumper
6. The message body of the post is the datastream contents
7. The downloadname for the resulting file will be
${pid}.${datastream}.json

And this is all there is to defining a service. This is all you need to
write. 


PUBLIC INFORMATION
Only the information in the public block is shown the user, when he
lists the methods. The only way to see the rest is to view the
DS-COMPOSITE-MODEL datastream.

The information in the public tag is
                <eom:method name="dumpAsJSON" redirect="false">
                    <eom:public>
                        <eom:docs>
                            Parses the dc terms from this datastream and
                            returns it as JSON.
                        </eom:docs>
                        <eom:type>getter</eom:type>
                        <eom:httpVerb>GET</eom:httpVerb>
                    </eom:public>
                </eom:method>



DEFAULT PARAMETERS
As you could see above, I used the ${xxx} notation. This is taken from
ant, which I am reasonably familiar with. ${xxx} is replaced by the
value of xxx when the method is invoked. These are the variables that
are always and automatically defined

${pid} The object pid
${datastream} The datastream name
${local.fedora.server} The server fedora is running on (dunno if it
includes /fedora)
${username} The username, if any, that invoked the method
${formatURI} The format URI for the datastream, if any
${mimetype} The mimetype for the datastream, if any
${contentLocation} The content location for the datastream (is this set
for xml datastreams?)
${datastreamState} The state of the datastream
${created} The created date of the datastream
${digest} The checksum of the datastream, if any
${digesttType} The checksum  algorithm of the datastream
${controlGroup} The controlgroup of the datastream
${label} The label of the datastream


You can define your own as well. 

<eom:methods xmlns:eom="namespace">
    <eom:method name="dumpAsJSON" redirect="false">
        <eom:public>
            <eom:docs>Parses the dc terms from this datastream and
                returns it as JSON.</eom:docs>
            <eom:type>getter</eom:type>
            <eom:httpVerb>GET</eom:httpVerb>

        </eom:public>
        <eom:resource
             url="http://${local.fedora.server}/${type}dumper?OddParam=
${oddparamvalue}"
             httpmethod="POST"/>
        <eom:defaultparameter name="type" value="json"/>
        <eom:defaultparameter name="oddparamvalue" value="123"/>
        <eom:messagebody kind="datastream"/>
        <eom:downloadName>${pid}.${datastream}.json</eom:downloadName>
    </eom:method>
</eom:methods>



Same example as before, but I have defined two defaultparameters, type
and oddparamvalue. They will be replaced into the all the sections
before the service is invoked. So, the url is now

http://${local.fedora.server}/${type}dumper?OddParam=${oddparamvalue}
But when invoked, it will be
http://localhost:8080/jsondumper?OddParam=123


Default parameters are not very powerful, as you could just as easily
have written out the value in the url. But they help you not having to
repeat yourself.

USER PARAMS

Now, for the user specified params
<eom:methods xmlns:eom="namespace">
    <eom:method name="dumpAsJSON" redirect="false">
        <eom:public>
            <eom:docs>Parses the dc terms from this datastream and
                returns it as JSON.</eom:docs>
            <eom:type>getter</eom:type>
            <eom:httpVerb>GET</eom:httpVerb>
            <eom:userparameter name="oddparamvalue" value="123"/>
        </eom:public>
        <eom:resource
             url="http://${local.fedora.server}/${type}dumper?OddParam=
${oddparamvalue}"
             httpmethod="POST"/>
        <eom:defaultparameter name="type" value="json"/>
        <eom:messagebody kind="datastream"/>
        <eom:downloadName>${pid}.${datastream}.json</eom:downloadName>
    </eom:method>
</eom:methods>

As you can see, the oddparamvalue is no longer a defaultparameter. It is
now a userparameter. The user parameter has a value, which is the
default value, if the user does not set the parameter. To invoke this
service with the param set, use

GET /ecm/{pid}/datastreams/DC/methods/dumpAsJSON?oddparamvalue=234

If not set, the 123 value will be used for the substitution. 


HTTPHEADERS

You can set the header parameters fedora should use when invoking the
remote service. All http headers are allowed here.


<eom:methods xmlns:eom="namespace">
    <eom:method name="dumpAsJSON" redirect="false">
        <eom:public>
            <eom:docs>Parses the dc terms from this datastream and
                returns it as JSON.</eom:docs>
            <eom:type>getter</eom:type>
            <eom:httpVerb>GET</eom:httpVerb>
            <eom:userparameter name="oddparamvalue" value="123"/>
        </eom:public>
        <eom:resource 
             url="http://${local.fedora.server}/${type}dumper?OddParam=
${oddparamvalue}"
             httpmethod="POST"/>
        <eom:defaultparameter name="type" value="json"/>
        <eom:messagebody kind="datastream"/>
        <eom:header name="Content-Type" value="${mimetype}"/>
        <eom:downloadName>${pid}.${datastream}.json</eom:downloadName>
    </eom:method>
</eom:methods>


This is the same example as the previous, except I have added the header
tag. It sets the http header "Content-Type" to the value of the
datastream mime type. As you can see, you can use variable substitution
in headers as well.


This can also be used for hardcoded authentication headers for invoking
the service.






MESSAGE BODY
The message body is only used when the remote service is invoked with a
POST request. The message body can be one of three types

* Datastream: 
   <eom:messagebody kind="datastream"/> The datastream dissemination is
sent as the body
* Disable:
   <eom:messagebody kind="disable"/> No message body is sent (or body
length 0)
* Text:
   <eom:messagebody kind="text">
            This is the text to sent as body.
            
            I can use variable substitution in here, so 
            here is the content location:
              ${contentlocation}
        </eom:messagebody>

With CDATA[[ tags you can even put xml in there. As you can use variable
substitution, with both default parameters, user parameters and
predefined parameters you can express some quite complex dynamic bodies.


REDIRECT

You might have noticed that I always had the redirect attribute to
false. 
<eom:method name="dumpAsJSON" redirect="false"> 

Redirect is a nifty little feature, only usable for getter methods.
Rather than streaming the response through Fedora, the client receives a
HTTP redirect response, to the service url (after the substitution have
been done, of course). 
It has been added for getters on big external datastreams, that should
not be streamed through Fedora. But there is another feature of
redirect. Since the request is redirected, the client can authenticate
itself with the service, rather than having Fedora do it (or not do it,
which is probably what will be done). 
Redirect can, of course, not be used with setters, as Fedora cannot
intercept the return body to store it in the datastream.







Just to finish of, here is an appetizer on what you can do with this
functionality

<dsCompositeModel>

    <dsTypeModel ID="RELS-EXT">
        <extensions name="METHODS">
            <eom:methods xmlns:eom="somenamespace">
                <eom:method name="getAsJSON" redirect="false">
                    <eom:public>
                        <eom:docs>Parses the datastream and returns it
                                  as json
                       </eom:docs>
                        <eom:type>getter</eom:type>
                        <eom:httpVerb>GET</eom:httpVerb>
                    </eom:public>
                    <eom:resource
                      url="http://${local.fedora.server}/${type}dumper";
                      httpmethod="POST"/>
                    <eom:defaultparameter name="type" value="json"/>
                    <eom:messagebody kind="datastream"/>
                    <eom:header 
                         name="Content-Type"
                         value="${mimetype}"/>
                </eom:method>
                <eom:method name="storeAsJSON" redirect="false">
                    <eom:public>
                        <eom:docs>Parses the message body as JSON,
                            converts it to RDF, 
                            and stores it in the datastream</eom:docs>
                        <eom:type>setter</eom:type>
                        <eom:httpVerb>POST</eom:httpVerb>
                        <eom:userparameter 
                             name="jsonmimetype"
                             value="application/json"/>
                    </eom:public>
                    <eom:resource
                       url="http://${local.fedora.server}/${type}dumper";
                       httpmethod="POST"/>
                    <eom:defaultparameter name="type" value="rdf"/>
                    <eom:messagebody kind="user"/>
                    <eom:header 
                         name="Content-Type"
                         value="${jsonmimetype}"/>
                </eom:method>

            </eom:methods>
        </extensions>
    </dsTypeModel>
</dsCompositeModel>


This is the definition of two methods on the RELS-EXT datastream. One
getter, and one setter. The getter allows you to get the datastream as
JSON. The setter allows you to store json, which it converts to rdf
before storing.


I would like to hear peoples response to getting this kind of
functionality in Fedora. If people feel it should not be in Fedora, I
will implement it as a standalone service. There should be no problem
(except a little performance problem) in using

GET/POST
http://someserver.com/fedora/objects/{pid}/datastreams/{datastream}/methods/{method}?Param=value...

or 
GET/POST
http://someserver.com/ecm/{pid}/datastreams/{datastream}/methods/{method}?Param=value...

Regards

Asger


------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Fedora-commons-developers mailing list
Fedora-commons-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/fedora-commons-developers

Reply via email to