Changes for page Web Services-Problems

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

From version 6.1
edited by Francis Labrie
on 2007/09/26 11:17
Change comment: Updates and layout fixes
To version 5.1
edited by smmccraw
on 2007/07/08 09:46
Change comment: There is no comment for this version

Summary

Details

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