web service - isti.cnr.itmartinelli/xml/doc/webservices/web_services_290410.pdf · conto della...
TRANSCRIPT
Web ServiceWeb Service
IntroduzioneIntroduzione
Massimo Martinelli
Consiglio Nazionale delle Ricerche - CNRIstituto di Scienza e Tecnologie della Informazione - ISTI
29/05/2010, Area Ricerca CNR, Pisa
Il software nell'era di InternetEsistono - 2500 linguaggi di programmazione (dato del 2007)- più di 1200 sistemi operativi
SW installato su dispositivi eterogenei: palmare, televisore, automobile...
SW costa scriverlo, modificarlo, sostituirlo: - risorse finanziarie e umane
Raro: programma che funziona da solo (senza collegarsi ad altri programmi o risorse installate su dispositivi, sistemi operativi e linguaggi differenti)
L'interoperabilità del software non è una moda, è un'esigenza
I Web Service forniscono un metodo per far interagire programmi in modo indipendente dal linguaggio e dalla piattaforma
Interoperabilità
Come fanno due applicazioni a comunicare tra loro ?
Varie soluzioni proposte in passato: DCE - procedurale RPC, …
ORB - object oriented COM, DCOM, CORBA, RMI, EJB, …
MOM -- message oriented JMS, …
PROBLEMA: generalmente servono a mettere in comunicazione due programmi
utilizzando un formato binario in modo sincrono tra implementazioni equivalenti (stesso linguaggio e piattaforma) e/o proprietarie in una rete intranet sicura in un modo piuttosto complicato
Le possibili soluzioni devono prevedere
• Indipendenza dalla piattaforma e dal linguaggio (separazione della specifica dall’implementazione)
• Interazioni basate su messaggi sincroni e anche asincroni
• Comunicazioni su Internet (non solo intranet)
• Protocolli standard prestabiliti che tengano di conto della sicurezza
Le soluzioni emerse ad oggi
XML-RPC SOAP
REST
XML-RPC si basa su uno scambio di informazioni codificate tramite un XML molto semplice e utilizza HTTP come mezzo di trasporto
SOAP (XML-Protocol) ha una specifica più ampia basata su XML, utilizza HTTP/HTTPS come protocollo di trasporto ma prevede il supporto per altri protocolli ( SMTP, FTP, TCP diretto, …)
REST mette a disposizione dei metodi (API) che mappano le azioni HTTP come GET, PUT, POST, DELETE per gestire le informazioni sul server remoto
Lo scambio di informazioni può essere basato su XML ma non è vincolante come per XML-RPC e SOAP (utilizza una forma libera)
simili
Limiti di XML-RPC
Sincronia: risposta avviene sulla stessa connessione HTTP richiesta Gestione problemi timeout o errori calcolo
Stateless: HTTP non mantiene lo stato, non ha un concetto di sessione, ogni richiesta-risposta ha una vita a se
programmazione procedurale: scarsa gestione degli oggetti
HTTP pensato per far comunicare browser e server non applicazione e applicazione
Manca la gestione della sicurezza
SOA Service Oriented Architecture
RegistrodeiServizi
pubblicazione
Fornitoredi unServizio
fornisco questo serviziocon questi criteri
Richiedentedi unServizio
ricer
cacerco un servizio che mi consenta di …
utilizzo del servizio(bind)
vorrei utilizzare questo servizio…
prova questo …
Cosa è un Web Service
Definizione e significato in evoluzione
Definizione formale secondo il W3C: “Un Web service è una applicazione software
identificata da un identificatore univoco delle risorse (URI), le cui interfacce e i binding (protocolli e codifiche) sono in grado di essere definite, descritte e ricercate tramite artefatti XML e supporta interazioni dirette con altre applicazioni software usando messaggi basati su XML tramite protocolli basati sui internet.”
Web Services: tecnologie standard Protocollo di comunicazione
HTTP/HTTPS, previsti anche anche SMTP, FTP, TCP, … Codifica delle informazioniSOAP (Simple Object Access Protocol), XML Schema
Descrizione dell’interfaccia
WSDL (Web Services Definition Language) Descrizione e ricerca del servizio
UDDI (Universal Description, Discovery and Integration protocol)
Sicurezza
WS-Security(WS-Secure Conversation, WS-Federation, WS-Authorization, WS-Policy, WS-Trust, WS-Privacy), XML-Signature, XML-Encryption, ...
SOA Service Oriented Architecture
RegistrodeiServizi
Richiedentedi unServizio
Fornitoredi unServizio
ricer
ca
pubblicazione
utilizzo del servizio(bind)
uddi
wsdl soap
uddi
SOAP
Semplice protocollo XML per scambio di informazione strutturata su Internet in modo decentralizzato in ambienti distribuiti
Si basa su: Un contenitore (envelope) che definisce una struttura per
descrivere il contenuto del messaggio (body) e chi e come deve elaborarlo (header opzionale)
Un insieme di regole di codifica per esprimere istanze di tipi di dato definiti da applicazioni e una convenzione per rappresentare chiamate a procedure remote e le risposte
EnvelopeXML
HeaderBody
codifica XML
Modalità SOAP: Messaggio e SOAP-RPC
Messaggio (one-way/senso unico)
Chiamata di procedura remotae risposta
Applicazione 1 Applicazione 2
Comunicazione asincrona e sincrona
Modello di elaborazione SOAP:mittente, intermediari e destinatario finale
SOAP Envelope
SOAP HeaderHeader Block: aaa
SOAP Body
Body sub-element: x
Body sub-element: y
SOAP Envelope
SOAP HeaderHeader Block: aaa
Header Block: bbb
SOAP Body
Body sub-element: x
Body sub-element: y
SOAP Envelope
SOAP HeaderHeader Block: aaa
SOAP Body
Body sub-element: x
Body sub-element: y
Header Block: bbb
Applicazione 1 Intermediario 1
Header Block: bbb
Intermediario 2
Body: riservato al destinatario finale
• I blocchi header processati devono essere rimossi• Intermediario attivo (elabora) o passivo (gira il messaggio ad un’altro nodo)
Come funziona SOAP
Un esempio:
supponiamo che l’ipotetico richiedente Mario Rossi di voglia prenotare un viaggio presso una agenzia
richiedente invia messaggio all’agenzia chiedendo di fare una prenotazione per un viaggio da Lucca a Olbia
destinatario ultimo (recipient) del messaggio SOAP spedito dall’applicazione è il servizio fornito dall’agenzia di viaggi. Possibile che il messaggio venga girato tra a uno o più intermediari SOAP che agiscono in qualche modo sul messaggio (log, verifica, modifica, …)
La richiesta SOAP (Messaggio)
SOAP Envelope
SOAP Header
Header Block: prenotazione
Header Block: passeggero
SOAP Body
Body sub-element: itinerario
Body sub-element: alloggio
La richiesta SOAP (Messaggio)<?xml version='1.0' ?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"> <env:Header> <m:prenotazione xmlns:m="http://compagniaviaggi.esempio.org/prenotazione" env:role="http://www.w3.org/2003/05/soap-envelope/role/next“role="http://www.w3.org/2003/05/soap-envelope/role/next“ env:mustUnderstand="true"mustUnderstand="true"> <m:riferimento>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:riferimento> <m:data_e_ora>2010-04-15T12:20:00.000-05:00</m:data_e_ora> </m:prenotazione> <n:passeggero xmlns:n="http://miacompagnia.esempio.com/impiegati" env:role="http://www.w3.org/2003/05/soap-envelope/role/next“ env:mustUnderstand="true"> <n:nome>Mario Rossi</n:nome> </n:passeggero> </env:Header> <env:Body> <p:itinerario xmlns:p="http://compagniaviaggi.esempio.org/prenotazione/viaggio"> <p:andata> <p:partenza_da>Lucca</p:partenza_da> <p:arrivo_a>Olbia</p:arrivo_a> <p:data_partenza>2010-06-19</p:data_partenza> <p:ora_partenza>mattina</p:ora_partenza> <p:preferenza_posto>finestrino</p:preferenza_posto> </p:andata> <p:ritorno> <p:partenza_da>Olbia</p:partenza_da> <p:arrivo_a>Lucca</p:arrivo_a> <p:data_partenza>2010-06-26</p:data_partenza> <p:ora_partenza>sera</p:ora_partenza> <p:preferenza_posto /> </p:ritorno> </p:itinerario> <q:alloggio xmlns:q=" http://compagniaviaggi.esempio.org/prenotazione/alberghi"> <q:preferenza>non mi spennare, please</q:preferenza> </q:alloggio> </env:Body></env:Envelope>
Messaggio SOAP
L’agenzia invia un messaggio di chiarimento: ci sono 3 possibili aeroporti da cui partire
(Pisa, Firenze, Roma)
Messaggio SOAP<?xml version='1.0' ?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"> <env:Header> <m:prenotazione xmlns:m="http://compagniaviaggi.esempio.org/prenotazione" env:role="http://www.w3.org/2003/05/soap-envelope/role/next“ env:mustUnderstand="true"> <m:riferimentoe>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:riferimento> <m:data_e_ora>2010-04-15T12:20:00.000-05:00</m:data_e_ora> </m:prenotazione> <n:passeggero xmlns:n="http://miacompagnia.esempio.com/impiegati" env:role="http://www.w3.org/2003/05/soap-envelope/role/next“ env:mustUnderstand="true"> <n:nome>Mario Rossi</n:nome> </n:passeggero> </env:Header> <env:Body> <p:chiarimento_itinerario xmlns:p="http://compagniaviaggi.esempio.org/prenotazione/viaggio"> <p:andata> <p:partenza_da> <p:possibili_aeroporti> Pisa Firenze Roma </p:possibili_aeroporti> </p:partenza_da> </p:andata> <p:ritorno> <p:arrivo_a> <p:possibili_aeroporti> Pisa Firenze Roma </p:possibili_aeroporti> </p:arrivo_a> </p:ritorno> </p:chiarimento_itineratio> </env:Body></env:Envelope>
I dati del richiedentenon si perdono, vengono spostati nell’Header
La richiesta di chiarimento(dell’agenzia)viene messa nel Body
Messaggio SOAP<?xml version='1.0' ?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"> <env:Header> <m:prenotazione xmlns:m="http://compagniaviaggi.esempio.org/prenotazione" env:role="http://www.w3.org/2003/05/soap-envelope/role/next“ env:mustUnderstand="true"> <m:riferimentoe>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:riferimento> <m:data_e_ora>2010-04-15T12:20:00.000-05:00</m:data_e_ora> </m:prenotazione> <n:passeggero xmlns:n="http://miacompagnia.esempio.com/impiegati" env:role="http://www.w3.org/2003/05/soap-envelope/role/next“ env:mustUnderstand="true"> <n:nome>Mario Rossi</n:nome> </n:passeggero> </env:Header> <env:Body> <p:itinerario xmlns:p="http://compagniaviaggi.esempio.org/prenotazione/viaggio"> <p:andata> <p:partenza_da> Pisa </p:partenza_da> </p:andata> <p:ritorno> <p:arrivo_a> Pisa </p:arrivo_a> </p:ritorno> </p:itineratio> </env:Body></env:Envelope>
I dati del richiedentesono sempre a disposizione
la scelta dell’aeroporto è nel Body
SOAP-RPC
Dopo una serie di messaggi il richiedente conferma l’itinerario ed effettua il pagamento tramite carta di creditoL’agenzia procede pagando presso una terza
parte (es: compagnia aerea o albergo – per semplicità è una sola)
In questo caso non si tratta in un semplice messaggio “one-way” ma viene chiamata una procedura remota che restituirà un risultato (il codice di prenotazione)
SOAP-RPC: la richiesta del servizio <?xml version='1.0' ?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" > <env:Header> <t:transazione xmlns:t="http://terzaparte.esempio.org/transazione" env:encodingStyle="http://esempio.com/encoding" env:mustUnderstand="true" >5</t:transazione> </env:Header> <env:Body> <m:pagamento_prenotazione env:encodingStyle="http://www.w3.org/2003/05/soap-encoding" xmlns:m="http://compagniaviaggi.esempio.org/"> <m:prenotazione xmlns:m="http://compagniaviaggi.esempio.org/prenotazione"> <m:codice>FT35ZBQ</m:codice> </m:prenotazione> <o:carta_di_credito xmlns:o="http://miacompagnia.esempio.com/finanziaria"> <n:nome xmlns:n="http://miacompagnia.esempio.com/impiegati"> Mario Rossi </n:nome> <o:numero>123456789099999</o:numero> <o:scadenza>2010-04-30</o:scadenza> </o:carta_di_credito> </m:pagamento_prenotazione> </env:Body></env:Envelope>
SOAP-RPC: la risposta (Response)
<?xml version='1.0' ?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" > <env:Header> <t:transazione xmlns:t="http://terzaparte.esempio.org/transazione" env:encodingStyle="http://example.com/encoding" env:mustUnderstand="true">5</t:transazione> </env:Header> <env:Body> <m:pagamento_prenotazioneResponse env:encodingStyle="http://www.w3.org/2003/05/soap-encoding" xmlns:m="http://compagniaviaggi.esempio.org/"> <m:codice>FT35ZBQ</m:codice> <m:vedere_a> http://compagniaviaggi.esempio.org/prenotazioni?codice=FT35ZBQ </m:vedere_a> </m:pagamento_prenotazioneResponse > </env:Body></env:Envelope>
L’agenzia manda la conferma al richiedente
Due parametri in output (out)codice - vedere_a
SOAP-RPC: rpc:result<?xml version='1.0' ?><env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" > <env:Header> <t:transazione xmlns:t="http://terzaparte.esempio.org/transazione" env:encodingStyle="http://example.com/encoding" env:mustUnderstand="true">5</t:transazione> </env:Header> <env:Body> <m:pagamento_prenotazioneResponse env:encodingStyle="http://www.w3.org/2003/05/soap-encoding" xmlns:rpc="http://www.w3.org/2003/05/soap-rpc" xmlns:m="http://travelcompany.example.org/"> <rpc:result>m:status</rpc:result><rpc:result>m:status</rpc:result> <m:stato>confermato</m:stato> <m:codice>FT35ZBQ</m:codice> <m:vedi_a> http://compagniaviaggi.esempio.org/prenotazioni?codice=FT35ZBQ </m:vedi_a> </m: m:pagamento_prenotazioneResponse > </env:Body></env:Envelope> Altro modo per inviare la conferma
Un valore di return e due parametri out
Web Service Definition Language (WSDL) Supponiamo un fornitore metta a disposizione il seguente servizio:
public class Converti { public double inLire(double euro) { return euro*1936.27; } }
Come lo descrive ? La classe Converti mette a disposizione un metodo inLire che richiede un parametro di tipo double e restituisce un risultato di tipo double
Ci siamo (quasi) ! Questo è il ruolo di WSDL
• Solo noi umani riusciremo a capire una tale descrizione, proviamo a scriverla in un formato “comprensibile” da una macchina
<?xml version=“1.0”?> <definizioni> <servizio nome=“Converti”> <metodo nome=“inLire”> <parametro nome=“euro” tipo=“double”> <risultato nome=“Responso_inLire” tipo=“double”> </metodo> </servizio> </definizioni>
Web Service Definition Language (WSDL)
WSDL è un linguaggio che fornisce un modello e un formato XML per descrivere servizi di rete
Il documento XML contiene una serie di definizioni
Analisi del documento WSDL
<definitions> l’elemento radice
<types> tipi di dati che verranno trasmessi, generalmente XML-Schema
<message> messaggi che verranno trasmessi descrive un messaggio (asincrono, o di richiesta o di risposta) definisce il nome del messaggio e può contenere elementi <part> che specificano eventuali parametri o valori di ritorno (risultati).
<portType> operazioni/funzioni che saranno supportate definite tramite un elenco di <operations> (se pensiamo a java sono le classi e i metodi messi a disposizione)
<binding> come i messaggi verranno trasmessi (http, smtp, …) e la codifica
<service> dov’è il servizio (generalmente l’URL) (endpoint)
tipi
SOAP definisce un tipo di codifica che è possibile utilizzare
basata su una prima versione di XML-Schema
E’ possibile utilizzarne un’altra In questo caso è necessario specificarla tramite
l’attributo env:encodingStyle Esempio con RDF
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:x="http://compagniaviaggi.esempio.org/vocab#" env:encodingStyle="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <x:ReservationRequest rdf:about="http://compagniaviaggi.esempio.org/prenotazioni?codice=FT35ZBQ">
….</rdf:RDF>
S
Mapping dei tipi tra SOAP-XML e Java
xsd:base64Binary byte[] xsd:boolean boolean xsd:byte byte xsd:dateTime java.util.Calendar xsd:decimal java.math.BigDecimal xsd:double double xsd:float float xsd:hexBinary byte[] xsd:int int xsd:integer java.math.BigInteger xsd:long long xsd:Qname javax.xml.namespace.QName xsd:short short xsd:string java.lang.String
S
messaggi
<wsdl:message name="inLireRequest"> <wsdl:part name="euro" type="xsd:double" /> </wsdl:message>
<wsdl:message name="inLireResponse"> <wsdl:part name="inLireReturn" type="xsd:double" /> </wsdl:message>
S
operazioni
<wsdl:portType name="Converti">
<wsdl:operation name="inLire" parameterOrder="euro"> <wsdl:input message="impl:inLireRequest" name="inLireRequest" /> <wsdl:output message="impl:inLireResponse" name="inLireResponse" /> </wsdl:operation>
</wsdl:portType>
S
Binding (adattatore protocollo in altre tecnologie) + encoding (codifica)
<wsdl:binding name="ConvertiSoapBinding" type="impl:Converti">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="inLire"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="inLireRequest"> <wsdlsoap:body use="encoded“ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/“ namespace="urn:Converti"/> </wsdl:input> <wsdl:output name="inLireResponse"> <wsdlsoap:body use="encoded“ encodingStyle="http://schemas.xmlsoap.org/soap/encoding/“ namespace="urn:Converti"/> </wsdl:output> </wsdl:operation>
</wsdl:binding>
S
Endpoint (metodi eseguibili del WS)
<wsdl:service name="ConvertiService">
<wsdl:port name="Converti" binding="impl:ConvertiSoapBinding">
<wsdlsoap:address location="http://localhost:8080/axis/services/Converti"/>
</wsdl:port>
</wsdl:service>
S
Il documento WSDL relativo al servizio “Converti”<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions targetNamespace="urn:Converti" xmlns:impl="urn:Converti" xmlns:intf="urn:Converti" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <wsdl:message name="inLireResponse"> <wsdl:part name="inLireReturn" type="xsd:double"/> </wsdl:message> <wsdl:message name="inLireRequest"> <wsdl:part name="euro" type="xsd:double"/> </wsdl:message> <wsdl:portType name="Converti"> <wsdl:operation name="inLire" parameterOrder="euro"> <wsdl:input name="inLireRequest" message="impl:inLireRequest"/> <wsdl:output name="inLireResponse" message="impl:inLireResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ConvertiSoapBinding" type="impl:Converti"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="inLire"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="inLireRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Converti"/> </wsdl:input> <wsdl:output name="inLireResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Converti"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ConvertiService"> <wsdl:port name="Converti" binding="impl:ConvertiSoapBinding"> <wsdlsoap:address location="http://localhost:8080/axis/services/Converti"/> </wsdl:port> </wsdl:service></wsdl:definitions>
<?xml version="1.0" ?><!-- stile Unwrapped --><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soapenv:Body> <num1 xmlns:ans="http://calcoli/">3</num1> <num2 xmlns:ans="http://calcoli/">5</num2> </soapenv:Body></soapenv:Envelope>
<?xml version="1.0" ?><!-- stile Wrapped --><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soapenv:Body> <somma xmlns:ans="http://calcoli/"> <num1>3</num1> <num2>5</num1> </somma> </soapenv:Body></soapenv:Envelope>
package calcoli; @WebServicepublic interface Calcola { @WebMethod int somma(int num1, int num2);}
Stile Wrapped DOCUMENTPer ottenere il massimo dai due stili (RPC e DOCUMENT) si sta diffondendo un nuovo stile: Wrapped Document
S
UDDI - Universal Description, Discovery and Integration
Un server UDDI è un registro di Servizi Web Permette la pubblicazione e la ricerca di Servizi Web
Mette a disposizione 3 tipi di informazione Pagine Bianche: informazioni anagrafiche delle aziende, come
l'indirizzo ed i numeri di telefono Pagine gialle: informazioni che indicano la categoria dei servizi e
delle aziende Pagine verdi: informazioni tecniche per comunicare con un servizio
web (url, wsdl,…)
Il registro è sincronizzato con altri nodi in modo simile al DNS. Quando viene pubblicato un servizio su un nodo questo lo propaga agli altri.
UDDI demo
Colleghiamoci a questo indirizzo(bisogna prima registrarsi)https://uddi.ibm.com/ubr/registry.html
http://www.soapclient.com/uddisearch.html(browser)
http://uddi.microsoft.com/
http://uddi4j.org/
Sun JAXR
Esempio di ricerca: messaggio SOAP The che può essere spedito ad un registro UDDI per cercare servizi di nome “prenotazione viaggi":
<?xml version="1.0" encoding="UTF-8"?><Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Body><find_service businessKey="*" generic="1.0" xmlns="urn:uddi-org:api"> <name>prenotazione viaggi</name></find_service></Body></Envelope>
Altre possibilità di ricerca: es. per categoria
Esempi di Servizi Web
Google: http://www.google.com/apisOntologie per migliorare la ricerca
Amazon: http://simplest-shop.com/camera
Interoperabilità (linguaggi e piattaforme diverse)
Poichè i messaggi e le chiamate di procedura avvengono utilizzando XML è semplice realizzare programmi scritti con linguaggi differenti che interagiscono tra loro.
Esempi in Java, .NET, man anche in php, perl pypthon sono reperibili facilmente su internet
VB6 client (Microsoft SOAP Toolkit) – Java server (Axis): clientVBConverti.txt
Bibliografia
XML Protocol / SOAP http://www.w3.org
Sun: JWS Tutorial http://java.sun.com UDDI: http://www.uddi.org/
Understanding XML Web Services:The Web Services Idea http://msdn.microsoft.com/webservices/understanding/readme/default.aspx
Java Web Services – O’Reilly Java Web Services Up and Running – O'Reilly