Wiki source code of WebServices
Hide last authors
1.1 | 1 | = Introduction = | |
2 | |||
3 | The REQUEA Platform is a service oriented platform. Every entity definition can be mapped as a WebService using the SOAP protocol. | ||
4 | |||
5 | Entity Properties become attributes in the Document schema definition. | ||
6 | Operations become SOAP operations. | ||
7 | |||
8 | = Calling REQUEA as a Web Service = | ||
9 | |||
10 | The SOAP Servlet generates automatically WSDL and accept SOAP request over HTTP(s) based on the Entity definition. | ||
11 | |||
12 | The syntax for the WebService servlet is the following: | ||
13 | |||
14 | http://[server]/dysoweb/ws/wsdl.ws?doc=[entity name] | ||
15 | |||
16 | So for example: | ||
17 | |||
18 | http://localhost:8080/dysoweb/ws/wsdl.ws?doc=custTest | ||
19 | |||
20 | |||
21 | == Using Visual Studio 2010 == | ||
22 | |||
23 | You can map automatically the REQUEA Web service as a service reference in Visual Studio: | ||
24 | |||
25 | [[image:img45.png]] | ||
26 | |||
27 | |||
28 | [[image:img46.png||alt="Entering the Web service WSDL URL"]] | ||
29 | |||
30 | |||
31 | [[image:img47.png||alt="Discovering Service Operations"]] | ||
32 | |||
33 | [[image:img48.png]] | ||
34 | |||
35 | |||
1.2 | 36 | ||
37 | === invoking the client === | ||
38 | |||
1.3 | 39 | Here is a sample of client code: | |
40 | |||
41 | {{code language="java"}} | ||
42 | |||
43 | BookClient client = new BookClient(); | ||
44 | client.ClientCredentials.UserName.UserName = "RequeaDev"; | ||
45 | client.ClientCredentials.UserName.Password = "RequeaDev"; | ||
46 | |||
47 | |||
48 | custBook bk = new custBook(); | ||
49 | bk.custTitle = tbCouleur.Text; | ||
50 | bk.custAuthor = tbNom.Text; | ||
51 | |||
52 | bk = client.Save(bk); | ||
53 | lblSysId.Text = bk.sysId; | ||
54 | {{/code}} | ||
55 | |||
56 | |||
57 | Note that the authentication is BASIC (HTTP) and requires an update of your app.config to specify the HTTP basic authentication: | ||
58 | |||
59 | |||
1.2 | 60 | <?xml version="1.0" encoding="utf-8" ?> | |
61 | <configuration> | ||
62 | <system.serviceModel> | ||
63 | <bindings> | ||
64 | <basicHttpBinding> | ||
65 | <binding name="Book" closeTimeout="00:01:00" openTimeout="00:01:00" | ||
66 | receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" | ||
67 | bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" | ||
68 | maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" | ||
69 | messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" | ||
70 | useDefaultWebProxy="true"> | ||
71 | <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" | ||
72 | maxBytesPerRead="4096" maxNameTableCharCount="16384" /> | ||
73 | **<security mode="TransportCredentialOnly">** | ||
74 | **~ <transport clientCredentialType="Basic" realm="" />** | ||
75 | **~ </security>** | ||
76 | </binding> | ||
77 | </basicHttpBinding> | ||
78 | </bindings> | ||
79 | <client> | ||
80 | <endpoint address="http://192.168.122.1:8080/dysoweb/ws/soap.ws" | ||
81 | binding="basicHttpBinding" bindingConfiguration="Book" contract="RequeaService.Book" | ||
82 | name="Book" /> | ||
83 | </client> | ||
84 | </system.serviceModel> | ||
85 | </configuration> | ||
86 | |||
87 | |||
88 | |||
89 | |||
90 | |||
91 | |||
92 | |||
93 | |||
1.1 | 94 | = Calling a Web Service in REQUEA = | |
95 | |||
96 | Invoking a Web Service from REQUEA requires that you adapt the semantics of the Web Service and wrap it as a JavaScript Plugin service. | ||
97 | |||
98 | The wrapping code should be written in Java. | ||
99 | |||
100 | There are (at least) two ways to wrap the code and invoke the Web Service: | ||
101 | |||
102 | * using Apache Axis | ||
103 | * using SaaJ and XML | ||
104 | |||
105 | == Using Apache Axis == | ||
106 | |||
107 | Using Apache Axis you can generate Java wrappers around the Web Service and invoke those wrapper from the Java code. | ||
108 | |||
109 | In this example, we will use the ViaMichelin SOAP API. | ||
110 | |||
111 | 1 - Generate the stubs | ||
112 | |||
113 | This is done with the Axis tool WSDL2Java: | ||
114 | |||
115 | {{code language="java"}} | ||
116 | java org.apache.axis.wsdl.WSDL2Java http://www.viamichelin.com/ws/services/Geocoding?wsdl | ||
117 | {{/code}} | ||
118 | |||
119 | |||
120 | This will generate some java classes, that you should include in your plugin project: | ||
121 | |||
122 | com\viamichelin\ws\geo\GeoCoordinates.java | ||
123 | com\viamichelin\ws\localization\Address.java | ||
124 | com\viamichelin\ws\localization\FindLocation.java | ||
125 | com\viamichelin\ws\localization\FindLocations.java | ||
126 | com\viamichelin\ws\localization\GeocodingRequest.java | ||
127 | com\viamichelin\ws\localization\InputAddress.java | ||
128 | com\viamichelin\ws\localization\Location.java | ||
129 | com\viamichelin\ws\localization\Poi.java | ||
130 | com\viamichelin\ws\localization\PoiDatasheet.java | ||
131 | com\viamichelin\ws\localization\PoiDescriptionList.java | ||
132 | com\viamichelin\ws\localization\PoiId.java | ||
133 | com\viamichelin\ws\localization\PoiMetaNumList.java | ||
134 | com\viamichelin\ws\localization\PoiMetaStringList.java | ||
135 | com\viamichelin\ws\localization\service\Geocoding.java | ||
136 | com\viamichelin\ws\localization\service\GeocodingService.java | ||
137 | com\viamichelin\ws\localization\service\GeocodingServiceLocator.java | ||
138 | com\viamichelin\ws\localization\service\GeocodingSoapBindingStub.java | ||
139 | com\viamichelin\ws\object\Integer.java | ||
140 | |||
141 | === Calling the Web Service === | ||
142 | |||
143 | The call is done within the plugin script in a jsFunction_execute for example: | ||
144 | |||
145 | {{code language="java"}} | ||
146 | |||
147 | |||
148 | InputAddress[] addressList = new InputAddress[1]; | ||
149 | addressList[0] = inputAddress; | ||
150 | request.setAddressesList(addressList); | ||
151 | |||
152 | // call the web service | ||
153 | GeocodingServiceLocator locator = new GeocodingServiceLocator(); | ||
154 | Geocoding service = locator.getGeocoding(); | ||
155 | |||
156 | String login = registry.getParam("com.requea.viamichelin.login"); | ||
157 | String passwd = registry.getParam("com.requea.viamichelin.password"); | ||
158 | if(login == null || passwd == null) { | ||
159 | throw new RegistryException("Viamichelin service not properly configured. Missing login or password"); | ||
160 | } | ||
161 | String url = registry.getParam("com.requea.viamichelin.url"); | ||
162 | if(url != null) { | ||
163 | locator.setGeocodingEndpointAddress(url); | ||
164 | } | ||
165 | |||
166 | try { | ||
167 | FoundLocationList result = service.getLocationsList(request, login+"|"+passwd)[0]; | ||
168 | if(result.getFoundLocations().length > 0) { | ||
169 | FoundLocation loc = result.getFoundLocations()[0]; | ||
170 | return new GeocodedLocation(loc.getLocationDesc()); | ||
171 | } else { | ||
172 | // nothing found | ||
173 | return null; | ||
174 | } | ||
175 | } catch(Exception e) { | ||
176 | throw new EndUserException(e); | ||
177 | } | ||
178 | |||
179 | {{/code}} | ||
180 | |||
181 | |||
182 | === Setting up classpath and dependencies === | ||
183 | |||
184 | in your pom.xml, you need to add the axis dependencies for inclusion in your bundle: | ||
185 | |||
186 | {{code language="xml"}} | ||
187 | <dependency> | ||
188 | <groupId>axis</groupId> | ||
189 | <artifactId>axis</artifactId> | ||
190 | <version>1.4</version> | ||
191 | <scope>provided</scope> | ||
192 | </dependency> | ||
193 | {{/code}} | ||
194 | |||
195 | and for the bundle class path: | ||
196 | |||
197 | {{code language="xml"}} | ||
198 | <Bundle-ClassPath> | ||
199 | ., | ||
200 | lib/axis-1.4.jar, | ||
201 | lib/axis-jaxrpc-1.4.jar, | ||
202 | lib/axis-saaj-1.4.jar, | ||
203 | lib/axis-wsdl4j-1.5.1.jar, | ||
204 | lib/commons-discovery-0.2.jar | ||
205 | </Bundle-ClassPath> | ||
206 | {{/code}} | ||
207 | |||
208 | [[Download the complete pom.xml>>attach:pom.xml||title="Download the pom.xml"]] | ||
209 | |||
210 | == Using SAAJ == | ||
211 | |||
212 | Using SAAJ, you can invoke the Web service without having to generate stubs. | ||
213 | |||
214 | It is a lower level protocol, allowing for a finer control of the WebService invokation, at the expense of the simplicity. | ||
215 | |||
216 | Here is a snipet of code that does a SAAJ invokation: | ||
217 | |||
218 | {{code language="java"}} | ||
219 | Thread th = Thread.currentThread(); | ||
220 | ClassLoader cl = th.getContextClassLoader(); | ||
221 | // build a GetList request | ||
222 | try { | ||
223 | th.setContextClassLoader(this.getClass().getClassLoader()); | ||
224 | String userName = registry.getParam("username"); | ||
225 | String password = registry.getParam("password"); | ||
226 | String strURL = registry.getParam("endpoint"); | ||
227 | |||
228 | SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance(); | ||
229 | SOAPConnection connection = factory.createConnection(); | ||
230 | URL endpoint = new URL(strURL); | ||
231 | |||
232 | // this web services requires the SOAPAction. | ||
233 | MessageFactory mf = MessageFactory.newInstance(); | ||
234 | SOAPMessage message = mf.createMessage(); | ||
235 | MimeHeaders hd = message.getMimeHeaders(); | ||
236 | hd.addHeader("SOAPAction", "urn:WS/"+action); | ||
237 | |||
238 | SOAPHeader header = message.getSOAPHeader(); | ||
239 | // adds auth info in the header | ||
240 | Element elAuth = header.getOwnerDocument().createElementNS( | ||
241 | "urn:WS", "AuthenticationInfo"); | ||
242 | elAuth.setAttribute("xlmns", "urn:WS"); | ||
243 | XMLUtils.addElement(elAuth, "userName", userName); | ||
244 | XMLUtils.addElement(elAuth, "password", password); | ||
245 | header.appendChild(elAuth); | ||
246 | |||
247 | // include the request in the body | ||
248 | SOAPBody body = message.getSOAPBody(); | ||
249 | body.appendChild(body.getOwnerDocument().adoptNode( | ||
250 | elRequest.cloneNode(true))); | ||
251 | |||
252 | SOAPMessage response = connection.call(message, endpoint); | ||
253 | // fault? | ||
254 | Element elBody = response.getSOAPBody(); | ||
255 | Element elFault = XMLUtils.getChild(elBody, "Fault"); | ||
256 | if(elFault != null) { | ||
257 | log.severe(XMLUtils.getChildText(elFault, "faultstring")); | ||
258 | throw new EndUserException(XMLUtils.getChildText(elFault, "faultstring")); | ||
259 | |||
260 | } | ||
261 | |||
262 | Element elResp = XMLUtils.getChild(elBody, "urn:WS", respName); | ||
263 | // close the connection | ||
264 | connection.close(); | ||
265 | |||
266 | return elResp; | ||
267 | |||
268 | } catch(Exception e) { | ||
269 | throw new RegistryException(e); | ||
270 | |||
271 | } finally { | ||
272 | th.setContextClassLoader(cl); | ||
273 | } | ||
274 | {{/code}} | ||
275 | |||
276 | |||
277 | Required dependencies in your project: | ||
278 | |||
279 | {{code language="xml"}} | ||
280 | <dependency> | ||
281 | <groupId>javax.xml</groupId> | ||
282 | <artifactId>saaj-api</artifactId> | ||
283 | <version>1.3</version> | ||
284 | </dependency> | ||
285 | <dependency> | ||
286 | <groupId>com.sun.xml.messaging.saaj</groupId> | ||
287 | <artifactId>saaj-impl</artifactId> | ||
288 | <version>1.3</version> | ||
289 | </dependency> | ||
290 | {{/code}} | ||
291 | |||
292 | and the plugin section in the pom.xml | ||
293 | |||
294 | {{code language="xml"}} | ||
295 | <plugin> | ||
296 | <groupId>com.requea.dysoapp</groupId> | ||
297 | <artifactId>maven-dysoapp-bundle</artifactId> | ||
298 | <extensions>true</extensions> | ||
299 | <configuration> | ||
300 | <instructions> | ||
301 | <Bundle-Name>${pom.name}</Bundle-Name> | ||
302 | <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName> | ||
303 | <Export-Package /> | ||
304 | <Import-Package> | ||
305 | org.apache.commons.logging, | ||
306 | org.osgi.framework, | ||
307 | com.requea.app, | ||
308 | com.requea.util, | ||
309 | com.requea.util.xml, | ||
310 | org.w3c.dom, | ||
311 | javax.net.*, | ||
312 | javax.crypto.*, | ||
313 | javax.xml.*, | ||
314 | javax.activation, | ||
315 | org.mozilla.javascript;version=1.7.2, | ||
316 | javax.imageio.*, | ||
317 | org.xml.*, | ||
318 | !org.jvnet.*, | ||
319 | !com.sun.* | ||
320 | </Import-Package> | ||
321 | <Bundle-Activator>com.requea.myplugin.Activator</Bundle-Activator> | ||
322 | <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency> | ||
323 | </instructions> | ||
324 | </configuration> | ||
325 | </plugin> | ||
326 | {{/code}} |