Oct 14, 2011

SOAP Messages with Attachments

A héten futottam bele egy feladatba [problémába :)], amelynél webszolgáltatáson keresztül, nem csupán xml adatstruktúrát, de csatolt állományokat is fel kellett dolgoznom.
Egy report szerverről (java alapú) volt szó, amelynek ha elküldünk egy megfelelően felépített xml-t - mint paramétert - SOAP-on keresztül, akkor az annak megfelelő dokumentumot legenerálja, majd úgyszintén webszolgáltatáson keresztül szolgáltatja vissza. Ki lehet találni, hogy az elküldésnél még minden rendben volt, viszont amikor a válasz üzenet visszaérkezett, akkor jelentkezett a - igazából várt  - probléma.
Tegyük fel, hogy  pdf kiterjesztésben kérem el a dokumentumot. Ilyenkor a válasz üzenet multipart/related tartalom típussal (Content-Type) fog érkezni. Röviden ez azt jelenti (részletesebben itt), hogy bár egy üzenet érkezik válaszként, az több különálló részre lesz osztva. A Content-Type fejlécben megadott boundary értékével lesznek az egyes részek elválasztva, amelyek külön-külön fejlécekkel és egyedi azonosítóval (Content-Id) rendelkeznek. A boundary információ mellett - related esetben - egy start attribútumot is találunk, értéke egy Content-Id-ra való hivatkozás. Azaz a start jelöli ki - esetünkben - a SOAP envelope-ot. Az, hogy az envelope-on belül milyen hivatkozások vannak a csatolt állományokra, minket most nem érdekel, csak a különböző részeket szeretnénk feldolgozni. Amikor éppen nem az envelope-ot dolgozzuk fel, akkor figyelni kell a Content-Transfer-Encoding fejlécet, mert ez lehet bináris, de akár base64 kódolású is. A leírtak nagyrészt (A kód közel véglegesnek tekinthető, de még vár rá néhány teszteset) lefedik a SOAP Messages with Attachments fogalmát.

Nézzük egy (kölcsönzött) példát a kapott válaszüzenetre:
MIME-Version: 1.0
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml;
        start="<http://claiming-it.com/claim061400a.xml>"
Content-Description: This is the optional message description.

--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <http://claiming-it.com/claim061400a.xml>
Content-Location: http://claiming-it.com/claim061400a.xml


<?xml version='1.0' ?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
...
<theSignedForm href="http://claiming-it.com/claim061400a.tiff"/>
...
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

--MIME_boundary
Content-Type: image/tiff
Content-Transfer-Encoding: binary
Content-ID: <http://claiming-it.com/claim061400a.tiff>
Content-Location: http://claiming-it.com/claim061400a.tiff

...binary TIFF image...
--MIME_boundary--


Egy ehhez hasonló üzenetet kellene tehát feldolgoznunk, hogy utána az egyes részek kényelmesen lekérhetőek legyenek. A gond viszont az, hogy a natív PHP SoapClient osztály az ilyen típusú üzeneteket nem támogatja, így másfelé kell nézelődnünk.
A problémára két megoldást találtam. Kibővítem a meglévő SoapClient osztályt, vagy egy kész könyvtárat használok (sem NuSOAP-ban, sem ZendFwSoap-ban nem találtam a feature-t [Ha valaki tud wso2-höz hasonló könyvtárat, kommentben kérem ossza meg]). A kész könyvtár a WSO2 Web Service Framework for PHP lenne, amely nagyon sok funkciót tud, köztük az SwA helyett ajánlott MTOM-ot (ez a kettő lényegében megegyezik, csupán az MTOM előrehaladottabb a csatolások belinkelésével).
A kibővítés mellett döntöttem, egyrészt mert a jövőre tekintve is elegendőnek tűnik a majd lentebb látható megoldás, másrészt a kódegység tartása (natív PHP SOAP osztályokat használok az érintett projektben) végett az összes SOAP-al kapcsolatos kódrészt át kellett volna írni, a könytárnak megfelelőre.
Mostmár rátérhetünk a gyakorlati részre, a kódra. Itt nem szeretnék hosszas magyarázatokba bocsátkozni, a lényeg annyi, hogy a SoapClient osztály __doRequest metódusát fogjuk felülírni. Ez az a metódus amely elküldi a kérést, majd visszatér a válasszal. Nekünk akkor kell beavatkoznunk, ha több részes üzenetet fedezünk fel a válaszban, egyébként az eddigi működést támogatjuk. Lekéréskor az összes részt, vagy csupán egyet is elkérhetünk. Egy résznek van fejléc része, amely kulcs-érték párokat tartalmaz és van tartalma, ezenkívül meg tudja mondani magáról, hogy ő maga-e az envelope.


Oct 11, 2011

Zend action controller, függvénybeli paraméterekkel


Rövid szünet után egy Zend Framework-el kapcsolatos poszt következik. Sajnos Zendéknél alapból, nincs lehetőségünk az Action metódusokban paramétereket megdani. Ez nekünk főleg, azért rossz, mert mi szeretnénk az url-ben átadott paramétereket ($_GET) azonnal lekérni a függvény paraméterein keresztül, nem pedig például a $this->getRequest()->getQuery() segítségével. Ezen probléma orvoslására már bizonyára sok megoldás született, de mivel én a Zf-et eddig nagyrészt csak komponensenként használtam főleg CodeIgniter alól, így nekem újdonság volt a dolog.
Alap esetben az url-ben szereplő paraméterek lekérdezésére a következő lehetőségünk van:
$this->_request->getQuery('query_string_parameter_name'); // zf request object
A cél eléréséhez a Zend_Controller_Action osztály dispatch metódusát kell felülírnunk. Azért van erre a függvényre szükségünk, mert ő lesz aki meghívja a megfelelő controller adott action metódusát, amelyet paraméterben megkap (egyszerű string-ként).
A kód megtekintése előtt csupán annyit emelnék még ki, hogy két lehetőségünk van az url-ben paramétereket átadni az adott akciónak:
  • module/controller/action?p1name=p1value&p2name=p2value
  • module/controller/action/p1name/p1value/p2name/p2value
(2. esetben a module, controller és az action kulcsok foglaltak)


Ui.: A fenti megoldás csupán teszt jellegű, éles környezetben nincs használva. Ezen kívül még annyi, hogy validációnál hátrányban lehetünk ilyen jellegű felhasználás esetén (változókban vannak a bemeneti értékek, a könnyebben kezelhető tömb helyett).