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