001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.http;
018
019 import java.net.URI;
020
021 import javax.jbi.management.DeploymentException;
022 import javax.jbi.messaging.MessageExchange.Role;
023 import javax.jbi.servicedesc.ServiceEndpoint;
024 import javax.wsdl.Binding;
025 import javax.wsdl.Definition;
026 import javax.wsdl.Port;
027 import javax.wsdl.PortType;
028 import javax.wsdl.Service;
029 import javax.wsdl.extensions.ExtensibilityElement;
030 import javax.wsdl.extensions.http.HTTPAddress;
031 import javax.xml.namespace.QName;
032
033 import org.apache.servicemix.common.ExternalEndpoint;
034 import org.apache.servicemix.common.ManagementSupport;
035 import org.apache.servicemix.common.security.AuthenticationService;
036 import org.apache.servicemix.common.security.KeystoreManager;
037 import org.apache.servicemix.http.processors.ConsumerProcessor;
038 import org.apache.servicemix.http.processors.ProviderProcessor;
039 import org.apache.servicemix.http.tools.PortTypeDecorator;
040 import org.apache.servicemix.soap.SoapEndpoint;
041 import org.apache.servicemix.soap.SoapExchangeProcessor;
042
043 import com.ibm.wsdl.extensions.http.HTTPAddressImpl;
044
045 /**
046 * an HTTP endpoint. This is the base for all HTTP endpoints.
047 *
048 * @author gnodet
049 * @version $Revision: 695841 $
050 * @org.apache.xbean.XBean element="endpoint" description="the base element for all HTTP endpoints"
051 */
052 public class HttpEndpoint extends SoapEndpoint implements HttpEndpointType {
053
054 protected ExtensibilityElement binding;
055 protected String locationURI;
056 protected SslParameters ssl;
057 protected String authMethod;
058 protected String soapAction;
059 protected BasicAuthCredentials basicAuthentication;
060 protected ProxyParameters proxy;
061 protected boolean synchronous;
062 protected boolean wantContentTypeHeaderFromExchangeIntoHttpRequest;
063 protected int timeout;
064
065 public HttpEndpoint() {
066 }
067
068 public HttpEndpoint(boolean dynamic) {
069 super(dynamic);
070 }
071
072 /**
073 * Determines if the HTTP provider processor copies the HTTP headers from the HTTP response into the JBI exchange.
074 *
075 * @return <code>true</code> if the HTTP headers will be copied into the exchange
076 */
077 public boolean isWantContentTypeHeaderFromExchangeIntoHttpRequest() {
078 return wantContentTypeHeaderFromExchangeIntoHttpRequest;
079 }
080
081 /**
082 * Specifies if the HTTP provider processor copies the HTTP headers from the HTTP response into the JBI exchange. If the headers
083 * will be used for a new HTTP reuquest, setting this to <code>true</code> leads to an error.
084 *
085 * @param wantContentTypeHeaderFromExchangeIntoHttpRequest <code>true</code> if the HTTP headers will be copied into the exchange
086 * @org.apache.xbean.Property description="Specifies if the HTTP provider will copy the HTTP request headers into the JBI
087 * exchange. The default is <code>false</code>. This value overrides the value set for the component
088 * using the <code>configuration</code> element."
089 */
090 public void setWantContentTypeHeaderFromExchangeIntoHttpRequest(boolean wantContentTypeHeaderFromExchangeIntoHttpRequest) {
091 this.wantContentTypeHeaderFromExchangeIntoHttpRequest = wantContentTypeHeaderFromExchangeIntoHttpRequest;
092 }
093
094 /**
095 * @return the synchronous
096 */
097 public boolean isSynchronous() {
098 return synchronous;
099 }
100
101 /**
102 * @param synchronous the synchronous to set
103 */
104 public void setSynchronous(boolean synchronous) {
105 this.synchronous = synchronous;
106 }
107
108 /**
109 * @return the soapAction
110 */
111 public String getSoapAction() {
112 return soapAction;
113 }
114
115 /**
116 * @param soapAction the soapAction to set
117 */
118 public void setSoapAction(String soapAction) {
119 this.soapAction = soapAction;
120 }
121
122 /**
123 * Returns a string describing the authentication scheme being used by an endpoint.
124 *
125 * @return a string representing the authentication method used by an endpoint
126 */
127 public String getAuthMethod() {
128 return authMethod;
129 }
130
131 /**
132 * Specifies the authentication method used by a secure endpoint. The authentication method is a string naming the scheme used
133 * for authenticating users.
134 *
135 * @param authMethod a string naming the authentication scheme a secure endpoint should use
136 * @org.apache.xbean.Property description="a string naming the scheme used for authenticating users"
137 */
138 public void setAuthMethod(String authMethod) {
139 this.authMethod = authMethod;
140 }
141
142 /**
143 * @return Returns the ssl.
144 */
145 public SslParameters getSsl() {
146 return ssl;
147 }
148
149 /**
150 * Sets the properties used to configure SSL for the endpoint.
151 *
152 * @param ssl an <code>SslParameters</code> object containing the SSL properties
153 * @org.apache.xbean.Property description="a bean containing the SSL configuration properties"
154 */
155 public void setSsl(SslParameters ssl) {
156 this.ssl = ssl;
157 }
158
159 public ExtensibilityElement getBinding() {
160 return binding;
161 }
162
163 public void setBinding(ExtensibilityElement binding) {
164 this.binding = binding;
165 }
166
167 /**
168 * Returns the URI to which the endpoint sends requests.
169 *
170 * @return a string representing the URI to which requests are sent
171 */
172 public String getLocationURI() {
173 return locationURI;
174 }
175
176 /**
177 * Sets the URI to which an endpoint sends requests.
178 *
179 * @param locationUri a string representing the URI
180 * @org.apache.xbean.Property description="the URI to which a provider endpoint sends requests"
181 */
182 public void setLocationURI(String locationUri) {
183 this.locationURI = locationUri;
184 }
185
186 /**
187 * Sets the authentication data used for provider endpoints using basic authentication.
188 *
189 * @param basicAuthCredentials the <code>BasicAuthCredentials</code> that will be used for authentication
190 * @org.apache.xbean.Property description="authentication data for using basic HTTP authentication."
191 */
192 public void setBasicAuthentication(BasicAuthCredentials basicAuthCredentials) {
193 this.basicAuthentication = basicAuthCredentials;
194 }
195
196 /**
197 * Gets the authentication data used for provider endpoints using basic authentication.
198 *
199 * @return the <code>BasicAuthCredentials</code> to use for authentication
200 */
201 public BasicAuthCredentials getBasicAuthentication() {
202 return basicAuthentication;
203 }
204
205 /**
206 * @return Returns the proxy.
207 */
208 public ProxyParameters getProxy() {
209 return this.proxy;
210 }
211
212 /**
213 * Sets the configuration information for the proxy used by a HTTP consumer endpoint. This configuration overrides the proxy
214 * configuraiton specified at the component level.
215 *
216 * @param proxy The proxy to set.
217 * @org.apache.xbean.Property description="configuration used to establish a proxy for sending HTTP requests. This configuration overrides that which is set at the component level."
218 */
219 public void setProxy(ProxyParameters proxy) {
220 this.proxy = proxy;
221 }
222
223 /**
224 * Sets the endpoint's role. HTTP endpoints can be either consumers or providers. Specifying <code>consumer</code> for the role
225 * defines the endpoint as a consumer which exposes an endpoint at a URL. Specifying <code>provider</code> for the role defines
226 * the endpoint as a provider that sends HTTP requests to a URL.
227 *
228 * @param role a string specifying the role of the endpoint
229 * @org.apache.xbean.Property alias="role" description= "HTTP endpoints can be either consumers or providers. Specifying
230 * <code>consumer</code> for the role defines the endpoint as a consumer which exposes an endpoint at
231 * a URL. Specifying <code>provider</code> for the role defines the endpoint as a provider that sends
232 * HTTP requests to a URL."
233 */
234 public void setRoleAsString(String role) {
235 super.setRoleAsString(role);
236 }
237
238 /**
239 * Specifies the timeout value for an HTTP endpoint. The timeout is specified in milliseconds. The default value is 0 which
240 * means that the endpoint will never timeout.
241 *
242 * @org.apache.xbean.Property description=
243 * "the number of milliseconds before the endpoint times out. The default value is 0 which means that the endpoint will never timeout."
244 * @param timeout the length time, in milliseconds, to wait before timing out
245 */
246 public void setTimeout(int timeout) {
247 this.timeout = timeout;
248 }
249
250 /**
251 * Returns the timeout value for an HTTP endpoint.
252 *
253 * @return the timeout specified in milliseconds
254 */
255 public int getTimeout() {
256 return timeout;
257 }
258
259 public void reloadWsdl() {
260 description = null;
261 definition = null;
262 loadWsdl();
263 }
264
265 protected PortType getTargetPortType(Definition def) {
266 PortType portType = null;
267 // If the WSDL description only contain one PortType, use it
268 if (def.getServices().size() == 0 && def.getPortTypes().size() == 1) {
269 if (logger.isDebugEnabled()) {
270 logger.debug("WSDL only defines a PortType, using this one");
271 }
272 portType = (PortType)def.getPortTypes().values().iterator().next();
273 } else if (targetInterfaceName != null) {
274 portType = def.getPortType(targetInterfaceName);
275 if (portType == null && logger.isDebugEnabled()) {
276 logger.debug("PortType for targetInterfaceName could not be found");
277 }
278 } else if (targetService != null && targetEndpoint != null) {
279 Service svc = def.getService(targetService);
280 Port port = (svc != null) ? svc.getPort(targetEndpoint) : null;
281 portType = (port != null) ? port.getBinding().getPortType() : null;
282 if (portType == null && logger.isDebugEnabled()) {
283 logger.debug("PortType for targetService/targetEndpoint could not be found");
284 }
285 } else if (targetService != null) {
286 Service svc = def.getService(targetService);
287 if (svc != null && svc.getPorts().size() == 1) {
288 Port port = (Port)svc.getPorts().values().iterator().next();
289 portType = (port != null) ? port.getBinding().getPortType() : null;
290 }
291 if (portType == null && logger.isDebugEnabled()) {
292 logger.debug("Service for targetService could not be found");
293 }
294 } else if (interfaceName != null) {
295 portType = def.getPortType(interfaceName);
296 if (portType == null && logger.isDebugEnabled()) {
297 logger.debug("Service for targetInterfaceName could not be found");
298 }
299 } else {
300 Service svc = def.getService(service);
301 Port port = (svc != null) ? svc.getPort(endpoint) : null;
302 portType = (port != null && port.getBinding() != null) ? port.getBinding().getPortType() : null;
303 if (portType == null && logger.isDebugEnabled()) {
304 logger.debug("Port for service/endpoint could not be found");
305 }
306 }
307 return portType;
308 }
309
310 protected void overrideDefinition(Definition def) throws Exception {
311 PortType portType = getTargetPortType(def);
312 if (portType != null) {
313 QName[] names = (QName[])def.getPortTypes().keySet().toArray(new QName[0]);
314 for (int i = 0; i < names.length; i++) {
315 if (!names[i].equals(portType.getQName())) {
316 def.removePortType(names[i]);
317 }
318 }
319 names = (QName[])def.getServices().keySet().toArray(new QName[0]);
320 for (int i = 0; i < names.length; i++) {
321 def.removeService(names[i]);
322 }
323 names = (QName[])def.getBindings().keySet().toArray(new QName[0]);
324 for (int i = 0; i < names.length; i++) {
325 def.removeBinding(names[i]);
326 }
327 String location = getLocationURI();
328 if (!location.endsWith("/")) {
329 location += "/";
330 }
331 HttpComponent comp = (HttpComponent)getServiceUnit().getComponent();
332 if (comp.getConfiguration().isManaged()) {
333 // Save the path
334 String path = new URI(location).getPath();
335 location = "http://localhost";
336 if (comp.getHost() != null) {
337 if (comp.getProtocol() != null) {
338 location = comp.getProtocol() + "://";
339 } else {
340 location = "http://";
341 }
342 location += comp.getHost();
343 if (comp.getPort() != 80) {
344 location += ":" + comp.getPort();
345 }
346 if (comp.getPath() != null) {
347 location += comp.getPath();
348 }
349 }
350 location += comp.getConfiguration().getMapping() + path;
351 }
352 if (portType.getQName().getNamespaceURI().equals(service.getNamespaceURI())) {
353 if (isSoap()) {
354 PortTypeDecorator.decorate(def, portType, location, endpoint + "Binding", service
355 .getLocalPart(), endpoint, soapVersion);
356 definition = def;
357 } else {
358 Binding bnd = def.createBinding();
359 bnd.setPortType(portType);
360 bnd.setQName(new QName(service.getNamespaceURI(), endpoint + "Binding"));
361 bnd.setUndefined(false);
362 def.addBinding(bnd);
363 Port port = def.createPort();
364 port.setName(endpoint);
365 port.setBinding(bnd);
366 HTTPAddress address = new HTTPAddressImpl();
367 address.setLocationURI(location);
368 port.addExtensibilityElement(address);
369 def.addNamespace("http", "http://schemas.xmlsoap.org/wsdl/http/");
370 Service svc = def.createService();
371 svc.setQName(service);
372 svc.addPort(port);
373 def.addService(svc);
374 definition = def;
375 }
376 } else {
377 definition = PortTypeDecorator.createImportDef(def, service.getNamespaceURI(),
378 "porttypedef.wsdl");
379 PortTypeDecorator.decorate(definition, portType, location, endpoint + "Binding", service
380 .getLocalPart(), endpoint, soapVersion);
381 }
382 }
383 }
384
385 protected SoapExchangeProcessor createProviderProcessor() {
386 return new ProviderProcessor(this);
387 }
388
389 protected SoapExchangeProcessor createConsumerProcessor() {
390 return new ConsumerProcessor(this);
391 }
392
393 protected ServiceEndpoint createExternalEndpoint() {
394 return new ExternalEndpoint(getServiceUnit().getComponent().getEPRElementName(), getLocationURI(),
395 getService(), getEndpoint(), getInterfaceName());
396 }
397
398 public AuthenticationService getAuthenticationService() {
399 HttpComponent comp = (HttpComponent)getServiceUnit().getComponent();
400 return AuthenticationService.Proxy.create(comp.getAuthenticationService());
401 }
402
403 public KeystoreManager getKeystoreManager() {
404 HttpComponent comp = (HttpComponent)getServiceUnit().getComponent();
405 return KeystoreManager.Proxy.create(comp.getKeystoreManager());
406 }
407
408 public void validate() throws DeploymentException {
409 if (getRole() == null) {
410 throw failure("deploy", "Endpoint must have a defined role", null);
411 }
412 if (getLocationURI() == null) {
413 throw failure("deploy", "Endpoint must have a defined locationURI", null);
414 }
415 if (!isSoap() && getRole() == Role.CONSUMER && getDefaultMep() == null) {
416 throw failure("deploy", "Non soap endpoints must have a defined defaultMep", null);
417 }
418 }
419
420 protected DeploymentException failure(String task, String info, Throwable e) {
421 ManagementSupport.Message msg = new ManagementSupport.Message();
422 msg.setComponent(serviceUnit.getComponent().getComponentName());
423 msg.setTask(task);
424 msg.setResult("FAILED");
425 msg.setType("ERROR");
426 msg.setMessage(info);
427 msg.setException(e);
428 return new DeploymentException(ManagementSupport.createComponentMessage(msg));
429 }
430
431 }