SAAJ: Nisu priložene žice

U vrijeme pisanja ovog članka, većina se web usluga sastoji od jednostavne razmjene poruka: klijent kontaktira web uslugu i šalje joj poruku. Web usluga zauzvrat obrađuje taj zahtjev, a zatim klijentu vraća odgovor. Taj jednostavan obrazac zahtjeva / odgovora modelira način na koji HTTP protokol olakšava interakciju klijent / web poslužitelj. Kao i kod HTTP-a, razmjena poruka putem web-usluga često mora uključivati ​​binarni sadržaj, poput slika, dokumenata ili zvučnih isječaka. Ovaj članak uvodi slanje i primanje binarnog sadržaja web usluga pomoću SOAP-a (Simple Object Access Protocol) s Attachments API for Java (SAAJ) 1.2.

Prije nego što zaronite u zamršenost prijenosa sadržaja binarnih web usluga, vrijedi istaknuti da se jednostavna web usluga u obliku zahtjeva / odgovora suprotstavlja uslugama koje modnu interakciju klijent / poslužitelj čine kao pozive udaljenih procedura ili RPC-ove. U RPC-u poslužitelj izlaže sučelje koje sliči API-ju. Zauzvrat, klijent poziva takvu uslugu upućivanjem udaljenih poziva na API usluge, prosljeđivanjem potrebnih parametara i primanjem vrijednosti koje poziv stvara.

RPC zasnovan na XML-u sliči načinu na koji pozivate objekte u objektno orijentiranom (OO) sustavu. Zapravo, kada radite s Java API-jem za RPC zasnovan na XML-u (JAX-RPC), rijetko postajete svjesni da radite s XML dokumentima, a ne s Java objektima. JAX-RPC omogućuje vam da o web uslugama razmišljate kao o udaljenim objektima, baš kao što biste to učinili i s Java RMI (daljinsko pozivanje metode). Izvršno vrijeme JAX-RPC prevodi pozive metode OO na visokoj razini u XML dokumente koje očekuje udaljena web usluga. Iako web usluge u RPC stilu često pružaju prikladniji model programiranja, RPC pozivi se također moraju oslanjati na sloj za razmjenu poruka niže razine za razmjenu XML poruka koje čine udaljeni poziv.

Za neke web usluge često je korisno izravno programiranje na taj sloj razmjene poruka niže razine. Na primjer, ako želite pozvati web uslugu koja troši dokument narudžbenice i vraća potvrdu, možete jednostavno modelirati tu razmjenu dokumenata kao jednu razmjenu zahtjeva / odgovora. Umjesto da pozivate metode na daljinu, vi biste konstruirali XML poruke, te poruke poslali izravno web usluzi i obradili XML odgovor usluge, ako postoji. Budući da SOAP definira uobičajeni format poruka za poruke web usluga, morat ćete konstruirati poruke koje odgovaraju SOAP-u i, nakon što usluga odgovori, raščlaniti te poruke SOAP odgovora natrag u format koji vaš program razumije.

SAAJ nudi prikladnu knjižnicu za konstrukciju i čitanje SOAP poruka, a također vam omogućuje slanje i primanje SOAP poruka putem mreže. SAAJ definira prostor imena javax.xml.soap. Klase koje se nalaze u tom paketu u početku su činile dio Java API-ja za XML poruke (JAXM), ali su nedavno odvojene u vlastiti API. JAXM se oslanja na SAAJ za izradu i manipulaciju SOAP porukama te dodaje pouzdanost poruke i druge značajke specifične za XML poruke. Iako je SAAJ potrebna komponenta J2EE (Java 2 Platform, Enterprise Edition) 1.4, JAXM nije. Ovaj se članak usredotočuje na jedan od najkorisnijih aspekata SAAJ-a: sposobnost spajanja binarnog sadržaja na SOAP poruku.

Blagodati vezanosti

Iako se SOAP-ov centar za dizajn usredotočuje na inkapsulaciju XML dokumenata u poruci, SOAP-ova značajka privitka proširuje SOAP poruku tako da uz redoviti SOAP dio uključuje i nula ili više privitaka, kao što prikazuje slika 1. Svaka je privitak definirana MIME tipom i može pretpostaviti bilo koji sadržaj predstavljen kao tok bajtova.

SOAP-ova značajka privitka pokazuje se najkorisnijom kada klijent želi binarne podatke, poput slike ili audio podataka, poslati na web uslugu. Bez SOAP privitaka slanje dijela binarnih podataka pokazalo bi se težim. Na primjer, SOAP poruka klijenta može prenijeti URL adresu binarne datoteke. Klijent bi tada morao upravljati HTTP poslužiteljem kako bi web usluga mogla pristupiti toj datoteci. To bi predstavljalo pretjerani teret za bilo kojeg klijenta web usluge, posebno za klijente koji rade na uređajima s ograničenim resursima, poput digitalnih fotoaparata ili skenera. Mogućnost pripajanja SOAP-a omogućuje bilo kojem klijentu web usluge koji može prenositi SOAP poruke ugrađivati ​​binarne datoteke izravno u SOAP poruku.

Primjeri SOAP-a, na primjer, pokazuju se korisnima u interakciji s web stranicama portala. Razmotrite mrežu agencija za promet nekretninama koja treba distribuirati opise i fotografije kuća za prodaju na centralizirani portal za pretraživanje nekretnina. Ako portal poslužuje servlet koji omogućuje objavljivanje SOAP poruka s prilozima, agencija za promet nekretnina mogla bi ažurirati svoje popise s nekoliko SOAP poruka, uključujući fotografije tih domova. Tijelo SOAP poruke može ugrađivati ​​opis svojstva, a SOAP privici mogu sadržavati slikovne datoteke. Prema tom scenariju, kada servlet operatora portala primi takvu poruku, vratio bi dokument o potvrdi koji ukazuje na dostupnost posta na portalu. Slika 2 ilustrira takvu web uslugu.

Anatomija SOAP-a s porukom o prilozima

SOAP poruke s prilozima W3C (World Wide Web Consortium) Napomena (vidi Resursi) SOAP-u ne dodaje nove značajke. Umjesto toga, definira kako iskoristiti MIME vrste u SOAP poruci za definiranje privitaka i kako uputiti te privitke unutar SOAP tijela.

Tip MIME multipart/relateddefinira dokumente koji se sastoje od više povezanih dijelova. SOAP poruke s prilozima moraju slijediti multipart/relatedMIME vrstu. Primjer u nastavku prikazuje multipart/relatedSOAP poruku, vezanu za HTTP protokol, s dva privitka:

POST / propertyListing HTTP / 1.1 Host: www.realproperties.com Tip sadržaja: Više dijelova / Srodno; granica = MIME_boundary; upišite = tekst / xml; Duljina sadržaja: NNNN --MIME_boundary Vrsta sadržaja: text / xml; charset = UTF-8 Kodiranje prijenosa sadržaja: 8-bitni Content-ID: Stvarno lijepi domovi, Inc. Dodaj 1234 Main St Pleasantville CA 94323 250000 --MIME_boundary Content-Type: image / jpeg Content-ID: .... JPEG DATA ..... --MIME_boundary Content-Type: image / jpeg Content-ID: .... JPEG DATA ..... --MIME_boundary--

Gornja višedijelna poruka sadrži niz MIME zaglavlja i srodnih podataka. U korijenu dokumenta nalazi se tijelo SOAP-a. Budući da SOAP tijelo sadrži samo XML podatke, MIME tip cijele poruke je text/xml. Nakon omotnice SOAP nalaze se dva privitka, svaki koji odgovara slikovnoj datoteci poslanoj zajedno s porukom.

ID sadržaja identificira svaki privitak. W3C Note dopušta ili ID sadržaja ili mjesto sadržaja da upućuju na privitke, ali daje prednost prethodnima. Takvi ID-ovi sadržaja djeluju kao referenca na jedinstveni identifikator resursa (URI) na privitke; pravila kodiranja SOAP 1.1 definiraju kako se referencira resurs u SOAP poruci putem URI-ja koji se može pozivati ​​na bilo koji sadržaj, a ne samo na XML (pogledajte Odjeljak 5 SOAP-a 1.1 u Resursima). SOAP procesor rješava te URI reference dok obrađuje poruku. Na temelju gornjeg primjera, SOAP procesor povezuje element frontImages odjeljkom podataka s Content ID-om [email protected]u SOAP poruci.

Stvorite i pošaljite SOAP poruku s prilozima

SAAJ vam omogućuje stvaranje i uređivanje bilo kojeg dijela SOAP poruke, uključujući privitke. Većina SAAJ-a temelji se na apstraktnim klasama i sučeljima tako da svaki pružatelj usluga može implementirati SAAJ u vlastite proizvode. Referentna implementacija Sun Microsystems dolazi s Java Developer Pack (JWSDP).

Budući da SOAP poruke predstavljaju samo poseban oblik XML dokumenata, JAAS se nadograđuje na API modela dokumenta (DOM) za obradu XML-a. Većina komponenata SOAP poruka spušta se sa javax.xml.soap.Nodesučelja, koje je pak org.w3c.dom.Nodepodrazred. SAAJ podklase Nodeza dodavanje konstrukcija specifičnih za SOAP. Na primjer, poseban Node, SOAPElementpredstavlja element SOAP poruke.

Izravni rezultat oslanjanja SAAJ-a na sučelja i apstraktne klase je da većinu zadataka povezanih sa SOAP-om ostvarujete tvorničkim metodama. Da biste povezali svoju aplikaciju sa SAAJ API-jem, prvo stvorite SOAPConnectiona SOAPConnectionFactory. Za stvaranje i uređivanje SOAP poruka također možete inicijalizirati a MessageFactoryi a SOAPFactory. MessageFactoryomogućuje vam stvaranje SOAP poruka i SOAPFactorypruža metode za stvaranje pojedinačnih dijelova SOAP poruke:

SOAPConnectionFactory spConFactory = SOAPConnectionFactory.newInstance (); SOAPConnection con = spConFactory.createConnection (); SOAPFactory soapFactory = SOAPFactory.newInstance ();

Pomoću ovih alata možete stvoriti SOAP poruku koju bi klijent agencije za promet nekretninama koristio za slanje ažuriranja popisa na web stranicu portala.

SAAJ nudi nekoliko načina za stvaranje nove SOAP poruke. Sljedeći primjer prikazuje najjednostavniju metodu koja stvara praznu SOAP poruku s omotnicom i zaglavljem i tijelom u toj omotnici. Budući da vam u ovoj poruci nije potrebno zaglavlje SOAP-a, možete ukloniti taj element iz poruke:

SOAPMessage poruka = ​​factory.createMessage (); SOAPHeader zaglavlje = message.getSOAPHeader (); header.detachNode ();

Dodavanje XML strukture tijelu poruke pokazuje se izravnim:

SOAPBody tijelo = message.getSOAPBody (); Ime listingElementName = soapFactory.createName ("propertyListing", "realProperty", "//schemas.realhouses.com/listingSubmission"); SOAPBodyElement listingElement = body.addBodyElement (listingElementName); Ime attname = soapFactory.createName ("id"); listingElement.addAttribute (naziv, "svojstvo_1234"); SOAPElement listingAgency = listingElement.addChildElement ("listingAgency"); listingAgency.addTextNode ("Stvarno lijepi domovi, Inc"); SOAPElement listingType = listingElement.addChildElement ("listingType"); listingType.addTextNode ("dodaj"); SOAPElement propertyAddress = listingElement.addChildElement ("propertyAddress"); SOAPElement ulica = propertyAddress.addChildElement ("ulica"); street.addTextNode ("1234 Main St "); SOAPElement city = propertyAddress.addChildElement (" city "); city.addTextNode (" Pleasantville "); SOAPElement state = propertyAddress.addChildElement (" state "); state.addTextNode (" CA "); SOAPElement zip = propertyAddress.addChildElement ("zip"); zip.addTextNode ("94521"); SOAPElement listPrice = listingElement.addChildElement ("listPrice"); listPrice.addTextNode ("25000");addChildElement ("listPrice"); listPrice.addTextNode ("25000");addChildElement ("listPrice"); listPrice.addTextNode ("25000");

Napomena dodajete jedinstveni ID svojstva kao atribut propertyListingelementu. Dalje, propertyListingelement kvalificirate s QNameimenom ili imenskim znanjem.

Privitke SOAP poruci možete dodati na nekoliko načina. U ovom primjeru prvo stvarate elemente koji označavaju prednje i unutarnje slike navedenog svojstva. Svaka ima hrefatribut koji označava ID sadržaja privitka:

String frontImageID = "[email protected]"; SOAPElement frontImRef = listingElement.addChildElement ("frontImage"); Ime hrefAttName = soapFactory.createName ("href"); frontImRef.addAttribute (hrefAttName, frontImageID); String interiorID = "[email protected]"; SOAPElement interiorImRef = listingElement.addChildElement ("interiorImage"); interiorImRef.addAttribute (hrefAttName, interiorID);

Da biste poruci lako priložili potrebne slikovne datoteke, upotrijebite javax.activation.DataHandlerobjekt iz JavaBeans Activation Framework. DataHandlermože automatski otkriti vrstu podataka koja mu je proslijeđena i stoga može automatski dodijeliti prikladnu vrstu sadržaja MIME privitku:

URL url = novi URL ("datoteka: ///export/files/pic1.jpg"); DataHandler dataHandler = novi DataHandler (url); AttachmentPart att = message.createAttachmentPart (dataHandler); att.setContentId (frontImageID); message.addAttachmentPart (att);

Alternativno, možda ćete moći proslijediti Object, zajedno s ispravnim MIME tipom, na createAttachmentPart(). Ta metoda nalikuje prvoj. Interno će implementacija SAAJ vjerojatno tražiti a DataContentHandlerza obradu navedenog tipa MIME. Ako ne može pronaći prikladnog rukovatelja, bacit createAttachmentPart()će IllegalArgumentException:

URL url2 = novi URL ("datoteka: ///export/files/pic2.jpg"); Slika im = Toolkit.getDefaultToolkit (). CreateImage (url2); AttachmentPart att2 = message.createAttachmentPart (im, "image / jpeg"); att2.setContentId (unutarnji ID); message.addAttachmentPart (att2);