001/* 002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * bstefanescu 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.webengine.session; 021 022import java.security.Principal; 023import java.util.HashMap; 024import java.util.Map; 025 026import javax.servlet.http.HttpServletRequest; 027import javax.servlet.http.HttpSession; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.webengine.jaxrs.context.RequestCleanupHandler; 032import org.nuxeo.ecm.webengine.jaxrs.context.RequestContext; 033 034/** 035 * Used to store user session. This object is cached in a the HTTP session Principal, subject and credentials are 036 * immutable per user session 037 * 038 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 039 */ 040// TODO: should be synchronized? concurrent access may happen for the same 041// session 042public final class UserSession extends HashMap<String, Object> { 043 044 private static final long serialVersionUID = 260562970988817064L; 045 046 protected static final Log log = LogFactory.getLog(UserSession.class); 047 048 protected Map<Class<?>, ComponentMap<?>> comps = new HashMap<Class<?>, ComponentMap<?>>(); 049 050 protected HttpServletRequest request; 051 052 protected UserSession(HttpServletRequest request) { 053 this.request = request; 054 } 055 056 public static UserSession getCurrentSession(HttpServletRequest request) { 057 String key = UserSession.class.getName(); 058 HttpSession session = request.getSession(false); 059 UserSession us = null; 060 if (session != null) { 061 us = (UserSession) session.getAttribute(key); 062 } 063 if (us == null) { 064 us = (UserSession) request.getAttribute(key); 065 } 066 if (us == null) { 067 us = new UserSession(request); 068 if (session != null) { 069 session.setAttribute(key, us); 070 } else { 071 request.setAttribute(key, us); 072 } 073 } 074 return us; 075 } 076 077 public Principal getPrincipal() { 078 return request.getUserPrincipal(); 079 } 080 081 /** 082 * Register a cleanup handler that will be invoked when HTTP request terminate. This method is not thread safe. 083 */ 084 public static void addRequestCleanupHandler(HttpServletRequest request, RequestCleanupHandler handler) { 085 RequestContext.getActiveContext(request).addRequestCleanupHandler(handler); 086 } 087 088 /** 089 * Finds an existing component. 090 * <p> 091 * The component state will not be modified before being returned as in {@link #getComponent(Class, String)}. 092 * <p> 093 * If the component was not found in that session, returns null. 094 */ 095 @SuppressWarnings("unchecked") 096 public synchronized <T extends Component> T findComponent(Class<T> type, String name) { 097 ComponentMap<T> map = (ComponentMap<T>) comps.get(type); 098 if (map == null) { 099 return null; 100 } 101 if (name == null) { 102 return map.getComponent(); 103 } else { 104 return type.cast(map.get(name)); 105 } 106 } 107 108 /** 109 * Gets a component given its class and an optional name. 110 * <p> 111 * If the component was not yet created in this session, it will be created and registered against the session. 112 */ 113 @SuppressWarnings("unchecked") 114 public synchronized <T extends Component> T getComponent(Class<T> type, String name) throws SessionException { 115 ComponentMap<T> map = (ComponentMap<T>) comps.get(type); 116 T comp; 117 if (map == null) { 118 map = new ComponentMap<T>(); 119 comps.put(type, map); 120 } else { 121 if (name == null) { 122 comp = map.getComponent(); 123 } else { 124 comp = type.cast(map.get(name)); 125 } 126 if (comp != null) { 127 return comp; 128 } 129 } 130 // component not found 131 try { 132 comp = type.newInstance(); 133 } catch (ReflectiveOperationException e) { 134 throw new SessionException("Failed to instantiate component: " + type, e); 135 } 136 comp.initialize(this, name); 137 if (name == null) { 138 map.setComponent(comp); 139 } else { 140 map.put(name, comp); 141 } 142 return type.cast(comp); 143 } 144 145 public <T extends Component> T getComponent(Class<T> type) throws SessionException { 146 return getComponent(type, null); 147 } 148 149 @SuppressWarnings("unchecked") 150 public <T extends Component> T getComponent(String typeName, String name) throws SessionException { 151 try { 152 Class<T> type = (Class<T>) Class.forName(typeName); 153 return getComponent(type, name); 154 } catch (ClassNotFoundException e) { 155 throw new SessionException("Could not find component class: " + typeName, e); 156 } 157 } 158 159 /** 160 * Gets component by ID. 161 * <p> 162 * The ID is of the form <code>type#name</code> for non-null names and <code>type</code> for null names. 163 */ 164 @SuppressWarnings("unchecked") 165 public <T extends Component> T getComponent(String id) throws SessionException { 166 int p = id.lastIndexOf('#'); 167 if (p > -1) { 168 return (T) getComponent(id.substring(0, p), id.substring(p + 1)); 169 } else { 170 return (T) getComponent(id, null); 171 } 172 } 173 174}