/*
* (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* This library 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.
*
* Contributors:
* bstefanescu
*
* $Id$
*/
package org.nuxeo.ecm.webengine.session;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.webengine.jaxrs.context.RequestCleanupHandler;
import org.nuxeo.ecm.webengine.jaxrs.context.RequestContext;
import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory;
/**
* Used to store user session. This object is cached in a the HTTP session
* Principal, subject and credentials are immutable per user session
*
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*
*/
// TODO: should be synchronized? concurrent access may happen for the same
// session
public final class UserSession extends HashMap<String, Object> {
private static final long serialVersionUID = 260562970988817064L;
protected static final Log log = LogFactory.getLog(UserSession.class);
protected Map<Class<?>, ComponentMap<?>> comps = new HashMap<Class<?>, ComponentMap<?>>();
protected HttpServletRequest request;
protected UserSession(HttpServletRequest request) {
this.request = request;
}
public static UserSession getCurrentSession(HttpServletRequest request) {
String key = UserSession.class.getName();
HttpSession session = request.getSession(false);
UserSession us = null;
if (session != null) {
us = (UserSession) session.getAttribute(key);
}
if (us == null) {
us = (UserSession) request.getAttribute(key);
}
if (us == null) {
us = new UserSession(request);
if (session != null) {
session.setAttribute(key, us);
} else {
request.setAttribute(key, us);
}
}
return us;
}
/**
* Gets a core session.
* <p>
* If it does not already exist, it will be opened against the given
* repository.
*
* @param repoName
* @return the core session
*
* @deprecated use {@link SessionFactory#getSession(HttpServletRequest, String)}
*/
public CoreSession getCoreSession(String repoName) {
try {
return SessionFactory.getSession(request, repoName);
} catch (Exception e) {
log.error(
"Failed to open core session for repository: " + repoName,
e);
return null;
}
}
/**
* Gets a core session.
* <p>
* If not already opened, opens a new core session against the default
* repository.
*
* @deprecated use {@link SessionFactory#getSession(HttpServletRequest)}
*/
public CoreSession getCoreSession() {
try {
return SessionFactory.getSession(request);
} catch (Exception e) {
log.error(
"Failed to open core session for default repository",
e);
return null;
}
}
public Principal getPrincipal() {
return request.getUserPrincipal();
}
/**
* Register a cleanup handler that will be invoked when HTTP request
* terminate. This method is not thread safe.
*/
public static void addRequestCleanupHandler(HttpServletRequest request,
RequestCleanupHandler handler) {
RequestContext.getActiveContext(request).addRequestCleanupHandler(handler);
}
/**
* Finds an existing component.
* <p>
* The component state will not be modified before being returned as in
* {@link #getComponent(Class, String)}.
* <p>
* If the component was not found in that session, returns null.
*/
@SuppressWarnings("unchecked")
public synchronized <T extends Component> T findComponent(Class<T> type,
String name) {
ComponentMap<T> map = (ComponentMap<T>) comps.get(type);
if (map == null) {
return null;
}
if (name == null) {
return map.getComponent();
} else {
return type.cast(map.get(name));
}
}
/**
* Gets a component given its class and an optional name.
* <p>
* If the component was not yet created in this session, it will be created
* and registered against the session.
*/
@SuppressWarnings("unchecked")
public synchronized <T extends Component> T getComponent(Class<T> type,
String name) throws SessionException {
ComponentMap<T> map = (ComponentMap<T>) comps.get(type);
T comp;
if (map == null) {
map = new ComponentMap<T>();
comps.put(type, map);
} else {
if (name == null) {
comp = map.getComponent();
} else {
comp = type.cast(map.get(name));
}
if (comp != null) {
return comp;
}
}
// component not found
try {
comp = type.newInstance();
} catch (Exception e) {
throw new SessionException("Failed to instantiate component: "
+ type, e);
}
comp.initialize(this, name);
if (name == null) {
map.setComponent(comp);
} else {
map.put(name, comp);
}
return type.cast(comp);
}
public <T extends Component> T getComponent(Class<T> type)
throws SessionException {
return getComponent(type, null);
}
@SuppressWarnings("unchecked")
public <T extends Component> T getComponent(String typeName, String name)
throws SessionException {
try {
Class<T> type = (Class<T>) Class.forName(typeName);
return getComponent(type, name);
} catch (ClassNotFoundException e) {
throw new SessionException("Could not find component class: "
+ typeName, e);
}
}
/**
* Gets component by ID.
* <p>
* The ID is of the form <code>type#name</code> for non-null names and
* <code>type</code> for null names.
*/
@SuppressWarnings("unchecked")
public <T extends Component> T getComponent(String id)
throws SessionException {
int p = id.lastIndexOf('#');
if (p > -1) {
return (T) getComponent(id.substring(0, p), id.substring(p + 1));
} else {
return (T) getComponent(id, null);
}
}
}