001package org.kohsuke.stapler;
002
003import javax.servlet.ServletContext;
004import javax.servlet.http.HttpServletRequest;
005import javax.servlet.http.HttpSession;
006import java.util.UUID;
007
008/**
009 * Type-safe attribute accessor.
010 *
011 * <p>
012 * Servlet API has a bag of stuff in several scopes (such as request, session, ...)
013 * but the API is not type-safe.
014 *
015 * This object provides a convenient type-safe access to to such bags, as well
016 * as providing uniform API regardless of the actual scope.
017 *
018 * <p>
019 * Each instance of {@link AttributeKey} gets an unique attribute name, which means
020 * in the most typical case, these instances should be used as a singleton.
021 *
022 * @author Kohsuke Kawaguchi
023 */
024public abstract class AttributeKey<T> {
025    protected final String name;
026
027    public AttributeKey() {
028        name = UUID.randomUUID().toString();
029    }
030
031    public AttributeKey(String name) {
032        this.name = name;
033    }
034
035    public abstract T get(HttpServletRequest req);
036
037    public abstract void set(HttpServletRequest req, T value);
038
039    public abstract void remove(HttpServletRequest req);
040
041    public final T get() {
042        return get(Stapler.getCurrentRequest());
043    }
044
045    public final void set(T value) {
046        set(Stapler.getCurrentRequest(),value);
047    }
048
049    public final void remove() {
050        remove(Stapler.getCurrentRequest());
051    }
052
053    /**
054     * Creates a new request-scoped {@link AttributeKey}.
055     */
056    public static <T> AttributeKey<T> requestScoped() {
057        return new AttributeKey<T>() {
058            public T get(HttpServletRequest req) {
059                return (T)req.getAttribute(name);
060            }
061
062            public void set(HttpServletRequest req, T value) {
063                req.setAttribute(name, value);
064            }
065
066            public void remove(HttpServletRequest req) {
067                req.removeAttribute(name);
068            }
069        };
070    }
071
072    /**
073     * Creates a new session-scoped {@link AttributeKey}.
074     */
075    public static <T> AttributeKey<T> sessionScoped() {
076        return new AttributeKey<T>() {
077            public T get(HttpServletRequest req) {
078                HttpSession s = req.getSession(false);
079                if (s==null)    return null;
080                return (T)s.getAttribute(name);
081            }
082
083            public void set(HttpServletRequest req, T value) {
084                req.getSession().setAttribute(name, value);
085            }
086
087            public void remove(HttpServletRequest req) {
088                HttpSession s = req.getSession(false);
089                if (s!=null)
090                    s.removeAttribute(name);
091            }
092        };
093    }
094
095    /**
096     * Creates a new {@link ServletContext}-scoped {@link AttributeKey}.
097     */
098    public static <T> AttributeKey<T> appScoped() {
099        return new AttributeKey<T>() {
100            public T get(HttpServletRequest req) {
101                return (T) getContext(req).getAttribute(name);
102            }
103
104            public void set(HttpServletRequest req, T value) {
105                getContext(req).setAttribute(name, value);
106            }
107
108            public void remove(HttpServletRequest req) {
109                getContext(req).removeAttribute(name);
110            }
111
112            private ServletContext getContext(HttpServletRequest req) {
113                return ((StaplerRequest)req).getServletContext();
114            }
115        };
116    }
117}