
org.kohsuke.stapler.WebApp Maven / Gradle / Ivy
Show all versions of stapler-core Show documentation
/*
* Copyright (c) 2004-2010, Kohsuke Kawaguchi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.kohsuke.stapler;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.bind.BoundObjectTable;
import javax.servlet.ServletContext;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.Hashtable;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Object scoped to the entire webapp. Mostly used for configuring behavior of Stapler.
*
*
* In contrast, {@link Stapler} is a servlet, so there can be multiple instances per webapp.
*
* @author Kohsuke Kawaguchi
* @see WebApp#get(ServletContext)
* @see WebApp#getCurrent()
* @see Stapler#getWebApp()
*/
public class WebApp {
/**
* Obtains the {@link WebApp} associated with the given {@link ServletContext}.
*/
public static WebApp get(ServletContext context) {
Object o = context.getAttribute(WebApp.class.getName());
if(o==null) {
synchronized (WebApp.class) {
o = context.getAttribute(WebApp.class.getName());
if(o==null) {
o = new WebApp(context);
context.setAttribute(WebApp.class.getName(),o);
}
}
}
return (WebApp)o;
}
/**
* {@link ServletContext} for this webapp.
*/
public final ServletContext context;
/**
* Duck-type wrappers for the given class.
*/
public final Map wrappers = new HashMap();
/**
* MIME type -> encoding map that determines how static contents in the war file is served.
*/
public final Map defaultEncodingForStaticResources = new HashMap();
/**
* Activated facets.
*
* TODO: is this really mutable?
*/
public final List facets = new Vector();
/**
* MIME type mapping from extensions (like "txt" or "jpg") to MIME types ("foo/bar").
*
* This overrides whatever mappings given in the servlet as far as stapler is concerned.
* This is case insensitive, and should be normalized to lower case.
*/
public final Map mimeTypes = new Hashtable();
private volatile ClassLoader classLoader;
/**
* All {@link MetaClass}es.
*
* Avoids class leaks by {@link WeakHashMap}.
*/
private final Map classMap = new WeakHashMap();
/**
* Handles objects that are exported.
*/
public final BoundObjectTable boundObjectTable = new BoundObjectTable();
private final CopyOnWriteArrayList responseRenderers = new CopyOnWriteArrayList();
private CrumbIssuer crumbIssuer = CrumbIssuer.DEFAULT;
public WebApp(ServletContext context) {
this.context = context;
// TODO: allow classloader to be given?
facets.addAll(Facet.discoverExtensions(Facet.class, Thread.currentThread().getContextClassLoader(), getClass().getClassLoader()));
responseRenderers.add(new HttpResponseRenderer.Default());
}
/**
* Returns the 'app' object, which is the user-specified object that
* sits at the root of the URL hierarchy and handles the request to '/'.
*/
public Object getApp() {
return context.getAttribute("app");
}
public void setApp(Object app) {
context.setAttribute("app",app);
}
public CrumbIssuer getCrumbIssuer() {
return crumbIssuer;
}
public void setCrumbIssuer(CrumbIssuer crumbIssuer) {
this.crumbIssuer = crumbIssuer;
}
public CopyOnWriteArrayList getResponseRenderers() {
return responseRenderers;
}
public ClassLoader getClassLoader() {
ClassLoader cl = classLoader;
if(cl==null)
cl = Thread.currentThread().getContextClassLoader();
if(cl==null)
cl = Stapler.class.getClassLoader();
return cl;
}
/**
* If the facet of the given type exists, return it. Otherwise null.
*/
public T getFacet(Class type) {
for (Facet f : facets)
if(type==f.getClass())
return type.cast(f);
return null;
}
/**
* Sets the classloader used by {@link StaplerRequest#bindJSON(Class, JSONObject)} and its sibling methods.
*/
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public MetaClass getMetaClass(Class c) {
if(c==null) return null;
synchronized(classMap) {
MetaClass mc = classMap.get(c);
if(mc==null) {
mc = new MetaClass(this,c);
classMap.put(c,mc);
}
return mc;
}
}
/**
* Convenience maintenance method to clear all the cached scripts for the given tearoff type.
*
*
* This is useful when you want to have the scripts reloaded into the live system without
* the performance penalty of {@link MetaClass#NO_CACHE}.
*
* @see MetaClass#NO_CACHE
*/
public void clearScripts(Class extends AbstractTearOff> clazz) {
synchronized (classMap) {
for (MetaClass v : classMap.values()) {
AbstractTearOff t = v.getTearOff(clazz);
if (t!=null)
t.clearScripts();
}
}
}
/**
* Gets the current {@link WebApp} that the calling thread is associated with.
*/
public static WebApp getCurrent() {
return Stapler.getCurrent().getWebApp();
}
}