All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bimserver.servlets.GenericWebServiceServlet Maven / Gradle / Ivy

There is a newer version: 1.5.9
Show newest version
package org.bimserver.servlets;

/******************************************************************************
 * Copyright (C) 2009-2016  BIMserver.org
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see {@literal}.
 *****************************************************************************/

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBException;

import org.apache.cxf.Bus;
import org.apache.cxf.BusException;
import org.apache.cxf.BusFactory;
import org.apache.cxf.databinding.DataBinding;
import org.apache.cxf.headers.HeaderManager;
import org.apache.cxf.headers.HeaderProcessor;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.InterceptorProvider;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.resource.ResourceManager;
import org.apache.cxf.transport.DestinationFactory;
import org.apache.cxf.transport.DestinationFactoryManager;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.apache.cxf.transport.http.DestinationRegistry;
import org.apache.cxf.transport.http.HTTPTransportFactory;
import org.apache.cxf.transport.servlet.ServletContextResourceResolver;
import org.apache.cxf.transport.servlet.ServletController;
import org.apache.cxf.transport.servlet.servicelist.ServiceListGeneratorServlet;
import org.apache.cxf.wsdl.WSDLConstants;
import org.bimserver.BimServer;
import org.bimserver.shared.Token;
import org.bimserver.shared.interfaces.PublicInterface;
import org.bimserver.webservices.CustomInvoker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GenericWebServiceServlet extends SubServlet {

	public GenericWebServiceServlet(BimServer bimServer, ServletContext servletContext) {
		super(bimServer, servletContext);
	}

	private static final Logger LOGGER = LoggerFactory.getLogger(GenericWebServiceServlet.class);
	private String bindingId;

	public void setBindingId(String bindingId) {
		this.bindingId = bindingId;
	}

	private static final String REDIRECTS_PARAMETER = "redirects-list";
	private static final String REDIRECT_SERVLET_NAME_PARAMETER = "redirect-servlet-name";
	private static final String REDIRECT_SERVLET_PATH_PARAMETER = "redirect-servlet-path";
	private static final String REDIRECT_QUERY_CHECK_PARAMETER = "redirect-query-check";

	private static final Map STATIC_CONTENT_TYPES;

	static {
		STATIC_CONTENT_TYPES = new HashMap();
		STATIC_CONTENT_TYPES.put("html", "text/html");
		STATIC_CONTENT_TYPES.put("txt", "text/plain");
		STATIC_CONTENT_TYPES.put("css", "text/css");
		STATIC_CONTENT_TYPES.put("pdf", "application/pdf");
		// TODO : add more types if needed
	}

	private List redirectList;
	private String dispatcherServletPath;
	private String dispatcherServletName;
	private boolean redirectQueryCheck;
	private DestinationRegistry destinationRegistry;
	private Bus bus;
	private ServletController controller;
	private ClassLoader loader;

	public void init(ServletConfig sc) throws ServletException {
		// Setting this property because otherwise a file named
		// "wsdl.properties" will be read from the JRE, which is not possible
		// due to restrictive permissions
		System.setProperty("javax.wsdl.factory.WSDLFactory", "com.ibm.wsdl.factory.WSDLFactoryImpl");

		if (this.bus == null) {
			loadBus(sc);
		}
		loader = bus.getExtension(ClassLoader.class);
		ResourceManager resourceManager = bus.getExtension(ResourceManager.class);
		resourceManager.addResourceResolver(new ServletContextResourceResolver(sc.getServletContext()));

		if (destinationRegistry == null) {
			this.destinationRegistry = getDestinationRegistryFromBus(this.bus);
		}
		this.controller = createServletController(sc);

		redirectList = parseListSequence(sc.getInitParameter(REDIRECTS_PARAMETER));
		redirectQueryCheck = Boolean.valueOf(sc.getInitParameter(REDIRECT_QUERY_CHECK_PARAMETER));
		dispatcherServletName = sc.getInitParameter(REDIRECT_SERVLET_NAME_PARAMETER);
		dispatcherServletPath = sc.getInitParameter(REDIRECT_SERVLET_PATH_PARAMETER);
	}

	private static DestinationRegistry getDestinationRegistryFromBus(Bus bus) {
		DestinationFactoryManager dfm = bus.getExtension(DestinationFactoryManager.class);
		try {
			DestinationFactory df = dfm.getDestinationFactory("http://cxf.apache.org/transports/http/configuration");
			if (df instanceof HTTPTransportFactory) {
				HTTPTransportFactory transportFactory = (HTTPTransportFactory) df;
				return transportFactory.getRegistry();
			}
		} catch (BusException e) {
			// why are we throwing a busexception if the DF isn't found?
		}
		return null;
	}

	private ServletController createServletController(ServletConfig servletConfig) {
		HttpServlet serviceListGeneratorServlet = new ServiceListGeneratorServlet(destinationRegistry, bus);
		ServletController newController = new ServletController(destinationRegistry, servletConfig, serviceListGeneratorServlet);
		return newController;
	}

	public Bus getBus() {
		return bus;
	}

	public void setBus(Bus bus) {
		this.bus = bus;
	}

	protected void invoke(HttpServletRequest request, HttpServletResponse response) throws ServletException {
		ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
		try {
			if (loader != null) {
				Thread.currentThread().setContextClassLoader(loader);
			}
			BusFactory.setThreadDefaultBus(bus);
			controller.invoke(request, response);
		} catch (ClassCastException e) {
			// Since updating to CXF 3.1.3 we are getting java.lang.ClassCastException: org.apache.cxf.message.MessageImpl cannot be cast to org.apache.cxf.binding.soap.SoapMessage
		} finally {
			BusFactory.setThreadDefaultBus(null);
			Thread.currentThread().setContextClassLoader(origLoader);
		}
	}

	public void destroy() {
		for (String path : destinationRegistry.getDestinationsPaths()) {
			// clean up the destination in case the destination itself can no
			// longer access the registry later
			AbstractHTTPDestination dest = destinationRegistry.getDestinationForPath(path);
			synchronized (dest) {
				destinationRegistry.removeDestination(path);
				dest.releaseRegistry();
			}
		}
		destinationRegistry = null;
		destroyBus();
	}

	public void destroyBus() {
		bus.shutdown(true);
	}

	private static List parseListSequence(String values) {
		if (values != null) {
			List list = new LinkedList();
			String[] pathValues = values.split(" ");
			for (String value : pathValues) {
				String theValue = value.trim();
				if (theValue.length() > 0) {
					list.add(theValue);
				}
			}
			return list;
		} else {
			return null;
		}
	}

	@Override
	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		invoke(request, response);
	}

	protected void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
		if ((dispatcherServletPath != null || dispatcherServletName != null) && (redirectList != null && matchPath(redirectList, request) || redirectList == null)) {
			// if no redirectList is provided then this servlet is redirecting
			// only
			redirect(request, response, request.getPathInfo());
			return;
		}

		invoke(request, response);
	}

	private boolean matchPath(List values, HttpServletRequest request) {
		String path = request.getPathInfo();
		if (redirectQueryCheck) {
			String queryString = request.getQueryString();
			if (queryString != null && queryString.length() > 0) {
				path += "?" + queryString;
			}
		}
		for (String value : values) {
			if (path.matches(value)) {
				return true;
			}
		}
		return false;
	}

	protected void serveStaticContent(HttpServletRequest request, HttpServletResponse response, String pathInfo) throws ServletException {
		InputStream is = super.getServletContext().getResourceAsStream(pathInfo);
		if (is == null) {
			throw new ServletException("Static resource " + pathInfo + " is not available");
		}
		try {
			int ind = pathInfo.lastIndexOf(".");
			if (ind != -1 && ind < pathInfo.length()) {
				String type = STATIC_CONTENT_TYPES.get(pathInfo.substring(ind + 1));
				if (type != null) {
					response.setContentType(type);
				}
			}

			ServletOutputStream os = response.getOutputStream();
			IOUtils.copy(is, os);
			os.flush();
		} catch (IOException ex) {
			throw new ServletException("Static resource " + pathInfo + " can not be written to the output stream");
		}
	}

	protected void redirect(HttpServletRequest request, HttpServletResponse response, String pathInfo) throws ServletException {

		String theServletPath = dispatcherServletPath == null ? "/" : dispatcherServletPath;

		ServletContext sc = super.getServletContext();
		RequestDispatcher rd = dispatcherServletName != null ? sc.getNamedDispatcher(dispatcherServletName) : sc.getRequestDispatcher(theServletPath + pathInfo);
		if (rd == null) {
			throw new ServletException("No RequestDispatcher can be created for path " + pathInfo);
		}
		try {
			HttpServletRequestFilter servletRequest = new HttpServletRequestFilter(request, pathInfo, theServletPath);
			rd.forward(servletRequest, response);
		} catch (Throwable ex) {
			throw new ServletException("RequestDispatcher for path " + pathInfo + " has failed");
		}
	}

	private static class HttpServletRequestFilter extends HttpServletRequestWrapper {

		private String pathInfo;
		private String servletPath;

		public HttpServletRequestFilter(HttpServletRequest request, String pathInfo, String servletPath) {
			super(request);
			this.pathInfo = pathInfo;
			this.servletPath = servletPath;
		}

		@Override
		public String getServletPath() {
			return servletPath;
		}

		@Override
		public String getPathInfo() {
			return pathInfo;
		}

		@Override
		public String getRequestURI() {
			String contextPath = getContextPath();
			if ("/".equals(contextPath)) {
				contextPath = "";
			}
			return contextPath + servletPath + pathInfo;
		}

		@Override
		public String getParameter(String name) {
			if (AbstractHTTPDestination.SERVICE_REDIRECTION.equals(name)) {
				return "true";
			}
			return super.getParameter(name);
		}
	}

	public void loadBus(ServletConfig servletConfig) {
		this.bus = BusFactory.newInstance().createBus();
		Bus bus = getBus();
		HeaderManager headerManager = bus.getExtension(HeaderManager.class);
		headerManager.registerHeaderProcessor(new HeaderProcessor() {
			@Override
			public String getNamespace() {
				return "uri:org.bimserver.shared";
			}

			@Override
			public InterceptorProvider getInterceptorProvider() {
				return null;
			}

			@Override
			public DataBinding getDataBinding() {
				try {
					return new JAXBDataBinding(Token.class);
				} catch (JAXBException e) {
					LOGGER.error("", e);
				}
				return null;
			}
		});
		BusFactory.setDefaultBus(bus);

		for (Class clazz : getBimServer().getServicesMap().getInterfaceClasses()) {
			JaxWsServerFactoryBean serverFactoryBean = new JaxWsServerFactoryBean();
			Map properties = new HashMap();
			properties.put("mtom-enabled", Boolean.TRUE);
			serverFactoryBean.setBindingId(bindingId);
			serverFactoryBean.setProperties(properties);
			serverFactoryBean.setServiceClass(clazz);
			serverFactoryBean.getOutFaultInterceptors().add(new StatusCodeModifyingFaultInterceptor());
			serverFactoryBean.setInvoker(new CustomInvoker(getBimServer().getServiceFactory(), clazz));
			serverFactoryBean.setAddress((bindingId == WSDLConstants.NS_SOAP11 ? "/soap11/" : "/soap12/") + clazz.getSimpleName()); // equals check allowed, just keep using the constant
			serverFactoryBean.setTransportId("http://schemas.xmlsoap.org/soap/http");
			serverFactoryBean.create();
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy