Professional Documents
Culture Documents
Service Component Architecture For PHP Konferenz 2006 Begin End
Service Component Architecture For PHP Konferenz 2006 Begin End
1
How to find us
• Google for OSOA
• (Open Service Oriented Architecture)
2
Agenda
• Two slide-overview
• Some simple SCA components (hello world–style)
• Components calling each other locally
• Make them all run as web services
• (Slides and Zend Studio)
• More SCA:
• Interoperability with other web services
• Exceptions
• Data Structures
• Work in progress: DOJO, JSON-RPC and SCA
• Summary, Futures and Links
3
Service Component Architecture
SWG AB Incubators
for PHP
• SCA for PHP allows a PHP programmer to write reusable
components (classes) in PHP, which can be called
either locally, or remotely via Web Services, with an
identical interface.
4
Making your component reusable
• Do not entangle the business logic with the “wiring”
A local component,
Same call stack
Local binding
2. Be flexible about
A component,
1. Be flexible about Web service binding containing
your dependencies
how you are called business logic
5
Four scenarios
1. One component called locally
2. One component calling two others
3. Make the single component expose a
Web service binding
4. Make them all use web services
6
Scenario 1. Simplest
• A client script calling one local
component
• What does the simplest SCA component
look like?
GreetingComponent
client
7
Our first simple SCA component
<?php
/**
• @service annotation * @service
*/
• include for SCA.php class GreetingComponent
{
public function greet($name)
{
return 'hello ' . $name;
}
}
?>
GreetingComponent
8
Calling an SCA component from a
client script
• Client script
• Includes SCA.php
• But is not itself a <?php
component
include 'SCA/SCA.php';
• Uses SCA::getService()
• getService takes a $service = SCA::getService('./GreetingComponent.php');
path
• Absolute or relative echo $service->greet('PHP');
• Relative paths are
resolved against the ?>
location of the script
"hello PHP"
• getService returns a
‘proxy’ object:
• Enforces pass-by-
value client GreetingComponent
9
Scenario 2. Multiple
• A local component calling other local
components
• How are the dependencies wired up?
GreetingComponent
client ReversedGreeting
Component ReversingComponent
"PHP olleh"
10
Add a second component
• Like GreetingComponent: <?php
include 'SCA/SCA.php';
• @service
• Include for SCA.php /**
* @service
*/
class ReversingComponent
{
function reverse ($in)
{
return strrev ($in);
}
ReversingComponent }
?>
11
Dependencies
<?php
include 'SCA/SCA.php';
• Dependencies are declared
• annotated with @reference /**
• The instance variable * @service
*/
following will be assigned a class ReversedGreetingComponent
proxy {
• Hence needs to be public /**
• Initialised before any * @reference
business logic * @binding.php GreetingComponent.php
*/
• @binding.php public $greeting_component;
• indicates how to find the
component /**
* @reference
• and that it is local * @binding.php ReversingComponent.php
• same rules as getService */
public $reversing_component;
?>
12
What have we got so far?
• Sample call stack:
reverse( $in ) C:\Program Files\Apache Group\Apache2\htdocs\Konferenz\ReversingComponent.php line 13
__call( $method_name, $arguments ) c:\php\PEAR\SCA\SCA_LocalProxy.php line 109
greet( $name ) C:\Program Files\Apache Group\Apache2\htdocs\Konferenz\ReversedGreetingComponent.php line 24
__call( $method_name, $arguments ) c:\php\PEAR\SCA\SCA_LocalProxy.php line 109
main( ) C:\Program Files\Apache Group\Apache2\htdocs\Konferenz\client2.php line 7
GreetingComponent
breakpoint
"PHP olleh"
13
Scenario 3. Web Service
• A client script calling one remote
component
• How to expose a web service binding
client GreetingComponent
14
Exposing a web service binding
<?php
• @binding include 'SCA/SCA.php';
• Expose a web service
binding /**
• Public methods are in the * @service
interface * @binding.ws
*/
• @param/@return
• Need more information class GreetingComponent
about each method {
/**
* @param string $name
* @return string
*/
public function greet($name)
{
GreetingComponent
return 'hello ' . $name;
}
}
?>
15
= SOAP Web service request/response
Generating the WSDL
• Generated in response to HTTP GET with ?wsdl
• http://www.example.com/GreetingComponent.php?wsdl
• Do it in a browser
• file_get_contents('http://www.example.com/GreetingCom
ponent.php?wsdl');
• Currently cached in the same directory as the
component
• http://www.example.com/GreetingComponent.wsdl
• (in future need to do something different to avoid
need for write access into htdocs)
16
Generated WSDL
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xsi:type="tDefinitions«
xmlns:tns2="http:// GreetingComponent"
xmlns:tns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns3="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
targetNamespace="http://GreetingComponent">
<types>
• Document/literal <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://GreetingComponent">
wrapped style <xs:element name="greet">
• Message <xs:complexType>
<xs:sequence>
formats are <xs:element name=“name" type="xs:string" nillable="true"/>
explicit within </xs:sequence>
the schema </xs:complexType>
</xs:element>
<xs:element name="greetResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="greetReturn" type="xs:string" nillable="true"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</types>
...
17
Generated WSDL
...
<message name="greetRequest">
<part name="greetRequest" element="tns2:greet"/>
• message … </message>
<message name="greetResponse">
<part name="return" element="tns2:greetResponse"/>
• post … </message>
<portType name="GreetingComponentPortType">
<operation name="greet">
18
Generated WSDL
• Location attribute is decided once the file is in place
• Currently using the URL to determine the location with respect to the
document root
• (in future need to do something different to cope with proxies,
rewriting, firewalls)
• Ends with a distinctive comment
• Special handling of exceptions when one component talks to another
...
<service name="GreetingComponentService">
<port name="GreetingComponentPort" binding="tns2:GreetingComponentBinding">
<tns3:address xsi:type="tAddress" location="http://www.example.com/GreetingComponent.php"/>
</port>
</service>
</definitions>
<!-- this line identifies this file as WSDL generated by SCA for PHP. Do not remove -->
19
Calling a remote SCA component from
a script
• SCA::getService() takes the <?php
location of the WSDL include 'SCA/SCA.php';
• Once again, $service is a
$service = SCA::getService(
proxy: SCA_SoapProxy 'http://www.example.com/GreetingComponent.wsdl');
• Proxy contains within it an
echo $service->greet();
instance of the ext/SOAP
client ?>
20
Sample Soap request
• Document/literal wrapped, so <greet>
element enclosing <name> element
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<tns:greet xmlns= "http://GreetingComponent"
xmlns:tns= "http://GreetingComponent"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="greet">
<name>PHP</name>
</tns:greet>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
21
Scenario 4. Multiple web service
• Everything separated
GreetingComponent
ReversedGreeting
client Component ReversingComponent
22
A second remote component
<?php
• Annotations include 'SCA/SCA.php';
• @binding
/**
• @param * @service
• @return * @binding.ws
*/
• And generate WSDL as
before class ReverseComponent
{
/**
* @param string $in
* @return string
*/
function reverse ($in)
ReversingComponent {
return strrev ($in);
}
}
?>
23
Remote dependencies
<?php
include 'SCA/SCA.php';
• @binding.ws /**
* @service
/**
* @reference
* @binding.ws ReversingComponent.wsdl
*/
public $reversing_component;
/**
* @param string $name
ReversedGreeting
Component * @return string
*/
public function greet($name)
{
$greeting = $this-> greeting_component->greet($name);
return $this->reversing_component->reverse($greeting);
}
}
24
?>
What have we got now?
• What have we achieved?
• Client <–> local <-> local
• Client <-> remote <-> remote
• What had to change?
• Arguments to getService(), or @binding.php to @binding.ws
• Annotatations to describe the interface in more detail
• Generating WSDL on demand; otherwise deployment is just copying the component
• But the business logic remains unchanged
GreetingComponent
ReversedGreeting
client Component ReversingComponent
25
Interlude
26
Futures
• Annotation overriding
• Changing service targets, bindings,
properties from outside
• PHP classes rather than xsds for data
structures
• Simple database services
• Other bindings
• Atompub, REST (XML and JSON), RSS
38
DOJO, JSON-RPC and SCA
• DOJO is a user interface widget set written in JavaScript
• Can talk back to the server asynchronously - AJAX style
• Can use JSON-RPC to do so
• JSON = JavaScript Object Notation
• Like a simplified XML
• Name/value pairs
• { for structure
• [ array
• A JSON-RPC interface can be defined in SMD = Service Method Description
• Like a simplified WSDL
• Also written in JSON
39
40
A component exposing a JSON
binding
• @binding.jsonrpc <?php
include 'SCA/SCA.php';
/**
• Generates .smd * @service
* @binding.jsonrpc
• <url>?smd */
class HelloService
{
• smd = service method /**
* @param string $name The name to say hello to
description * @return string The string hello <name>
*/
public function sayHello ($name)
{
return ‘hello ‘ . $name;
}
}
?>
41
HelloService.php?smd
• Defines a service that has:
• One method sayHello(), with …
• One parameter, name
{
"SMDVersion":".1",
"serviceType":"JSON-RPC",
"serviceURL":"http://localhost/Samples/JsonRpc/hello/HelloService.php",
"methods": [ {
"name":"sayHello",
"parameters": [ {
"name":"name",
"type":"string“
} ],
"return": {"type":"string"}
} ]
}
42
A DOJO function to call sayHello
• Obtain .smd
• Issue the call
function sayHello()
{
var SCA = new dojo.rpc.JsonService({smdUrl: "HelloService.php?smd"});
var inputfield = document.getElementById("hellotext").value;
SCA.sayHello(inputfield).addCallback(handleResponse);
}
43
JSON-RPC - POST
• POST Style - Request
POST /json-rpc/HelloService.php HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Type: application/json-rpc
Content-Length: 48
Pragma: no-cache
Cache-Control: no-cache
{"params":["Hello!"],"method":"sayHello","id":1}
{“return":"Hello "}
44
Links
• SCA for PHP homepage
• http://osoa.org/display/PHP/SOA+PHP+Homepage
• Discussion Group
• http://groups.google.com/group/phpsoa/
• Blog
• http://www.ibm.com/developerworks/blogs/page/phpblog
45
Acknowledgements
• Other members of the SCA for PHP team
• Graham Charters, Megan Beynon, Chris
Miller, Caroline Maynard, Simon Laws
• Special thanks to Dmitry Stogov for help
with the SOAP extension, serialising and
de-serialising SDOs
46
The end
47