From ad1c9458ea08eb593be252b706a88568f17c494c Mon Sep 17 00:00:00 2001 From: lresende Date: Wed, 19 Nov 2008 00:07:37 +0000 Subject: Moving current trunk modules to contrib, before starting the Equinox branch merge git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@718812 13f79535-47bb-0310-9956-ffa450edef68 --- .../http/provider/HTTPBindingListenerServlet.java | 516 +++++++++++++++++++++ .../http/provider/HTTPBindingProviderFactory.java | 64 +++ .../http/provider/HTTPGetListenerServlet.java | 94 ++++ .../http/provider/HTTPServiceBindingProvider.java | 137 ++++++ .../http/provider/HTTPServiceListenerServlet.java | 136 ++++++ .../sca/binding/http/util/HTTPHeadersParser.java | 50 ++ ...che.tuscany.sca.provider.BindingProviderFactory | 19 + 7 files changed, 1016 insertions(+) create mode 100644 java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingListenerServlet.java create mode 100644 java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingProviderFactory.java create mode 100644 java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPGetListenerServlet.java create mode 100644 java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceBindingProvider.java create mode 100644 java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceListenerServlet.java create mode 100644 java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/util/HTTPHeadersParser.java create mode 100644 java/sca/contrib/modules/binding-http-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory (limited to 'java/sca/contrib/modules/binding-http-runtime/src/main') diff --git a/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingListenerServlet.java b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingListenerServlet.java new file mode 100644 index 0000000000..084f52026f --- /dev/null +++ b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingListenerServlet.java @@ -0,0 +1,516 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.http.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URLDecoder; +import java.text.ParseException; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.binding.http.HTTPCacheContext; +import org.apache.tuscany.sca.binding.http.util.HTTPHeadersParser; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySetAttachPoint; +import org.apache.tuscany.sca.policy.authentication.basic.BasicAuthenticationPolicy; + +/** + * Servlet responsible for dispatching HTTP requests to the + * target component implementation. + * + * @version $Rev$ $Date$ + */ +public class HTTPBindingListenerServlet extends HttpServlet { + private static final long serialVersionUID = 2865466417329430610L; + + private static final QName AUTEHTICATION_INTENT = new QName("http://www.osoa.org/xmlns/sca/1.0","authentication"); + + transient private Binding binding; + + transient private boolean requiresAuthentication = false; + transient private BasicAuthenticationPolicy basicAuthenticationPolicy = null; + + private MessageFactory messageFactory; + private Invoker getInvoker; + private Invoker conditionalGetInvoker; + private Invoker putInvoker; + private Invoker conditionalPutInvoker; + private Invoker postInvoker; + private Invoker conditionalPostInvoker; + private Invoker deleteInvoker; + private Invoker conditionalDeleteInvoker; + + /** + * Constructs a new HTTPServiceListenerServlet. + */ + public HTTPBindingListenerServlet(Binding binding, MessageFactory messageFactory) { + this.binding = binding; + this.messageFactory = messageFactory; + + + // find out which policies are active + if (binding instanceof PolicySetAttachPoint) { + List intents = ((PolicySetAttachPoint)binding).getRequiredIntents(); + for(Intent intent : intents) { + if(intent.getName().equals(AUTEHTICATION_INTENT)) { + requiresAuthentication = true; + } + } + + + List policySets = ((PolicySetAttachPoint)binding).getApplicablePolicySets(); + for (PolicySet ps : policySets) { + for (Object p : ps.getPolicies()) { + if (BasicAuthenticationPolicy.class.isInstance(p)) { + basicAuthenticationPolicy = (BasicAuthenticationPolicy)p; + } else { + // etc. check for other types of policy being present + } + } + } + } + } + + + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + if(requiresAuthentication) { + if(! hasAuthenticationHeader(request, response)) { + response.setHeader("WWW-Authenticate", "BASIC realm=\"Tuscany\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } + } + + super.service(request, response); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // Get the request path + String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8"); + if (path.length() ==0) { + // Redirect to a URL ending with / to make relative hrefs work + // relative to the served resource. + response.sendRedirect(request.getRequestURL().append('/').toString()); + return; + } + + // Invoke the get operation on the service implementation + Message requestMessage = messageFactory.createMessage(); + + //store http headers to message + requestMessage.getHeaders().addAll(HTTPHeadersParser.getHeaders(request)); + + String id = path.substring(1); + + Message responseMessage = null; + HTTPCacheContext cacheContext = null; + try { + cacheContext = HTTPCacheContext.getCacheContextFromRequest(request); + } catch (ParseException e) { + } + + // Route message based on availability of cache info and cache methods + if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalGetInvoker != null )) { + requestMessage.setBody(new Object[] {id, cacheContext}); + responseMessage = conditionalGetInvoker.invoke(requestMessage); + } else { + requestMessage.setBody(new Object[] {id}); + responseMessage = getInvoker.invoke(requestMessage); + } + if (responseMessage.isFault()) { + Object body = responseMessage.getBody(); + + int index = -1; + if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_NOT_MODIFIED ); + return; + } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED ); + return; + } + + throw new ServletException((Throwable)responseMessage.getBody()); + } + + // Write the response from the service implementation to the response + // output stream + InputStream is = (InputStream)responseMessage.getBody(); + OutputStream os = response.getOutputStream(); + byte[] buffer = new byte[2048]; + for (;;) { + int n = is.read(buffer); + if (n <= 0) + break; + os.write(buffer, 0, n); + } + os.flush(); + os.close(); + } + + @Override + protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // Get the request path + String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8"); + if (path.length() ==0) { + // Redirect to a URL ending with / to make relative hrefs work + // relative to the served resource. + response.sendRedirect(request.getRequestURL().append('/').toString()); + return; + } + + // Invoke the get operation on the service implementation + Message requestMessage = messageFactory.createMessage(); + String id = path.substring(1); + + Message responseMessage = null; + HTTPCacheContext cacheContext = null; + try { + cacheContext = HTTPCacheContext.getCacheContextFromRequest(request); + } catch (ParseException e) { + } + + // Route message based on availability of cache info and cache methods + if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalDeleteInvoker != null )) { + requestMessage.setBody(new Object[] {id, cacheContext}); + responseMessage = conditionalDeleteInvoker.invoke(requestMessage); + } else { + requestMessage.setBody(new Object[] {id}); + responseMessage = deleteInvoker.invoke(requestMessage); + } + if (responseMessage.isFault()) { + Object body = responseMessage.getBody(); + + int index = -1; + if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_NOT_MODIFIED ); + return; + } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED ); + return; + } + + throw new ServletException((Throwable)responseMessage.getBody()); + } + + // Write the response from the service implementation to the response + // output stream + InputStream is = (InputStream)responseMessage.getBody(); + OutputStream os = response.getOutputStream(); + byte[] buffer = new byte[2048]; + for (;;) { + int n = is.read(buffer); + if (n <= 0) + break; + os.write(buffer, 0, n); + } + os.flush(); + os.close(); + } + + @Override + protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // Get the request path + String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8"); + if (path.length() ==0) { + // Redirect to a URL ending with / to make relative hrefs work + // relative to the served resource. + response.sendRedirect(request.getRequestURL().append('/').toString()); + return; + } + + // Invoke the get operation on the service implementation + Message requestMessage = messageFactory.createMessage(); + String id = path.substring(1); + + Message responseMessage = null; + HTTPCacheContext cacheContext = null; + try { + cacheContext = HTTPCacheContext.getCacheContextFromRequest(request); + } catch (ParseException e) { + } + + // Route message based on availability of cache info and cache methods + if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalPutInvoker != null )) { + requestMessage.setBody(new Object[] {id, cacheContext}); + responseMessage = conditionalPutInvoker.invoke(requestMessage); + } else { + requestMessage.setBody(new Object[] {id}); + responseMessage = putInvoker.invoke(requestMessage); + } + if (responseMessage.isFault()) { + Object body = responseMessage.getBody(); + + int index = -1; + if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_NOT_MODIFIED ); + return; + } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED ); + return; + } + + throw new ServletException((Throwable)responseMessage.getBody()); + } + + // Write the response from the service implementation to the response + // output stream + InputStream is = (InputStream)responseMessage.getBody(); + OutputStream os = response.getOutputStream(); + byte[] buffer = new byte[2048]; + for (;;) { + int n = is.read(buffer); + if (n <= 0) + break; + os.write(buffer, 0, n); + } + os.flush(); + os.close(); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // Get the request path + String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8"); + if (path.length() ==0) { + // Redirect to a URL ending with / to make relative hrefs work + // relative to the served resource. + response.sendRedirect(request.getRequestURL().append('/').toString()); + return; + } + + // Invoke the get operation on the service implementation + Message requestMessage = messageFactory.createMessage(); + // String id = path.substring(1); + + Message responseMessage = null; + HTTPCacheContext cacheContext = null; + try { + cacheContext = HTTPCacheContext.getCacheContextFromRequest(request); + } catch (ParseException e) { + } + + // Route message based on availability of cache info and cache methods + if (( cacheContext != null ) && (cacheContext.isEnabled()) && (conditionalPostInvoker != null )) { + requestMessage.setBody(new Object[] {cacheContext}); + responseMessage = conditionalPostInvoker.invoke(requestMessage); + } else { + requestMessage.setBody(new Object[] {}); + responseMessage = postInvoker.invoke(requestMessage); + } + if (responseMessage.isFault()) { + Object body = responseMessage.getBody(); + + int index = -1; + if ( -1 < (index = body.getClass().getName().indexOf( "NotModifiedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_NOT_MODIFIED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_NOT_MODIFIED ); + return; + } else if ( -1 < (index = body.getClass().getName().indexOf( "PreconditionFailedException")) ) { + if ( index > -1 ) + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED, body.toString().substring( index )); + else + response.sendError( HttpServletResponse.SC_PRECONDITION_FAILED ); + return; + } + + throw new ServletException((Throwable)responseMessage.getBody()); + } + + + // Test if the ETag and LastModified are returned as a cache context. + Object body = responseMessage.getBody(); + if ( body.getClass() == HTTPCacheContext.class ) { + // Transfer to header if so. + HTTPCacheContext cc = (HTTPCacheContext)responseMessage.getBody(); + if (( cc != null ) && ( cc.isEnabled() )) { + String eTag = cc.getETag(); + if ( eTag != null ) + response.setHeader( "ETag", cc.getETag() ); + String lastModified = cc.getLastModified(); + if ( lastModified != null) + response.setHeader( "LastModified", cc.getLastModified() ); + } + } + } + + /** + * @return the getInvoker + */ + public Invoker getGetInvoker() { + return getInvoker; + } + + /** + * @param getInvoker the getInvoker to set + */ + public void setGetInvoker(Invoker getInvoker) { + this.getInvoker = getInvoker; + } + + /** + * @return the conditionalGetInvoker + */ + public Invoker getConditionalGetInvoker() { + return conditionalGetInvoker; + } + + /** + * @param conditionalGetInvoker the conditionalGetInvoker to set + */ + public void setConditionalGetInvoker(Invoker conditionalGetInvoker) { + this.conditionalGetInvoker = conditionalGetInvoker; + } + + /** + * @return the putInvoker + */ + public Invoker getPutInvoker() { + return putInvoker; + } + + /** + * @param putInvoker the putInvoker to set + */ + public void setPutInvoker(Invoker putInvoker) { + this.putInvoker = putInvoker; + } + + /** + * @return the conditionalPutInvoker + */ + public Invoker getConditionalPutInvoker() { + return conditionalPutInvoker; + } + + /** + * @param conditionalPutInvoker the conditionalPutInvoker to set + */ + public void setConditionalPutInvoker(Invoker conditionalPutInvoker) { + this.conditionalPutInvoker = conditionalPutInvoker; + } + + /** + * @return the postInvoker + */ + public Invoker getPostInvoker() { + return postInvoker; + } + + /** + * @param postInvoker the postInvoker to set + */ + public void setPostInvoker(Invoker postInvoker) { + this.postInvoker = postInvoker; + } + + /** + * @return the conditionalPostInvoker + */ + public Invoker getConditionalPostInvoker() { + return conditionalPostInvoker; + } + + /** + * @param conditionalPostInvoker the conditionalPostInvoker to set + */ + public void setConditionalPostInvoker(Invoker conditionalPostInvoker) { + this.conditionalPostInvoker = conditionalPostInvoker; + } + + /** + * @return the deleteInvoker + */ + public Invoker getDeleteInvoker() { + return deleteInvoker; + } + + /** + * @param deleteInvoker the deleteInvoker to set + */ + public void setDeleteInvoker(Invoker deleteInvoker) { + this.deleteInvoker = deleteInvoker; + } + + /** + * @return the conditionalDeleteInvoker + */ + public Invoker getConditionalDeleteInvoker() { + return conditionalDeleteInvoker; + } + + /** + * @param conditionalDeleteInvoker the conditionalDeleteInvoker to set + */ + public void setConditionalDeleteInvoker(Invoker conditionalDeleteInvoker) { + this.conditionalDeleteInvoker = conditionalDeleteInvoker; + } + + + /** + * Utility Methods related to Policy + */ + + + private boolean hasAuthenticationHeader(HttpServletRequest request, ServletResponse response) { + boolean result = false; + if(request.getHeader("Authorization") != null) { + result = true; + } + + return result; + } + + +} diff --git a/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingProviderFactory.java b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingProviderFactory.java new file mode 100644 index 0000000000..fccd10f3cd --- /dev/null +++ b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPBindingProviderFactory.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.http.provider; + +import org.apache.tuscany.sca.binding.http.HTTPBinding; +import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.host.http.ServletHostExtensionPoint; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; + + +/** + * Factory for HTTP binding providers. + * + * @version $Rev$ $Date$ + */ +public class HTTPBindingProviderFactory implements BindingProviderFactory { + + private MessageFactory messageFactory; + private ServletHost servletHost; + + public HTTPBindingProviderFactory(ExtensionPointRegistry extensionPoints) { + ServletHostExtensionPoint servletHosts = extensionPoints.getExtensionPoint(ServletHostExtensionPoint.class); + this.servletHost = servletHosts.getServletHosts().get(0); + ModelFactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class); + messageFactory = modelFactories.getFactory(MessageFactory.class); + } + + public ReferenceBindingProvider createReferenceBindingProvider(RuntimeComponent component, RuntimeComponentReference reference, HTTPBinding binding) { + return null; + } + + public ServiceBindingProvider createServiceBindingProvider(RuntimeComponent component, RuntimeComponentService service, HTTPBinding binding) { + return new HTTPServiceBindingProvider(component, service, binding, messageFactory, servletHost); + } + + public Class getModelType() { + return HTTPBinding.class; + } +} diff --git a/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPGetListenerServlet.java b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPGetListenerServlet.java new file mode 100644 index 0000000000..e20d420d49 --- /dev/null +++ b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPGetListenerServlet.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.http.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URLDecoder; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; + +/** + * Servlet responsible for dispatching HTTP GET requests to the + * target component implementation. + * + * @version $Rev$ $Date$ + */ +public class HTTPGetListenerServlet extends HttpServlet { + private static final long serialVersionUID = 2865466417329430610L; + + private MessageFactory messageFactory; + private Invoker getInvoker; + + /** + * Constructs a new HTTPServiceListenerServlet. + */ + public HTTPGetListenerServlet(Invoker getInvoker, MessageFactory messageFactory) { + this.getInvoker = getInvoker; + this.messageFactory = messageFactory; + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + // Get the request path + String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8"); + if (path.length() ==0) { + + // Redirect to a URL ending with / to make relative hrefs work + // relative to the served resource. + response.sendRedirect(request.getRequestURL().append('/').toString()); + return; + } + + // Invoke the get operation on the service implementation + Message requestMessage = messageFactory.createMessage(); + String id = path.substring(1); + requestMessage.setBody(new Object[] {id}); + Message responseMessage = getInvoker.invoke(requestMessage); + if (responseMessage.isFault()) { + throw new ServletException((Throwable)responseMessage.getBody()); + } + + // Write the response from the service implementation to the response + // output stream + InputStream is = (InputStream)responseMessage.getBody(); + OutputStream os = response.getOutputStream(); + byte[] buffer = new byte[2048]; + for (;;) { + int n = is.read(buffer); + if (n <= 0) + break; + os.write(buffer, 0, n); + } + os.flush(); + os.close(); + + } + +} diff --git a/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceBindingProvider.java b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceBindingProvider.java new file mode 100644 index 0000000000..8f91ff4343 --- /dev/null +++ b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceBindingProvider.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.http.provider; + +import javax.servlet.Servlet; + +import org.apache.tuscany.sca.binding.http.HTTPBinding; +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.runtime.RuntimeWire; + +/** + * Implementation of an HTTP binding provider. + * + * @version $Rev$ $Date$ + */ +public class HTTPServiceBindingProvider implements ServiceBindingProvider { + private RuntimeComponentService service; + private HTTPBinding binding; + private MessageFactory messageFactory; + + private ServletHost servletHost; + private String servletMapping; + private HTTPBindingListenerServlet bindingListenerServlet; + + public HTTPServiceBindingProvider(RuntimeComponent component, + RuntimeComponentService service, + HTTPBinding binding, + MessageFactory messageFactory, + ServletHost servletHost) { + this.service = service; + this.binding = binding; + this.messageFactory = messageFactory; + this.servletHost = servletHost; + } + + public void start() { + // Get the invokers for the supported operations + RuntimeComponentService componentService = (RuntimeComponentService) service; + RuntimeWire wire = componentService.getRuntimeWire(binding); + Servlet servlet = null; + bindingListenerServlet = new HTTPBindingListenerServlet(binding, messageFactory ); + for (InvocationChain invocationChain : wire.getInvocationChains()) { + Operation operation = invocationChain.getTargetOperation(); + String operationName = operation.getName(); + if (operationName.equals("get")) { + Invoker getInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setGetInvoker(getInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("conditionalGet")) { + Invoker conditionalGetInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setConditionalGetInvoker(conditionalGetInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("delete")) { + Invoker deleteInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setDeleteInvoker(deleteInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("conditionalDelete")) { + Invoker conditionalDeleteInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setConditionalDeleteInvoker(conditionalDeleteInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("put")) { + Invoker putInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setPutInvoker(putInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("conditionalPut")) { + Invoker conditionalPutInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setConditionalPutInvoker(conditionalPutInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("post")) { + Invoker postInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setPostInvoker(postInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("conditionalPost")) { + Invoker conditionalPostInvoker = invocationChain.getHeadInvoker(); + bindingListenerServlet.setConditionalPostInvoker(conditionalPostInvoker); + servlet = bindingListenerServlet; + } else if (operationName.equals("service")) { + Invoker serviceInvoker = invocationChain.getHeadInvoker(); + servlet = new HTTPServiceListenerServlet(binding, serviceInvoker, messageFactory); + break; + } + } + if (servlet == null) { + throw new IllegalStateException("No get or service method found on the service"); + } + + // Create our HTTP service listener Servlet and register it with the + // Servlet host + servletMapping = binding.getURI(); + if (!servletMapping.endsWith("/")) { + servletMapping += "/"; + } + if (!servletMapping.endsWith("*")) { + servletMapping += "*"; + } + servletHost.addServletMapping(servletMapping, servlet); + } + + public void stop() { + // Unregister the Servlet from the Servlet host + servletHost.removeServletMapping(servletMapping); + } + + public InterfaceContract getBindingInterfaceContract() { + return null; + } + + public boolean supportsOneWayInvocation() { + return false; + } + +} diff --git a/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceListenerServlet.java b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceListenerServlet.java new file mode 100644 index 0000000000..493255655d --- /dev/null +++ b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/provider/HTTPServiceListenerServlet.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.http.provider; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySetAttachPoint; +import org.apache.tuscany.sca.policy.authentication.basic.BasicAuthenticationPolicy; + +/** + * Servlet responsible for dispatching HTTP service requests to the + * target component implementation. + * + * @version $Rev$ $Date$ + */ +public class HTTPServiceListenerServlet implements Servlet { + private static final QName AUTEHTICATION_INTENT = new QName("http://www.osoa.org/xmlns/sca/1.0","authentication"); + + transient private Binding binding; + transient private ServletConfig config; + transient private MessageFactory messageFactory; + transient private Invoker serviceInvoker; + + transient private boolean requiresAuthentication = false; + transient private BasicAuthenticationPolicy basicAuthenticationPolicy = null; + + /** + * Constructs a new HTTPServiceListenerServlet. + */ + public HTTPServiceListenerServlet(Binding binding, Invoker serviceInvoker, MessageFactory messageFactory) { + this.binding = binding; + this.serviceInvoker = serviceInvoker; + this.messageFactory = messageFactory; + + // find out which policies are active + if (binding instanceof PolicySetAttachPoint) { + List intents = ((PolicySetAttachPoint)binding).getRequiredIntents(); + for(Intent intent : intents) { + if(intent.getName().equals(AUTEHTICATION_INTENT)) { + requiresAuthentication = true; + } + } + + + List policySets = ((PolicySetAttachPoint)binding).getApplicablePolicySets(); + for (PolicySet ps : policySets) { + for (Object p : ps.getPolicies()) { + if (BasicAuthenticationPolicy.class.isInstance(p)) { + basicAuthenticationPolicy = (BasicAuthenticationPolicy)p; + } else { + // etc. check for other types of policy being present + } + } + } + } + } + + public ServletConfig getServletConfig() { + return config; + } + + public String getServletInfo() { + return ""; + } + + public void init(ServletConfig config) throws ServletException { + this.config = config; + } + + public void destroy() { + + } + + public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { + + if(requiresAuthentication) { + if(! hasAuthenticationHeader((HttpServletRequest)request, (HttpServletResponse)response)) { + ((HttpServletResponse)response).sendError(HttpServletResponse.SC_UNAUTHORIZED); + } + } + + // Dispatch the service interaction to the service invoker + Message requestMessage = messageFactory.createMessage(); + requestMessage.setBody(new Object[]{request, response}); + Message responseMessage = serviceInvoker.invoke(requestMessage); + if (responseMessage.isFault()) { + // Turn a fault into an exception + //throw new ServletException((Throwable)responseMessage.getBody()); + Throwable e = (Throwable)responseMessage.getBody(); + ((HttpServletResponse)response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString()); + } + } + + + private boolean hasAuthenticationHeader(HttpServletRequest request, ServletResponse response) { + boolean result = false; + if(request.getHeader("Authorization") != null) { + result = true; + } + + return result; + } +} diff --git a/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/util/HTTPHeadersParser.java b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/util/HTTPHeadersParser.java new file mode 100644 index 0000000000..1fe4600e31 --- /dev/null +++ b/java/sca/contrib/modules/binding-http-runtime/src/main/java/org/apache/tuscany/sca/binding/http/util/HTTPHeadersParser.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.http.util; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.tuscany.sca.binding.http.HTTPHeader; + +public class HTTPHeadersParser { + + /** + * Parse http request headers to a map + * + * @param request + * @return + */ + public static List getHeaders(HttpServletRequest request) { + List headers = new ArrayList(); + + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = (String) headerNames.nextElement(); + Object headerValue = request.getHeader(headerName); + HTTPHeader header = new HTTPHeader(headerName, headerValue); + headers.add(header); + } + return headers; + } +} diff --git a/java/sca/contrib/modules/binding-http-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory b/java/sca/contrib/modules/binding-http-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory new file mode 100644 index 0000000000..0fa8d44c08 --- /dev/null +++ b/java/sca/contrib/modules/binding-http-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Implementation class for the binding extension +org.apache.tuscany.sca.binding.http.provider.HTTPBindingProviderFactory;model=org.apache.tuscany.sca.binding.http.HTTPBinding -- cgit v1.2.3