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 | |||
3.2 | 57 | Note that the authentication is BASIC (HTTPS) and requires an update of your app.config to specify the HTTPS basic authentication: | |
1.3 | 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" /> | ||
3.1 | 73 | **<security mode="Transport">** | |
1.2 | 74 | **~ <transport clientCredentialType="Basic" realm="" />** | |
75 | **~ </security>** | ||
76 | </binding> | ||
77 | </basicHttpBinding> | ||
78 | </bindings> | ||
79 | <client> | ||
3.2 | 80 | <endpoint address="https://myserver/dysoweb/ws/soap.ws" | |
1.2 | 81 | binding="basicHttpBinding" bindingConfiguration="Book" contract="RequeaService.Book" | |
82 | name="Book" /> | ||
83 | </client> | ||
84 | </system.serviceModel> | ||
85 | </configuration> | ||
86 | |||
87 | |||
88 | |||
89 | |||
3.2 | 90 | For an http connexion: (Not recommanded for security reasons unless in controled intranet environments): | |
1.2 | 91 | ||
3.2 | 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> | ||
1.2 | 118 | ||
119 | |||
120 | |||
3.2 | 121 | ||
1.1 | 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}} |