/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.rest.internal;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.ext.servlet.ServletUtils;
import org.restlet.routing.Filter;
import org.xwiki.component.manager.ComponentLifecycleException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.context.Execution;
import org.xwiki.context.ExecutionContext;
import org.xwiki.rest.XWikiRestComponent;
/**
* <p>
* The Setup cleanup filter is used to populate the Restlet context with relevant variables that are used by JAX-RS
* resources. It is also used to release the JAX-RS resources that are instantiated by using the component manager, in
* order to avoid memory leaks.
* </p>
*
* @version $Id: 6b47763940f9aa697f2a55132998eb04db99e745 $
*/
public class XWikiSetupCleanupFilter extends Filter
{
@Override
protected int beforeHandle(Request request, Response response)
{
/*
* We put the original HTTP request in context attributes because this is needed for reading
* application/www-form-urlencoded POSTs. In fact servlet filters might call getParameters() which invalidates
* the request body, making Restlet unable to process it. In this case we need to use getParameters as well
* instead of reading form data from the input stream, and in order to do this we need the original HTTP request
* object. This is basically a hack that should be removed as soon as the Restlet JAX-RS extension will support
* the injection of the request object via the @Context annotation.
*/
getContext().getAttributes().put(Constants.HTTP_REQUEST, getHttpRequest(request));
return Filter.CONTINUE;
}
@Override
protected void afterHandle(Request request, Response response)
{
// Release all the JAX-RS resources that are implemented as components with per-lookup policy and that have been
// instantiated during this request.
ComponentManager componentManager =
(ComponentManager) getApplication().getContext().getAttributes().get(Constants.XWIKI_COMPONENT_MANAGER);
for (XWikiRestComponent component : getReleasableComponents(componentManager)) {
try {
componentManager.release(component);
} catch (ComponentLifecycleException e) {
getLogger().log(Level.WARNING, "Unable to release component [{0}]. ({1})",
new Object[] {component.getClass().getName(), e.getMessage()});
}
}
/* Avoid that empty entities make the engine forward the response creation to the XWiki servlet. */
if (response.getEntity() != null) {
if (!response.getEntity().isAvailable()) {
response.setEntity(null);
}
}
}
/**
* @param componentManager the component manager
* @return the list of JAX-RS resources that are implemented as components with per-lookup policy and that have been
* instantiated during this request
*/
private List<XWikiRestComponent> getReleasableComponents(ComponentManager componentManager)
{
try {
ExecutionContext executionContext = componentManager.<Execution> getInstance(Execution.class).getContext();
@SuppressWarnings("unchecked")
List<XWikiRestComponent> releasableComponents =
(List<XWikiRestComponent>) executionContext.getProperty(Constants.RELEASABLE_COMPONENT_REFERENCES);
return releasableComponents != null ? releasableComponents : Collections.<XWikiRestComponent> emptyList();
} catch (Exception e) {
getLogger().log(Level.WARNING, "Failed to retrieve the list of releasable components.", e);
return Collections.emptyList();
}
}
/**
* <p>
* Retrieves the original servlet request.
* </p>
*
* @param req The Restlet request to handle.
* @return httpServletRequest The original HTTP servlet request.
*/
protected static HttpServletRequest getHttpRequest(Request req)
{
return ServletUtils.getRequest(req);
}
}