Wiki source code of WebServices
Show last authors
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 | |
36 | |
37 | === invoking the client === |
38 | |
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 (HTTPS) and requires an update of your app.config to specify the HTTPS basic authentication: |
58 | |
59 | |
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="Transport">** |
74 | **~ <transport clientCredentialType="Basic" realm="" />** |
75 | **~ </security>** |
76 | </binding> |
77 | </basicHttpBinding> |
78 | </bindings> |
79 | <client> |
80 | <endpoint address="https://myserver/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 | For an http connexion: (Not recommanded for security reasons unless in controled intranet environments): |
91 | |
92 | <?xml version="1.0" encoding="utf-8" ?> |
93 | <configuration> |
94 | <system.serviceModel> |
95 | <bindings> |
96 | <basicHttpBinding> |
97 | <binding name="Book" closeTimeout="00:01:00" openTimeout="00:01:00" |
98 | receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" |
99 | bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" |
100 | maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" |
101 | messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" |
102 | useDefaultWebProxy="true"> |
103 | <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" |
104 | maxBytesPerRead="4096" maxNameTableCharCount="16384" /> |
105 | **<security mode="TransportCredentialOnly">** |
106 | **~ <transport clientCredentialType="Basic" realm="" />** |
107 | **~ </security>** |
108 | </binding> |
109 | </basicHttpBinding> |
110 | </bindings> |
111 | <client> |
112 | <endpoint address="http://myserver/dysoweb/ws/soap.ws" |
113 | binding="basicHttpBinding" bindingConfiguration="Book" contract="RequeaService.Book" |
114 | name="Book" /> |
115 | </client> |
116 | </system.serviceModel> |
117 | </configuration> |
118 | |
119 | |
120 | |
121 | |
122 | = Calling a Web Service in REQUEA = |
123 | |
124 | Invoking a Web Service from REQUEA requires that you adapt the semantics of the Web Service and wrap it as a JavaScript Plugin service. |
125 | |
126 | The wrapping code should be written in Java. |
127 | |
128 | There are (at least) two ways to wrap the code and invoke the Web Service: |
129 | |
130 | * using Apache Axis |
131 | * using SaaJ and XML |
132 | |
133 | == Using Apache Axis == |
134 | |
135 | Using Apache Axis you can generate Java wrappers around the Web Service and invoke those wrapper from the Java code. |
136 | |
137 | In this example, we will use the ViaMichelin SOAP API. |
138 | |
139 | 1 - Generate the stubs |
140 | |
141 | This is done with the Axis tool WSDL2Java: |
142 | |
143 | {{code language="java"}} |
144 | java org.apache.axis.wsdl.WSDL2Java http://www.viamichelin.com/ws/services/Geocoding?wsdl |
145 | {{/code}} |
146 | |
147 | |
148 | This will generate some java classes, that you should include in your plugin project: |
149 | |
150 | com\viamichelin\ws\geo\GeoCoordinates.java |
151 | com\viamichelin\ws\localization\Address.java |
152 | com\viamichelin\ws\localization\FindLocation.java |
153 | com\viamichelin\ws\localization\FindLocations.java |
154 | com\viamichelin\ws\localization\GeocodingRequest.java |
155 | com\viamichelin\ws\localization\InputAddress.java |
156 | com\viamichelin\ws\localization\Location.java |
157 | com\viamichelin\ws\localization\Poi.java |
158 | com\viamichelin\ws\localization\PoiDatasheet.java |
159 | com\viamichelin\ws\localization\PoiDescriptionList.java |
160 | com\viamichelin\ws\localization\PoiId.java |
161 | com\viamichelin\ws\localization\PoiMetaNumList.java |
162 | com\viamichelin\ws\localization\PoiMetaStringList.java |
163 | com\viamichelin\ws\localization\service\Geocoding.java |
164 | com\viamichelin\ws\localization\service\GeocodingService.java |
165 | com\viamichelin\ws\localization\service\GeocodingServiceLocator.java |
166 | com\viamichelin\ws\localization\service\GeocodingSoapBindingStub.java |
167 | com\viamichelin\ws\object\Integer.java |
168 | |
169 | === Calling the Web Service === |
170 | |
171 | The call is done within the plugin script in a jsFunction_execute for example: |
172 | |
173 | {{code language="java"}} |
174 | |
175 | |
176 | InputAddress[] addressList = new InputAddress[1]; |
177 | addressList[0] = inputAddress; |
178 | request.setAddressesList(addressList); |
179 | |
180 | // call the web service |
181 | GeocodingServiceLocator locator = new GeocodingServiceLocator(); |
182 | Geocoding service = locator.getGeocoding(); |
183 | |
184 | String login = registry.getParam("com.requea.viamichelin.login"); |
185 | String passwd = registry.getParam("com.requea.viamichelin.password"); |
186 | if(login == null || passwd == null) { |
187 | throw new RegistryException("Viamichelin service not properly configured. Missing login or password"); |
188 | } |
189 | String url = registry.getParam("com.requea.viamichelin.url"); |
190 | if(url != null) { |
191 | locator.setGeocodingEndpointAddress(url); |
192 | } |
193 | |
194 | try { |
195 | FoundLocationList result = service.getLocationsList(request, login+"|"+passwd)[0]; |
196 | if(result.getFoundLocations().length > 0) { |
197 | FoundLocation loc = result.getFoundLocations()[0]; |
198 | return new GeocodedLocation(loc.getLocationDesc()); |
199 | } else { |
200 | // nothing found |
201 | return null; |
202 | } |
203 | } catch(Exception e) { |
204 | throw new EndUserException(e); |
205 | } |
206 | |
207 | {{/code}} |
208 | |
209 | |
210 | === Setting up classpath and dependencies === |
211 | |
212 | in your pom.xml, you need to add the axis dependencies for inclusion in your bundle: |
213 | |
214 | {{code language="xml"}} |
215 | <dependency> |
216 | <groupId>axis</groupId> |
217 | <artifactId>axis</artifactId> |
218 | <version>1.4</version> |
219 | <scope>provided</scope> |
220 | </dependency> |
221 | {{/code}} |
222 | |
223 | and for the bundle class path: |
224 | |
225 | {{code language="xml"}} |
226 | <Bundle-ClassPath> |
227 | ., |
228 | lib/axis-1.4.jar, |
229 | lib/axis-jaxrpc-1.4.jar, |
230 | lib/axis-saaj-1.4.jar, |
231 | lib/axis-wsdl4j-1.5.1.jar, |
232 | lib/commons-discovery-0.2.jar |
233 | </Bundle-ClassPath> |
234 | {{/code}} |
235 | |
236 | [[Download the complete pom.xml>>attach:pom.xml||title="Download the pom.xml"]] |
237 | |
238 | == Using SAAJ == |
239 | |
240 | Using SAAJ, you can invoke the Web service without having to generate stubs. |
241 | |
242 | It is a lower level protocol, allowing for a finer control of the WebService invokation, at the expense of the simplicity. |
243 | |
244 | Here is a snipet of code that does a SAAJ invokation: |
245 | |
246 | {{code language="java"}} |
247 | Thread th = Thread.currentThread(); |
248 | ClassLoader cl = th.getContextClassLoader(); |
249 | // build a GetList request |
250 | try { |
251 | th.setContextClassLoader(this.getClass().getClassLoader()); |
252 | String userName = registry.getParam("username"); |
253 | String password = registry.getParam("password"); |
254 | String strURL = registry.getParam("endpoint"); |
255 | |
256 | SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance(); |
257 | SOAPConnection connection = factory.createConnection(); |
258 | URL endpoint = new URL(strURL); |
259 | |
260 | // this web services requires the SOAPAction. |
261 | MessageFactory mf = MessageFactory.newInstance(); |
262 | SOAPMessage message = mf.createMessage(); |
263 | MimeHeaders hd = message.getMimeHeaders(); |
264 | hd.addHeader("SOAPAction", "urn:WS/"+action); |
265 | |
266 | SOAPHeader header = message.getSOAPHeader(); |
267 | // adds auth info in the header |
268 | Element elAuth = header.getOwnerDocument().createElementNS( |
269 | "urn:WS", "AuthenticationInfo"); |
270 | elAuth.setAttribute("xlmns", "urn:WS"); |
271 | XMLUtils.addElement(elAuth, "userName", userName); |
272 | XMLUtils.addElement(elAuth, "password", password); |
273 | header.appendChild(elAuth); |
274 | |
275 | // include the request in the body |
276 | SOAPBody body = message.getSOAPBody(); |
277 | body.appendChild(body.getOwnerDocument().adoptNode( |
278 | elRequest.cloneNode(true))); |
279 | |
280 | SOAPMessage response = connection.call(message, endpoint); |
281 | // fault? |
282 | Element elBody = response.getSOAPBody(); |
283 | Element elFault = XMLUtils.getChild(elBody, "Fault"); |
284 | if(elFault != null) { |
285 | log.severe(XMLUtils.getChildText(elFault, "faultstring")); |
286 | throw new EndUserException(XMLUtils.getChildText(elFault, "faultstring")); |
287 | |
288 | } |
289 | |
290 | Element elResp = XMLUtils.getChild(elBody, "urn:WS", respName); |
291 | // close the connection |
292 | connection.close(); |
293 | |
294 | return elResp; |
295 | |
296 | } catch(Exception e) { |
297 | throw new RegistryException(e); |
298 | |
299 | } finally { |
300 | th.setContextClassLoader(cl); |
301 | } |
302 | {{/code}} |
303 | |
304 | |
305 | Required dependencies in your project: |
306 | |
307 | {{code language="xml"}} |
308 | <dependency> |
309 | <groupId>javax.xml</groupId> |
310 | <artifactId>saaj-api</artifactId> |
311 | <version>1.3</version> |
312 | </dependency> |
313 | <dependency> |
314 | <groupId>com.sun.xml.messaging.saaj</groupId> |
315 | <artifactId>saaj-impl</artifactId> |
316 | <version>1.3</version> |
317 | </dependency> |
318 | {{/code}} |
319 | |
320 | and the plugin section in the pom.xml |
321 | |
322 | {{code language="xml"}} |
323 | <plugin> |
324 | <groupId>com.requea.dysoapp</groupId> |
325 | <artifactId>maven-dysoapp-bundle</artifactId> |
326 | <extensions>true</extensions> |
327 | <configuration> |
328 | <instructions> |
329 | <Bundle-Name>${pom.name}</Bundle-Name> |
330 | <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName> |
331 | <Export-Package /> |
332 | <Import-Package> |
333 | org.apache.commons.logging, |
334 | org.osgi.framework, |
335 | com.requea.app, |
336 | com.requea.util, |
337 | com.requea.util.xml, |
338 | org.w3c.dom, |
339 | javax.net.*, |
340 | javax.crypto.*, |
341 | javax.xml.*, |
342 | javax.activation, |
343 | org.mozilla.javascript;version=1.7.2, |
344 | javax.imageio.*, |
345 | org.xml.*, |
346 | !org.jvnet.*, |
347 | !com.sun.* |
348 | </Import-Package> |
349 | <Bundle-Activator>com.requea.myplugin.Activator</Bundle-Activator> |
350 | <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency> |
351 | </instructions> |
352 | </configuration> |
353 | </plugin> |
354 | {{/code}} |