| /* |
| * 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.rest.provider; |
| |
| import java.io.IOException; |
| import java.lang.annotation.Annotation; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.Enumeration; |
| import java.util.GregorianCalendar; |
| import java.util.HashSet; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import javax.servlet.FilterConfig; |
| import javax.servlet.ServletContext; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import javax.ws.rs.core.MediaType; |
| import javax.ws.rs.ext.MessageBodyWriter; |
| |
| import org.apache.tuscany.sca.assembly.Binding; |
| import org.apache.tuscany.sca.binding.rest.RESTBinding; |
| import org.apache.tuscany.sca.common.http.HTTPCacheContext; |
| import org.apache.tuscany.sca.common.http.HTTPContext; |
| import org.apache.tuscany.sca.common.http.HTTPHeader; |
| import org.apache.tuscany.sca.common.http.ThreadHTTPContext; |
| import org.apache.tuscany.sca.common.http.cors.CORSHeaderProcessor; |
| import org.apache.tuscany.sca.core.ExtensionPointRegistry; |
| import org.apache.tuscany.sca.extensibility.ClassLoaderContext; |
| import org.apache.wink.common.internal.registry.ProvidersRegistry; |
| import org.apache.wink.common.model.wadl.WADLGenerator; |
| import org.apache.wink.server.handlers.HandlersChain; |
| import org.apache.wink.server.handlers.MessageContext; |
| import org.apache.wink.server.handlers.ResponseHandler; |
| import org.apache.wink.server.internal.DeploymentConfiguration; |
| import org.apache.wink.server.internal.servlet.RestServlet; |
| |
| /** |
| * |
| */ |
| public class TuscanyRESTServlet extends RestServlet { |
| private static final long serialVersionUID = 89997233133964915L; |
| |
| private static final Logger logger = Logger.getLogger(TuscanyRESTServlet.class.getName()); |
| |
| private static final Annotation[] annotations = new Annotation[0]; |
| |
| |
| private ExtensionPointRegistry registry; |
| private RESTBinding binding; |
| private Class<?> resourceClass; |
| |
| public TuscanyRESTServlet(ExtensionPointRegistry registry, Binding binding, Class<?> resourceClass) { |
| super(); |
| this.registry = registry; |
| this.binding = (RESTBinding) binding; |
| this.resourceClass = resourceClass; |
| } |
| |
| @Override |
| protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { |
| |
| if (binding.isCORS()) { |
| CORSHeaderProcessor.processCORS(binding.getCORSConfiguration(), request, response); |
| } |
| |
| //create context |
| HTTPContext bindingContext = new HTTPContext(); |
| bindingContext.setHttpRequest(request); |
| bindingContext.setHttpResponse(response); |
| |
| |
| try { |
| //store in thread local |
| ThreadHTTPContext.setHTTPContext(bindingContext); |
| ThreadBindingContext.setBindingContext(binding); |
| |
| // handle special ?wadl request |
| String query = request.getQueryString(); |
| if(query != null && query.indexOf("wadl") >= 0) { |
| handleWadlRequest(request, response); |
| } else { |
| super.service(request, response); |
| } |
| } finally { |
| //remove |
| ThreadHTTPContext.removeHTTPContext(); |
| ThreadBindingContext.removeBindingContext(); |
| } |
| } |
| |
| |
| public void init() throws ServletException { |
| ClassLoader cl = |
| ClassLoaderContext.setContextClassLoader(Thread.currentThread().getContextClassLoader(), |
| registry.getServiceDiscovery(), |
| "/META-INF/server/wink-providers", |
| "javax.ws.rs.ext.RuntimeDelegate"); |
| try { |
| super.init(); |
| } finally { |
| if (cl != null) { |
| // return previous classLoader |
| Thread.currentThread().setContextClassLoader(cl); |
| } |
| } |
| } |
| |
| @SuppressWarnings({"unchecked", "rawtypes"}) |
| @Override |
| public DeploymentConfiguration getDeploymentConfiguration() throws ClassNotFoundException, InstantiationException, |
| IllegalAccessException, IOException { |
| |
| DeploymentConfiguration config = |
| (DeploymentConfiguration)getServletContext().getAttribute(DeploymentConfiguration.class.getName()); |
| if (config != null) { |
| return config; |
| } |
| |
| // setup proper classLoader to work on OSGi environment |
| ClassLoader cl = |
| ClassLoaderContext.setContextClassLoader(Thread.currentThread().getContextClassLoader(), |
| registry.getServiceDiscovery(), |
| "javax.ws.rs.ext.RuntimeDelegate", |
| "/META-INF/wink-alternate-shortcuts.properties", |
| "/META-INF/server/wink-providers"); |
| |
| try { |
| config = super.getDeploymentConfiguration(); |
| getServletContext().setAttribute(DeploymentConfiguration.class.getName(), config); |
| } finally { |
| if (cl != null) { |
| // return previous classLoader |
| Thread.currentThread().setContextClassLoader(cl); |
| } |
| } |
| |
| // [rfeng] FIXME: This is a hack to fool Apache wink to not remove the servlet path |
| config.setFilterConfig(new FilterConfig() { |
| |
| public ServletContext getServletContext() { |
| return TuscanyRESTServlet.this.getServletContext(); |
| } |
| |
| public Enumeration getInitParameterNames() { |
| return TuscanyRESTServlet.this.getInitParameterNames(); |
| } |
| |
| public String getInitParameter(String p) { |
| return TuscanyRESTServlet.this.getInitParameter(p); |
| } |
| |
| public String getFilterName() { |
| return TuscanyRESTServlet.this.getServletName(); |
| } |
| }); |
| |
| ProvidersRegistry providers = config.getProvidersRegistry(); |
| providers.addProvider(new DataBindingJAXRSReader(registry), 0.2, true); |
| providers.addProvider(new DataBindingJAXRSWriter(registry), 0.2, true); |
| |
| config.getResponseUserHandlers().add(new TuscanyResponseHandler()); |
| |
| return config; |
| } |
| |
| private void handleWadlRequest(HttpServletRequest request, HttpServletResponse response) { |
| try { |
| org.apache.wink.common.model.wadl.Application wadlDocument = null; |
| WADLGenerator generator = new WADLGenerator(); |
| Set<Class<?>> classes = new HashSet<Class<?>>(); |
| classes.add(resourceClass); |
| wadlDocument = generator.generate(binding.getURI(), classes); |
| |
| MessageBodyWriter<org.apache.wink.common.model.wadl.Application> writer = |
| this.getDeploymentConfiguration().getProvidersRegistry(). |
| getMessageBodyWriter(org.apache.wink.common.model.wadl.Application.class, |
| org.apache.wink.common.model.wadl.Application.class, |
| annotations, |
| MediaType.APPLICATION_XML_TYPE, |
| null); |
| |
| writer.writeTo(wadlDocument, |
| org.apache.wink.common.model.wadl.Application.class, |
| org.apache.wink.common.model.wadl.Application.class, |
| annotations, |
| MediaType.APPLICATION_XML_TYPE, |
| null, response.getOutputStream()); |
| |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| |
| } |
| |
| /** |
| * TuscanyResponseHandler |
| * |
| * The response handler is shared, that's why we need to get the |
| * binding from the thread context otherwise different components |
| * might get wrong binding configuration (e.g. headers) |
| * |
| * Required to support declarative HTTP Headers |
| */ |
| class TuscanyResponseHandler implements ResponseHandler { |
| public void handleResponse(MessageContext context, HandlersChain chain) throws Throwable { |
| |
| // assert response is not committed |
| final HttpServletResponse httpResponse = context.getAttribute(HttpServletResponse.class); |
| if (httpResponse.isCommitted()) { |
| logger.log(Level.FINE, "The response is already committed. Nothing to do."); |
| return; |
| } |
| |
| RESTBinding binding = ThreadBindingContext.getBindingContext(); |
| |
| //process declarative headers |
| for(HTTPHeader header : binding.getHttpHeaders()) { |
| //treat special headers that need to be calculated |
| if(header.getName().equalsIgnoreCase("Expires")) { |
| GregorianCalendar calendar = new GregorianCalendar(); |
| calendar.setTime(new Date()); |
| |
| calendar.add(Calendar.HOUR, Integer.parseInt(header.getValue())); |
| |
| httpResponse.setHeader("Expires", HTTPCacheContext.RFC822DateFormat.format( calendar.getTime() )); |
| } else { |
| //default behaviour to pass the header value to HTTP response |
| httpResponse.setHeader(header.getName(), header.getValue()); |
| } |
| } |
| |
| chain.doChain(context); |
| } |
| |
| public void init(Properties props) { |
| |
| } |
| } |
| } |