Wiki source code of Web Services-Problems

Last modified by Francis Labrie on 2007/10/15 16:21

Hide last authors
Francis Labrie 9.1 1 |=(((
2 Contents
3 )))
4 |(((
5 {{section}}
6 1. [[#Problems>>doc:||anchor="Problems"]]
7 11. [[#DirectToWebService can't return a WSDL with secure HTTPS references in it>>doc:||anchor="DirectToWebService can't return a WSDL with secure HTTPS references in it"]]
8 11. [[#SOAP serializers and deserializers registered with ~~{~~{WOWebServiceRegistrar}} class doesn't appear in the WSDL schema>>doc:||anchor="SOAP serializers and deserializers registered with {{WOWebServiceRegistrar}} class doesn't appear in the WSDL schema"]]
9 11. [[#DirectToWebService can't return a WSDL with custom namespace and definitions name in it>>doc:||anchor="DirectToWebService can't return a WSDL with custom namespace and definitions name in it"]]
10 11. [[#WOWebServiceClient class can't connect to a server that requires an authentication>>doc:||anchor="WOWebServiceClient class can't connect to a server that requires an authentication"]]
11 11. [[#Web Services can't return a WSDL with secure HTTPS references specifying port other than the default 443>>doc:||anchor="Web Services can't return a WSDL with secure HTTPS references specifying port other than the default 443"]]
12 {{/section}}
13 )))
Francis Labrie 7.1 14
Francis Labrie 6.1 15 = Problems =
Pascal Robert 2.1 16
17 This section describes some problems and bugs that sometimes occur when using //WebObjects Web Services//.
18
Francis Labrie 6.1 19 == DirectToWebService can't return a WSDL with secure HTTPS references in it ==
Pascal Robert 2.1 20
Francis Labrie 6.1 21 **Authors:** Francis Labrie
Francis Labrie 9.1 22 **Affected products:** //WebObjects// 5.2.x, 5.3.x
23 **Bug reference:** [[rdar:~~/~~/3546304>>url:rdar://3546304||shape="rect"]]
Pascal Robert 2.1 24
Francis Labrie 6.1 25 === Problem: ===
Pascal Robert 2.1 26
Francis Labrie 9.1 27 A //DirectToWebService// defined Web Services doesn't return correct WSDL document, even if the correct procedure (see [[doc:WO.Secure Web Services]]) is followed. So only classes oriented Web Services manually registered with the {{code language="none"}}com.webobjects.appserver.WOWebServiceRegistrar{{/code}} class seems to generate a correct WSDL.
Pascal Robert 2.1 28
Francis Labrie 6.1 29 === Solution: ===
Pascal Robert 2.1 30
Francis Labrie 9.1 31 Darel Lee from Apple told me that right now, the dynamic WSDL generation is not exposed to developers so there currently isn't a clean solution to perform this. One workaround is to hardcode rules (of {{code language="none"}}com.webobjects.directtoweb.Assignment{{/code}} type) with the {{code language="none"}}serviceLocationURL{{/code}} key for each operation that you want to use secure HTTPS references. For instance:
Pascal Robert 2.1 32
33 {{code}}
34
Francis Labrie 6.1 35 ((operationName="anOperation") and (serviceName="Service")) ->
36 serviceLocationURL="https://host.net/cgi-bin/Service.woa/ws/Service"
Pascal Robert 2.1 37
38 {{/code}}
39
Francis Labrie 6.1 40 If you need all operation to be called using the secure protocol, you can also define a more generic rule like this one:
Pascal Robert 2.1 41
42 {{code}}
43
Francis Labrie 6.1 44 (serviceName="Service") ->
45 serviceLocationURL="https://host.net/cgi-bin/Service.woa/ws/Service"
Pascal Robert 2.1 46
47 {{/code}}
48
Francis Labrie 9.1 49 == SOAP serializers and deserializers registered with {{code language="none"}}WOWebServiceRegistrar{{/code}} class doesn't appear in the WSDL schema ==
Pascal Robert 2.1 50
Francis Labrie 6.1 51 **Authors:** Francis Labrie
Francis Labrie 9.1 52 **Affected products:** //WebObjects// 5.2.x, 5.3.x
53 **Bug reference:** [[rdar:~~/~~/3546330>>url:rdar://3546330||shape="rect"]]
Pascal Robert 2.1 54
Francis Labrie 7.1 55 === Problem: ===
Pascal Robert 2.1 56
Francis Labrie 9.1 57 Custom SOAP serializers and deserializers registered to Web Services with {{code language="none"}}com.webobjects.appserver.WOWebServiceRegistrar{{/code}} class are never added to the types / schema definition of the WSDL. The only type definitions shown are the following:
Pascal Robert 2.1 58
Francis Labrie 6.1 59 {{code}}
Pascal Robert 2.1 60
Francis Labrie 6.1 61 <types>
Pascal Robert 2.1 62 <schema targetNamespace="http://lang.java/" xmlns:soapenc=
63 "http://schemas.xmlsoap.org/soap/encoding/" xmlns=
64 "http://www.w3.org/2001/XMLSchema">
65 <complexType name="Class">
66 <sequence/>
67 </complexType>
68 <complexType name="ArrayOf_xsd_any">
69 <complexContent>
70 <restriction base="soapenc:Array">
71 <attribute ref="soapenc:arrayType" wsdl:arrayType=
72 "xsd:any[]"/>
73 </restriction>
74 </complexContent>
75 </complexType>
76 <element name="ArrayOf_xsd_any" nillable="true" type=
Francis Labrie 6.1 77 "lang:ArrayOf_xsd_any"/>
Pascal Robert 2.1 78 </schema>
79 <schema targetNamespace="http://www.apple.com/webobjects/
80 webservices/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/
81 soap/encoding/" xmlns="http://www.w3.org/2001/XMLSchema">
82 <complexType name="EOGlobalID">
83 <element name="entityName" type="xsd:string"/>
84 <element name="primaryKeys" type="lang:ArrayOf_xsd_any"/>
85 </complexType>
Francis Labrie 6.1 86 <element name="EOGlobalID" type="tns:EOGlobalID"/>
Pascal Robert 2.1 87 <complexType name="EOEnterpriseObject">
88 <element name="entityName" type="xsd:string"/>
89 <element name="globalID" type="webobjects:EOGlobalID"/>
90 <element name="properties" type="soapenc:Struct"/>
91 </complexType>
92 </schema>
93 </types>
94
Francis Labrie 6.1 95 {{/code}}
Pascal Robert 2.1 96
Francis Labrie 7.1 97 === Solution: ===
Francis Labrie 6.1 98
Francis Labrie 9.1 99 You must know that all complexe data types referred in operations will be added to the WSDL types definition. But if a complexe type makes references to others complexe types, you should make sure you add proper calls in the {{code language="none"}}writeSchema(Types){{/code}} method of the class serializer. For example:
Francis Labrie 6.1 100
smmccraw 4.1 101 {{code}}
Pascal Robert 2.1 102
Francis Labrie 6.1 103 public boolean writeSchema(Types types)
104 throws Exception {
105 ...
106 // Add type for Foo
Francis Labrie 8.1 107 String prefixedName = types.writeType(Foo.class, _FooQName);
Francis Labrie 6.1 108 ...
smmccraw 4.1 109
Francis Labrie 6.1 110 return true;
111 }
Pascal Robert 2.1 112
Francis Labrie 6.1 113 {{/code}}
Pascal Robert 2.1 114
Francis Labrie 6.1 115 Unfortunately, I don't know a dynamic workaround for all possible cases right now. At least a static and complete WSDL can be shared through a direct action, but it's not very handy though...
Pascal Robert 2.1 116
Francis Labrie 7.1 117 == DirectToWebService can't return a WSDL with custom namespace and definitions name in it ==
Pascal Robert 2.1 118
Francis Labrie 6.1 119 **Authors:** Francis Labrie
Francis Labrie 9.1 120 **Affected products:** //WebObjects// 5.2.x, 5.3.x
121 **Bug reference:**
Pascal Robert 2.1 122
Francis Labrie 7.1 123 === Problem: ===
Pascal Robert 2.1 124
Francis Labrie 6.1 125 A //DirectToWebService// defined Web Services can't return a WSDL with custom values for properties like namespaces and definitions name. Worse, the generated namespace can even contains WebObjects application instance number or the wrong hostname.
Pascal Robert 2.1 126
Francis Labrie 7.1 127 === Solution: ===
Pascal Robert 2.1 128
Francis Labrie 9.1 129 Base on a tips from Darel Lee, I've found in the {{code language="none"}}com.webobjects.webservices.generation._private.WOWSDLTemplate{{/code}} class some extras key definitions read from the {{code language="none"}}user.d2wmodel{{/code}} //DirectToWebService// rule file. For instance:
smmccraw 4.1 130
Francis Labrie 6.1 131 * **serviceLocationURL:** a key that allow the setting of the location URL for an operation. This is usefull if you need your WebServices to be reached using a secure HTTPS reference;
132 * **WSDLDefinitionName:** a key that allow the definitions name change. So instead of having "ServiceNameDefinition", you can set this value;
133 * **WSDLTargetNamespace:** a key that allow the namespace change. This is the most usefull: you can avoid dynamic generation depending on WebObjects HTTP Adaptor with this.
134
Pascal Robert 2.1 135 Here is an example of rule definition changing the above values:
136
137 {{code}}
138
Francis Labrie 6.1 139 (se(serviceName="Service") ->
140 WSDLTargetNamespace="https://host.net/cgi-bin/Service.woa/ws/Service"
141 (serviceName="Service") ->
142 WSDLDefinitionName="AnotherDefinition"
143 ((operationName="anOperation") and (serviceName="Service")) ->
144 serviceLocationURL="https://host.net/cgi-bin/Service.woa/ws/Service"
Pascal Robert 2.1 145
Francis Labrie 6.1 146 {{/code}}
Pascal Robert 2.1 147
Francis Labrie 7.1 148 == WOWebServiceClient class can't connect to a server that requires an authentication ==
Pascal Robert 2.1 149
Francis Labrie 6.1 150 **Authors:** Francis Labrie
Francis Labrie 9.1 151 **Affected products:** //WebObjects// 5.2.x, 5.3.x
152 **Bug reference:** [[rdar:~~/~~/3568441>>url:rdar://3568441||shape="rect"]]
Pascal Robert 2.1 153
Francis Labrie 7.1 154 === Problem: ===
Pascal Robert 2.1 155
Francis Labrie 9.1 156 The {{code language="none"}}com.webobjects.webservices.client.WOWebServiceClient{{/code}} class can't connect to a server that requires a Basic HTTP Authentication despite the fact this class offers a way to register a security delegate (see {{code language="none"}}setSecurityDelegateForServiceNamed(Object, String){{/code}} instance method).
Pascal Robert 2.1 157
Francis Labrie 9.1 158 Normally, the {{code language="none"}}processClientRequest(MessageContext){{/code}} delegate method (see {{code language="none"}}com.webobjects.webservices.support.WOSecurityDelegateinterface{{/code}} documentation) would allow an easy way to set a username and a password to the message context. But there is a problem related to the design of the class: to register a security delegate, the {{code language="none"}}WOWebServiceClient{{/code}} class has to fetch the Web Services Definition Language (WSDL) XML document. But to get access to this WSDL, an authentication header must be set. This is the classic chicken and egg problem...
Pascal Robert 2.1 159
Francis Labrie 7.1 160 === Solution: ===
Pascal Robert 2.1 161
Francis Labrie 9.1 162 The best would be to add a default method to {{code language="none"}}WOWebServiceClient{{/code}} class to register a default security delegate that is not related to a service name before the class fetch the WSDL. But unfortunately, all key methods that would allow this kind of behavior change are privates, so subclassing is not a solution...
Pascal Robert 2.1 163
Francis Labrie 6.1 164 But a workaround is still possible:
Pascal Robert 2.1 165
Francis Labrie 9.1 166 1. Fetch the WSDL document yourself and store it to the local filesystem, using the java.net.URL instance and setting up the Basic HTTP Authentication header field of the {{code language="none"}}java.net.URLConnection{{/code}} yourself;
167 1. Instanciate another {{code language="none"}}java.net.URL{{/code}} class that refer to the local WSDL document file;
168 1. Instanciate the {{code language="none"}}com.webobjects.webservices.client.WOWebServiceClient{{/code}} class using the file URL;
Pascal Robert 2.1 169 1. Set for each service a security delegate that will add the proper credential information for the Basic HTTP Authentication.
170
171 That's it. It looks like a big hack, but it works...
172
Francis Labrie 7.1 173 == Web Services can't return a WSDL with secure HTTPS references specifying port other than the default 443 ==
Pascal Robert 2.1 174
Francis Labrie 6.1 175 **Authors:** Francis Labrie
Francis Labrie 9.1 176 **Affected products:** //WebObjects// 5.2.x, 5.3.x
177 **Bug reference:** [[rdar:~~/~~/4196417>>url:rdar://4196417||shape="rect"]]
Francis Labrie 6.1 178
Francis Labrie 7.1 179 === Problem: ===
Francis Labrie 6.1 180
Pascal Robert 2.1 181 HTTPS protocol references can be published in Web Services WSDL. But unfortunately, WebObjects seems to ignore ports other than the default 443.
182
Francis Labrie 9.1 183 This problem is related to the bad way {{code language="none"}}com.webobjects.appserver.WORequest{{/code}} builds the URL prefix: if the protocol is secure and no port (i.e. 0) is set when calling the {{code language="none"}}_completeURLPrefix(StringBuffer, boolean, int){{/code}} method, the port will always be 443. Unfortunately, Web Services {{code language="none"}}com.webobjects.appserver._private.WOWebService{{/code}} class seems to call this method without setting the port number.
Pascal Robert 2.1 184
Francis Labrie 7.1 185 === Solution: ===
Pascal Robert 2.1 186
Francis Labrie 9.1 187 To work around this bug, you can subclass the {{code language="none"}}com.webobjects.appserver.WORequest{{/code}} class like this:
Francis Labrie 6.1 188
189 {{code}}
190
smmccraw 4.1 191 package com.smoguli.appserver;
Pascal Robert 2.1 192
193 import com.webobjects.appserver.WORequest;
194 import com.webobjects.foundation.NSData;
195 import com.webobjects.foundation.NSDictionary;
196
Francis Labrie 6.1 197 /**
Pascal Robert 2.1 198 * This class provide fixed {@link com.webobjects.appserver.WORequest} methods.
199 * To use it, just overload the {@link com.webobjects.appserver.WOApplication.
Francis Labrie 6.1 200 * createRequest(String,String,String,NSDictionary,NSData,NSDictionary)} method
Pascal Robert 2.1 201 * to instanciate this class instead.
202 *
Francis Labrie 6.1 203 * @author Francis Labrie <francis.labrie at smoguli.com>
Pascal Robert 2.1 204 */
205 public class WOFixedRequest extends WORequest {
206
Francis Labrie 6.1 207 /**
208 * @see com.webobjects.appserver.WORequest#WORequest(String,String,String,
209 * NSDictionary,NSData,NSDictionary)
210 */
211 public WOFixedRequest(String method, String url, String httpVersion, NSDictionary headers, NSData content, NSDictionary info) {
212 super(method, url, httpVersion, headers, content, info);
213 } // WOFixedRequest
Pascal Robert 2.1 214
Francis Labrie 6.1 215 /**
216 * This method builds the URL prefix into the <code>urlPrefix</code> buffer
217 * with the appropriate protocol (<code>http</code> or <code>https</code>)
218 * and the right TCP port. But unlike the {@link com.webobjects.appserver.
219 * WORequest#_completeURLPrefix(StringBuffer,boolean,int} method, it
220 * supports secure HTTP protocol (<code>https</code>) with port other than
221 * <code>443</code>, even if the <code>port</code> parameter is set
222 * <code>0</code>.
223 *
224 * @param urlPrefix the buffer that receives the contructed URL.
225 * @param isSecure a flag indicating if the protocol is secure.
226 * @param port the port number.
227 */
228 public void _completeURLPrefix(StringBuffer urlPrefix, boolean isSecure, int port) {
229 if(isSecure && (port == 0)) {
230 String serverPort;
Pascal Robert 2.1 231
Francis Labrie 6.1 232 serverPort = _serverPort();
233 if((serverPort != null) && !serverPort.equals("443")) {
234 try {
235 port = Integer.parseInt(serverPort);
236 } catch(NumberFormatException exception) {} // catch
237 } // if
238 } // if
Pascal Robert 2.1 239
Francis Labrie 6.1 240 super._completeURLPrefix(urlPrefix, isSecure, port);
241 } // _completeURLPrefix
242 } // WOFixedRequest
Pascal Robert 2.1 243
244 {{/code}}