Integrating Heterogeneous Web Service Styles with Flexible Semantic Web Services Groundings
Dave Lambert, Neil Benn, and John Domingue Knowledge Media Institute, The Open University
Milton Keynes, United Kingdom
Semantic web services are touted as a means to integrate web services inside and outside the enterprise, but while current semantic web service frameworks—
including OWL-S [1], SA-WSDL , and WSMO
1[2]—assume a homogeneous ecosys- tem of SOAP services and XML serialisations, growing numbers of real services are implemented using XML-RPC and REST ful interfaces, and non- XML serialisations like JSON .
2Semantic services platforms based on OWL-S and WSMO use XML mapping languages to translate between an XML serialisation of the ontology data and the on-the-wire messages exchanged with the web service, a process referred to as grounding. This XML mapping approach suffers from two problems:
it cannot address the growing number of non- SOAP , non- XML services being deployed on the Web, and it requires the modeller creating the semantic web service descriptions to work with the serialisation of the service ontology and a syntactic mapping language, in addition to the knowledge representation language used for representing the semantic service ontologies and descriptions.
Our approach draws the service’s interface into the ontology: we define ontology objects that represent the whole HTTP message, and use backward- chaining rules to translate between semantic service invocation instances and the HTTP messages passed to and from the service. This novel approach is based on several principles:
1. Target HTTP , the Web’s native protocol: all three Web services approaches in use today, namely SOAP , XML-RPC , and REST ful, use HTTP .
2. Be agnostic about content type: HTTP carries not only XML , but other text serialisations such as JSON , as well as images, sound, and other data.
3. Stay within the ontology language: the fewer languages the service semantics engineer must deal with, the better.
When a semantic broker invokes a web service, it translates an abstract ontological representation of the service invocation into an HTTP message that can be sent to the server. The server’s response is, in due course, translated from the HTTP message to an ontological representation of the result. These two processes are respectively known as lowering and lifting. In our scheme we define two generic rules, which we call lower and lift :
( l o w e r ? s e r v i c e T y p e ? s e r v i c e I n v o c a t i o n ? h t t p R e q u e s t ) ( l i f t ? s e r v i c e T y p e ? h t t p R e s p o n s e ? s e r v i c e I n v o c a t i o n )
1
The WSMO specification deftly sidesteps the issue of grounding to any kind of Web service, current WSMO implementations are SOAP-centric.
2
http://www.json.org/
Each web service description can define its own version of lift and lower , which the broker distinguishes by unifying on the ?serviceType parameter that names the service being invoked. The ?serviceInvocation represents the abstract invocation message, and ?httpRequest and ?httpResponse the ontological representations of the on-the-wire messages. The lower rule’s successful fulfilment leads to the instantiation of ?httpRequest , which can then be directly interpreted by the broker to call the web service. When a response is received from the server, the lift rule runs on the the newly returned ?httpResponse , modifying the original ?serviceInvocation frame to record the return values. We have fully implemented the approach in the Internet Reasoning Service ( IRS ),
3a broker based on WSMO and using OCML
4for its ontology language. In another paper [3]
we showed how the approach integrates REST ful and XML-RPC services, and we now demonstrate the same approach cleanly extends to JSON serialisations.
JSON is a simple data format derived from Javascript, and is increasingly popular as a lightweight alternative to XML , particularly in REST ful services.
Our lift and lower rules could directly manipulate the string representations of JSON , but this becomes cumbersome, prone to error, and fails to model in any meaningful way the transformations. Instead, we introduce a simple ontologisation of JSON . JSON is built on two main structures: objects and arrays. An object is an unordered set of key/value pairs, whereas an array is a sequence of values.
Values are strings, numbers, booleans, other objects or arrays, or null . Our JSON ontologisation in OCML introduces a top-level class Value , which is then subclassed by Object and Array . An Object is made up of a list of Members , where each element of the list is a Pair consisting of a key (a string) and a Value . An Array is made up of a list of Elements , where each element of the list is a Value . Finally, the JSON value-types string, number, and boolean, are matched to OCML ’s equivalent built-in types, while JSON null values are treated as OCML nil . The OCML relation serialiseJson converts between JSON ontologisations in OCML , and the string containing the serialised JSON . The key definitions are:
( def - c l a s s V a l u e () ? v a l u e : s u f f i c i e n t
( or ( S t r i n g ? v a l u e ) ( N u m b e r ? v a l u e ) ( B o o l e a n ? v a l u e ) (= ? v a l u e nil ))) ( def - c l a s s O b j e c t ( V a l u e )
(( m e m b e r s : t y p e M e m b e r s ))) ( def - c l a s s A r r a y ( V a l u e )
(( e l e m e n t s : t y p e E l e m e n t s )))
( def - c l a s s E l e m e n t s () ? e l e m e n t s : iff - def ( and ( l i s t p ? e l e m e n t s )
( e v e r y ? e l e m e n t s V a l u e ))) ( def - c l a s s M e m b e r s () ? m e m b e r s
: iff - def ( and ( l i s t p ? m e m b e r s ) ( e v e r y ? m e m b e r s P a i r ))) ( def - c l a s s P a i r ()
(( key : t y p e S t r i n g ) ( v a l u e : t y p e V a l u e )))
To illustrate how we can invoke, in a uniform way, Web services employing JSON and XML formats, we use two Flickr
5services: a) getting a list of recently changed photos in a user’s account ( flickr.photos.recentlyUpdated ), and b) getting a list of sizes in which those are available ( flickr.photos.getSizes ). We will ground
3
http://technologies.kmi.open.ac.uk/irs/
4
http://technologies.kmi.open.ac.uk/ocml/
5
http://www.flickr.com/services/api/
the first service in a REST ful way, consuming JSON output, and the second service via XML-RPC , consuming XML output, integrating the services at the ontological level. We begin with lowering rule for the flickr.photos.recentlyUpdated service:
( def - r u l e lower - for - p h o t o s R e c e n t l y U p d a t e d / R e s t J s o n
(( l o w e r p h o t o s R e c e n t l y U p d a t e d / R e s t J s o n ? i n v o c a t i o n ? http - r e q u e s t ) if (= ? a c c o u n t ( wsmo - role - v a l u e ? i n v o c a t i o n h a s A c c o u n t ))
(= ? t o k e n ( wsmo - role - v a l u e ? i n v o c a t i o n h a s T o k e n ))
(= ? min - d a t e ( wsmo - role - v a l u e ? i n v o c a t i o n h a s M i n i m u m D a t e )) ( h a s K e y ? a c c o u n t ? a p i k e y )
( h a s V a l u e ? a p i k e y ? apikey - s t r i n g ) ( h a s V a l u e ? t o k e n ? token - s t r i n g ) (= ? a r g s ( new - i n s t a n c e A r g u m e n t s ))
( a d d A r g u m e n t ? a r g s " m e t h o d " " f l i c k r . p h o t o s . r e c e n t l y U p d a t e d ") ( a d d A r g u m e n t ? a r g s " a p i _ k e y " ? apikey - s t r i n g )
( a d d A r g u m e n t ? a r g s " a u t h _ t o k e n " ? token - s t r i n g ) ( a d d A r g u m e n t ? a r g s " m i n _ d a t e " ? min - d a t e ) ( a d d A r g u m e n t ? a r g s " f o r m a t " " j s o n ") ( a d d A r g u m e n t ? a r g s " n o j s o n c a l l b a c k " " 1 " ) ( s i g n A r g u m e n t s r e s t ? a r g s ? a c c o u n t ) ( a r g s T o R e s t R e q u e s t ? a r g s ? http - r e q u e s t )))
The rule is straightforward, with the first half concerned with extracting from the ?invocation the necessary argument values, and the second half constructing an Arguments instance using those values. The rule signArguments takes care of signing arguments with a valid Flickr account key, while argstoRestRequest takes care of converting the arguments set to URL parameters of the form
p a r a m 1 = v a l u e 1 & p a r a m 2 = v a l u e 2 ...
and sets the ?http-request fields appropriately (neither rule is shown due to space constraints, but they are relatively simple). The lifting rule is:
( def - r u l e lift - for - p h o t o s R e c e n t l y U p d a t e d / R e s t J s o n
(( l i f t p h o t o s R e c e n t l y U p d a t e d / R e s t J s o n ? http - r e s p o n s e ? i n v o c a t i o n ) if ( r f c 2 6 1 6 : get - c o n t e n t ? http - r e s p o n s e ? http - c o n t e n t )
( j s o n : s e r i a l i s e J s o n ? j s o n ? http - c o n t e n t ) ( j s o n : O b j e c t ? j s o n )
( j s o n : m e m b e r s ? j s o n ? o b j M e m b e r s )
( m e m b e r ? p h o t o s K e y V a l u e P a i r ? o b j M e m b e r s ) ( j s o n : key ? p h o t o s K e y V a l u e P a i r " p h o t o s ")
( j s o n : v a l u e ? p h o t o s K e y V a l u e P a i r ? i n n e r P h o t o s O b j e c t ) ( e x t r a c t P h o t o L i s t F r o m J s o n ? i n n e r P h o t o s O b j e c t ? p h o t o l i s t ) ( set - goal - slot - v a l u e ? i n v o c a t i o n h a s P h o t o L i s t ? p h o t o l i s t )))
In lifting the response, we extract the content from the ?http-response into an ontological model of the JSON . This extraction is done through the two rules extractPhotoListFromJson and extractPhotoFromJson defined below:
( def - r u l e e x t r a c t P h o t o L i s t F r o m J s o n
(( e x t r a c t P h o t o L i s t F r o m J s o n ? i n n e r P h o t o s O b j e c t ? p h o t o l i s t ) if (= ? p h o t o l i s t
( s e t o f a l l ? p h o t o
( and ( j s o n : O b j e c t ? i n n e r P h o t o s O b j e c t )
( j s o n : m e m b e r s ? i n n e r P h o t o s O b j e c t M e m b e r s )
( m e m b e r ? p h o t o K e y V a l u e P a i r ? i n n e r P h o t o s O b j e c t M e m b e r s ) ( j s o n : key ? p h o t o K e y V a l u e P a i r " p h o t o ")
( j s o n : v a l u e ? p h o t o K e y V a l u e P a i r ? p h o t o O b j e c t ) ( e x t r a c t P h o t o F r o m J s o n ? p h o t o O b j e c t ? p h o t o ) ) ) ) ) ) ( def - r u l e e x t r a c t P h o t o F r o m J s o n
(( e x t r a c t P h o t o F r o m J s o n ? p h o t o O b j e c t ? p h o t o ) if ( j s o n : O b j e c t ? p h o t o O b j e c t )
( j s o n : m e m b e r s ? p h o t o O b j e c t ? p h o t o O b j e c t M e m b e r s )
( m e m b e r ? i d K e y V a l u e P a i r ? p h o t o O b j e c t M e m b e r s ) ( j s o n : key ? i d K e y V a l u e P a i r " id ")
( j s o n : v a l u e ? i d K e y V a l u e P a i r ? id )
( m e m b e r ? t i t l e K e y V a l u e P a i r ? p h o t o O b j e c t M e m b e r s ) ( j s o n : key ? t i t l e K e y V a l u e P a i r " t i t l e ")
( j s o n : v a l u e ? t i t l e K e y V a l u e P a i r ? t i t l e ) (= ? s l o t s (( id ? id ) ( t i t l e ? t i t l e ))) ( new ? p h o t o P h o t o ? s l o t s )))
With this list of photographs, represented in OCML , we are now ready to invoke the second service, flickr.photos.getSizes , using XML-RPC .
( def - r u l e lower - for - p h o t o s G e t S i z e s / X m l r p c
(( l o w e r p h o t o s G e t S i z e s / X m l r p c ? i n v o c a t i o n ? http - r e q u e s t ) if ( a r g s F o r P h o t o s G e t S i z e s ? i n v o c a t i o n ? a r g s )
(= ? a c c o u n t ( wsmo - role - v a l u e ? i n v o c a t i o n h a s A c c o u n t )) ( s i g n A r g u m e n t s x m l r p c ? a r g s ? a c c o u n t )
( a r g s T o X m l r p c R e q u e s t ? a r g s ? http - r e q u e s t )))
This time, the conversion from the invocation object to the argument pairs used by Flickr is done in another rule argsForPhotosGetSizes (not shown). The use of a rule for this means we could share the logic between the XML-RPC version shown here, and a REST or SOAP version. The argument set is again signed using signArguments , and then passed to the rule argsToXmlrpcRequest :
( def - r u l e a r g s T o X m l r p c R e q u e s t
(( a r g s T o X m l r p c R e q u e s t ? a r g s ? http - r e q u e s t ) if ( g e t A r g u m e n t ? a r g s " m e t h o d " ? m e t h o d )
(= ? n o n m e t h o d a r g s ( s e t o f a l l ? m e m b e r
( and ( h a s A r g u m e n t ? a r g s ? arg ) ( h a s N a m e ? arg ? n a m e ) ( not (= ? n a m e " m e t h o d ")) ( h a s V a l u e ? arg ? v a l u e )
(= ? m e m b e r ( x m l r p c : M e m b e r ? n a m e
( x m l r p c : S t r i n g ? v a l u e ) ) ) ) ) ) (= ? x m l r p c ( x m l r p c : M e t h o d C a l l ? m e t h o d
( x m l r p c : P a r a m ( x m l r p c : S t r u c t ? n o n m e t h o d a r g s ) ) ) ) ( x m l r p c : m a p T o X m l ? x m l r p c ? x m l m o d e l )
( xml : s e r i a l i s e X m l ? x m l m o d e l ? x m l s t r i n g ) ( r f c 2 6 1 6 : set - c o n t e n t ? http - r e q u e s t ? x m l s t r i n g ) ( r f c 2 6 1 6 : set - m e t h o d ? http - r e q u e s t " P O S T ")
( r f c 2 6 1 6 : set - url ? http - r e q u e s t " h t t p :// api . f l i c k r . com / s e r v i c e s / x m l r p c / " ) ) )