org.apache.wink.server.internal.servlet.RestServlet Maven / Gradle / Ivy
/*******************************************************************************
* 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.wink.server.internal.servlet;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Application;
import org.apache.wink.common.internal.i18n.Messages;
import org.apache.wink.common.internal.lifecycle.ObjectFactory;
import org.apache.wink.common.internal.properties.WinkSystemProperties;
import org.apache.wink.common.internal.utils.ClassUtils;
import org.apache.wink.server.internal.DeploymentConfiguration;
import org.apache.wink.server.internal.RequestProcessor;
import org.apache.wink.server.internal.application.ServletWinkApplication;
import org.apache.wink.server.internal.log.Providers;
import org.apache.wink.server.internal.log.Resources;
import org.apache.wink.server.internal.utils.ServletFileLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* Main servlet that is used by the runtime to handle the incoming request.
*
* The init-params are supported:
*
* - propertiesLocation - custom properties file
* - applicationConfigLocation - locations of flat application
* configuration files. Relevant only if the no
* javax.ws.rs.core.Application is provided.
* - deploymentConfiguration - custom deployment configuration class
* name. The deployment configuration must extend
* org.apache.wink.server.internal.DeploymentConfiguration.
*
*
* Important! The init-params are relevant only when working without the
* Spring support module. When working with Spring, the
* org.springframework.web.context.ContextLoaderListener must be
* configured and the whole customization should occur via the spring context.
*/
public class RestServlet extends AbstractRestServlet {
private static final long serialVersionUID = 8797036173835816706L;
private static final Logger logger =
LoggerFactory
.getLogger(RestServlet.class);
public static final String APPLICATION_INIT_PARAM = "javax.ws.rs.Application"; //$NON-NLS-1$
public static final String PROPERTIES_DEFAULT_FILE = "META-INF/wink-default.properties"; //$NON-NLS-1$
public static final String PROPERTIES_INIT_PARAM = "propertiesLocation"; //$NON-NLS-1$
public static final String APP_LOCATION_PARAM = "applicationConfigLocation"; //$NON-NLS-1$
public static final String DEPLOYMENT_CONF_PARAM = "deploymentConfiguration"; //$NON-NLS-1$
@Override
public void init() throws ServletException {
logger.trace("Initializing {} servlet", this); //$NON-NLS-1$
try {
super.init();
// try to get the request processor
// the request processor can be available if it was loaded by a
// listener
// or when working with Spring
RequestProcessor requestProcessor = getRequestProcessor();
if (requestProcessor == null) {
// create the request processor
requestProcessor = createRequestProcessor();
if (requestProcessor == null) {
throw new IllegalStateException(Messages
.getMessage("restServletRequestProcessorCouldNotBeCreated")); //$NON-NLS-1$
}
storeRequestProcessorOnServletContext(requestProcessor);
}
if (requestProcessor.getConfiguration().getServletConfig() == null) {
requestProcessor.getConfiguration().setServletConfig(getServletConfig());
}
if (requestProcessor.getConfiguration().getServletContext() == null) {
requestProcessor.getConfiguration().setServletContext(getServletContext());
}
} catch (Exception e) {
// when exception occurs during the servlet initialization
// it should be marked as unavailable
logger.error(e.getMessage(), e);
throw new UnavailableException(e.getMessage());
}
}
@Override
protected void service(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws ServletException,
IOException {
getRequestProcessor().handleRequest(httpServletRequest, httpServletResponse);
}
protected RequestProcessor createRequestProcessor() throws ClassNotFoundException,
InstantiationException, IllegalAccessException, IOException {
DeploymentConfiguration deploymentConfiguration = getDeploymentConfiguration();
// order of next two lines is important to allow Application to have
// control over priority order of Providers
Application app = getApplication();
if (app == null) {
app = getApplication(deploymentConfiguration);
}
if (logger.isTraceEnabled()) {
logger.trace("Setting application to " + app.toString());
}
deploymentConfiguration.addApplication(app, false);
if (!LoggerFactory.getLogger(Resources.class).isTraceEnabled()) {
/*
* if just debug or higher is enabled, then log only user
* applications
*/
new Resources(deploymentConfiguration.getResourceRegistry()).log();
}
if (!LoggerFactory.getLogger(Providers.class).isTraceEnabled()) {
/*
* if just debug or higher is enabled, then log only user
* applications
*/
new Providers(deploymentConfiguration.getProvidersRegistry()).log();
}
RequestProcessor requestProcessor = new RequestProcessor(deploymentConfiguration);
logger.trace("Creating request processor {} for servlet {}", requestProcessor, this); //$NON-NLS-1$
if (LoggerFactory.getLogger(Resources.class).isTraceEnabled()) {
/*
* if full trace is enabled, then log everything
*/
new Resources(deploymentConfiguration.getResourceRegistry()).log();
}
if (LoggerFactory.getLogger(Providers.class).isTraceEnabled()) {
/*
* if full trace is enabled, then log everything
*/
new Providers(deploymentConfiguration.getProvidersRegistry()).log();
}
return requestProcessor;
}
protected DeploymentConfiguration getDeploymentConfiguration() throws ClassNotFoundException,
InstantiationException, IllegalAccessException, IOException {
DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration();
deploymentConfiguration.setServletConfig(getServletConfig());
deploymentConfiguration.setServletContext(getServletContext());
deploymentConfiguration.setProperties(getProperties());
deploymentConfiguration.init();
return deploymentConfiguration;
}
/**
* order of loading and property precedence: wink-default.properties file
* referred to by propertiesLocation init param (may override and add to
* above set props) JVM system properties (only sets values for key/value
* pairs where the value is null or empty)
*/
protected Properties getProperties() throws IOException {
Properties defaultProperties = loadProperties(PROPERTIES_DEFAULT_FILE, null);
logger.trace("Default properties {} used in RestServlet {}", defaultProperties, this); //$NON-NLS-1$
String propertiesLocation = getInitParameter(PROPERTIES_INIT_PARAM);
if (propertiesLocation != null) {
if (logger.isInfoEnabled()) {
logger.info(Messages.getMessage("restServletUsePropertiesFileAtLocation", //$NON-NLS-1$
propertiesLocation,
PROPERTIES_INIT_PARAM));
}
// Load properties set on JVM. These should not override
// the ones set in the configuration file.
Properties properties = loadProperties(propertiesLocation, defaultProperties);
properties.putAll(WinkSystemProperties.loadSystemProperties(properties));
return properties;
}
logger.trace("Final properties {} used in RestServlet {}", defaultProperties, this); //$NON-NLS-1$
// Load properties set on JVM. These should not override
// the ones set in the configuration file.
defaultProperties.putAll(WinkSystemProperties.loadSystemProperties(defaultProperties));
return defaultProperties;
}
protected DeploymentConfiguration createDeploymentConfiguration()
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
String initParameter = getInitParameter(DEPLOYMENT_CONF_PARAM);
if (initParameter != null) {
if (logger.isInfoEnabled()) {
logger.info(Messages.getMessage("restServletUseDeploymentConfigurationParam", //$NON-NLS-1$
initParameter,
DEPLOYMENT_CONF_PARAM));
}
// use ClassUtils.loadClass instead of Class.forName so we have
// classloader visibility into the Web module in J2EE environments
Class> confClass = ClassUtils.loadClass(initParameter);
return (DeploymentConfiguration)confClass.newInstance();
}
return new DeploymentConfiguration();
}
@SuppressWarnings("unchecked")
protected Application getApplication(DeploymentConfiguration configuration)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class extends Application> appClass = null;
String initParameter = getInitParameter(APPLICATION_INIT_PARAM);
if (initParameter != null) {
if (logger.isInfoEnabled()) {
logger.info(Messages.getMessage("restServletJAXRSApplicationInitParam", //$NON-NLS-1$
initParameter,
APPLICATION_INIT_PARAM));
}
// use ClassUtils.loadClass instead of Class.forName so we have
// classloader visibility into the Web module in J2EE environments
appClass = (Class extends Application>)ClassUtils.loadClass(initParameter);
// let the lifecycle manager create the instance and process fields
// for injection
ObjectFactory of = configuration.getOfFactoryRegistry().getObjectFactory(appClass);
configuration.addApplicationObjectFactory(of);
return (Application)of.getInstance(null);
}
String appLocationParameter = getInitParameter(APP_LOCATION_PARAM);
if (appLocationParameter == null) {
if (logger.isWarnEnabled()) {
logger.warn(Messages.getMessage("propertyNotDefined", APP_LOCATION_PARAM)); //$NON-NLS-1$
}
}
if (logger.isInfoEnabled()) {
logger.info(Messages.getMessage("restServletWinkApplicationInitParam", //$NON-NLS-1$
appLocationParameter,
APP_LOCATION_PARAM));
}
return new ServletWinkApplication(getServletContext(), appLocationParameter);
}
protected Application getApplication() throws ClassNotFoundException, InstantiationException,
IllegalAccessException {
/*
* this is a legacy call. in the end, should call
* getApplication(DeploymentConfiguration) by default but this is left
* as a call for legacy
*/
return null;
}
/**
* loadProperties will try to load the properties from the resource,
* overriding existing properties in defaultProperties, and adding new ones,
* and return the result
*
* @param resourceName
* @param defaultProperties
* @return
* @throws IOException
*/
private Properties loadProperties(String resourceName, Properties defaultProperties)
throws IOException {
Properties properties =
defaultProperties == null ? new Properties() : new Properties(defaultProperties);
InputStream is = null;
try {
is = ServletFileLoader.loadFileAsStream(getServletContext(), resourceName);
properties.load(is);
} catch (FileNotFoundException e) {
logger.debug("FileNotFoundException for {}", resourceName); //$NON-NLS-1$
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
if (logger.isWarnEnabled()) {
logger
.warn(Messages.getMessage("exceptionClosingFile") + ": " + resourceName, e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
return properties;
}
@Override
public void destroy() {
getRequestProcessor().getConfiguration().getProvidersRegistry().removeAllProviders();
getRequestProcessor().getConfiguration().getResourceRegistry().removeAllResources();
for (ObjectFactory> of : getRequestProcessor().getConfiguration()
.getApplicationObjectFactories()) {
of.releaseAll(null);
}
/*
* Be sure to call super.destroy()
*/
super.destroy();
}
}