350 lines
11 KiB
Java
Executable File
350 lines
11 KiB
Java
Executable File
/*
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public License
|
|
as published by the Free Software Foundation; either version 2.1 of
|
|
the License, or (at your option) any later version.
|
|
|
|
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.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
package com.arsdigita.london.userprefs;
|
|
|
|
import com.arsdigita.caching.CacheTable;
|
|
import com.arsdigita.domain.DataObjectNotFoundException;
|
|
import com.arsdigita.domain.DomainCollection;
|
|
import com.arsdigita.kernel.Kernel;
|
|
import com.arsdigita.kernel.User;
|
|
import com.arsdigita.persistence.OID;
|
|
import com.arsdigita.util.UncheckedWrapperException;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.SecureRandom;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.Random;
|
|
|
|
import javax.servlet.http.Cookie;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import javax.servlet.http.HttpSession;
|
|
|
|
import org.apache.log4j.Logger;
|
|
|
|
/**
|
|
* <p>User Preferences. An object for storing user preferences in the current
|
|
* session.</p>
|
|
*
|
|
* <p>This object is an abstraction of PersistentUserPreferences, which is a
|
|
* <code>DomainObject</code> stored in the database. <code>UserPrefs</code> is
|
|
* cached in the java Session and will not touch the database on every
|
|
* request.</p>
|
|
*
|
|
* <p>If the current user is not logged in, <code>UserPrefs</code> will use its
|
|
* own cookie. This means that preferences can be saved even when a user doesn't
|
|
* log in.</p>
|
|
*
|
|
* @author Matthew Booth <mbooth@redhat.com>
|
|
*/
|
|
|
|
public class UserPrefs {
|
|
private static final Logger s_log = Logger.getLogger( UserPrefs.class );
|
|
|
|
private static final String COOKIE = "WAF_USER_PREFS";
|
|
static final String SESSION_ATTRIBUTE = UserPrefs.class.getName();
|
|
|
|
private OID m_user = null;
|
|
private OID m_persistentPrefs = null;
|
|
private Long m_cookie = null;
|
|
|
|
private HashMap m_prefs = new HashMap();
|
|
|
|
private static final CacheTable s_prefsCache =
|
|
new CacheTable( "user_preferences" );
|
|
|
|
private UserPrefs() {};
|
|
|
|
private UserPrefs( PersistentUserPrefs persistentPrefs ) {
|
|
init( persistentPrefs );
|
|
}
|
|
|
|
private void init( PersistentUserPrefs persistentPrefs ) {
|
|
m_persistentPrefs = persistentPrefs.getOID();
|
|
m_cookie = persistentPrefs.getCookie();
|
|
m_user = persistentPrefs.getUser() == null ?
|
|
null : persistentPrefs.getUser().getOID();
|
|
|
|
DomainCollection prefs = persistentPrefs.getAllValues();
|
|
while( prefs.next() ) {
|
|
Pref pref = (Pref) prefs.getDomainObject();
|
|
m_prefs.put( pref.getKey(), pref.getValue() );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>Retrieve a UserPrefs object for the current request.</p>
|
|
*
|
|
* <p>In order, this will:
|
|
*
|
|
* <ul>
|
|
* <li>Look for prefs in the http session</li>
|
|
* <li>Look for prefs for the currently logged in user</li>
|
|
* <li>Look for prefs for a supplied cookie (from DB)</li>
|
|
* <li>Create a new preferences object</li>
|
|
* </ul>
|
|
* </p>
|
|
*/
|
|
public static UserPrefs retrieve( HttpServletRequest req,
|
|
HttpServletResponse res ) {
|
|
HttpSession session = req.getSession();
|
|
|
|
// Yes, this seems like a silly use of an HttpSession, but they really
|
|
// are broken in almost every useful way.
|
|
UserPrefs prefs = (UserPrefs) s_prefsCache.get( session.getId() );
|
|
|
|
if( null != prefs ) {
|
|
if( s_log.isDebugEnabled() ) {
|
|
s_log.debug( "Retrieved user prefs for session " +
|
|
session.getId() );
|
|
}
|
|
return prefs;
|
|
}
|
|
|
|
PersistentUserPrefs persistentPrefs = retrievePersistent( req, res );
|
|
if( null != persistentPrefs ) {
|
|
prefs = new UserPrefs( persistentPrefs );
|
|
} else {
|
|
prefs = new UserPrefs();
|
|
|
|
User user = (User) Kernel.getContext().getParty();
|
|
if( null != user ) {
|
|
prefs.m_user = user.getOID();
|
|
} else {
|
|
Long cookie;
|
|
try {
|
|
SecureRandom random = SecureRandom.getInstance( "SHA1PRNG" );
|
|
cookie = new Long( random.nextLong() );
|
|
} catch( NoSuchAlgorithmException ex ) {
|
|
s_log.warn( "Unable to get SecureRandom for SHA1PRNG. " +
|
|
"Falling back to insecure random generator." );
|
|
cookie = new Long( new Random().nextLong() );
|
|
}
|
|
|
|
prefs.m_cookie = cookie;
|
|
setCookie( res, cookie.toString() );
|
|
}
|
|
|
|
s_log.debug( "Created new prefs" );
|
|
}
|
|
|
|
s_prefsCache.put( session.getId(), prefs );
|
|
return prefs;
|
|
}
|
|
|
|
private static PersistentUserPrefs retrievePersistent
|
|
( HttpServletRequest req, HttpServletResponse res )
|
|
{
|
|
PersistentUserPrefs persistentPrefs = null;
|
|
|
|
User user = (User) Kernel.getContext().getParty();
|
|
if( null != user ) {
|
|
persistentPrefs = PersistentUserPrefs.retrieveForUser( user );
|
|
}
|
|
|
|
if( null != persistentPrefs ) {
|
|
s_log.debug( "Got prefs for user" );
|
|
return persistentPrefs;
|
|
}
|
|
|
|
Long cookie = getCookie( req );
|
|
if( null != cookie ) {
|
|
persistentPrefs = PersistentUserPrefs.retrieveForCookie( cookie );
|
|
|
|
// Remove a bogus cookie
|
|
if( null == persistentPrefs ) {
|
|
removeCookie( res );
|
|
}
|
|
}
|
|
|
|
if( null != persistentPrefs ) {
|
|
s_log.debug( "Got prefs for cookie" );
|
|
return persistentPrefs;
|
|
}
|
|
|
|
s_log.debug( "No existing prefs" );
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the value of a user preference entry.
|
|
*
|
|
* @param key The identifier of the preference to be retrieved
|
|
* @return The value of the requsted preference, or null if it is not set
|
|
*/
|
|
public String get( String key ) {
|
|
return (String) m_prefs.get( key );
|
|
}
|
|
|
|
/**
|
|
* Retrieve all stored user preferences.
|
|
*
|
|
* @return An Iterator of Map.Entry objects containing key/value pairs for
|
|
* the user's current preferences
|
|
*/
|
|
public Iterator getAll() {
|
|
return m_prefs.entrySet().iterator();
|
|
}
|
|
|
|
/**
|
|
* Set a preference.
|
|
*
|
|
* @param key The identifier of the preference to be stored
|
|
* @param value The value of the preference to be stored
|
|
*/
|
|
public void set( String key, String value,
|
|
HttpServletRequest req, HttpServletResponse res ) {
|
|
m_prefs.put( key, value );
|
|
|
|
PersistentUserPrefs prefs = getPersistent();
|
|
if( null == prefs ) prefs = createPersistent( req, res );
|
|
prefs.setValue( key, value );
|
|
}
|
|
|
|
/**
|
|
* Remove a user preference.
|
|
*
|
|
* @param key The identifier of the preference to be removed
|
|
*/
|
|
public void remove( String key, HttpServletRequest req ) {
|
|
m_prefs.remove( key );
|
|
|
|
PersistentUserPrefs persistent = getPersistent();
|
|
|
|
if( !m_prefs.isEmpty() ) {
|
|
if( null != persistent ) persistent.removeValue( key );
|
|
} else {
|
|
if( null != persistent ) persistent.delete();
|
|
|
|
req.getSession().setAttribute( SESSION_ATTRIBUTE, null );
|
|
m_persistentPrefs = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save user preferences to the database
|
|
*/
|
|
public void persist( HttpServletRequest req,
|
|
HttpServletResponse res ) {
|
|
s_log.info( "Persisting session" );
|
|
|
|
PersistentUserPrefs prefs = getPersistent();
|
|
if( null == prefs ) prefs = createPersistent( req, res );
|
|
|
|
prefs.setAllValues( m_prefs );
|
|
prefs.save();
|
|
|
|
s_log.debug( "Session persisted" );
|
|
}
|
|
|
|
/**
|
|
* Get a PersistentUserPrefs object. Create one if necessary.
|
|
*/
|
|
private PersistentUserPrefs getPersistent() {
|
|
PersistentUserPrefs prefs = null;
|
|
|
|
if( null != m_persistentPrefs ) {
|
|
try {
|
|
prefs = new PersistentUserPrefs( m_persistentPrefs );
|
|
} catch( DataObjectNotFoundException ex ) {
|
|
s_log.warn( "User preferences object contained bogus " +
|
|
"persistent preferences OID" );
|
|
}
|
|
}
|
|
|
|
// If we're saving something and we have a user object now, use that
|
|
// in preference
|
|
if( null == m_user ) {
|
|
User user = (User) Kernel.getContext().getParty();
|
|
if( null != user ) {
|
|
prefs.setUser( user );
|
|
prefs.setCookie( null );
|
|
}
|
|
}
|
|
|
|
return prefs;
|
|
}
|
|
|
|
private PersistentUserPrefs createPersistent( HttpServletRequest req,
|
|
HttpServletResponse res ) {
|
|
PersistentUserPrefs prefs = retrievePersistent( req, res );
|
|
if( null == prefs ) {
|
|
prefs = new PersistentUserPrefs();
|
|
|
|
if( s_log.isDebugEnabled() ) {
|
|
s_log.debug( "Initializing new user preferences: " +
|
|
prefs.getOID() );
|
|
}
|
|
|
|
if( null != m_user ) {
|
|
prefs.setUser( new User( m_user ) );
|
|
}
|
|
|
|
else if( null != m_cookie ) {
|
|
prefs.setCookie( m_cookie );
|
|
}
|
|
|
|
else {
|
|
throw new UncheckedWrapperException ( "User preferences object doesn't contain either a user or a cookie object" );
|
|
}
|
|
|
|
m_persistentPrefs = prefs.getOID();
|
|
} else {
|
|
if( s_log.isDebugEnabled() ) {
|
|
s_log.debug( "Reusing existing persistent preferences " +
|
|
prefs.getOID() );
|
|
}
|
|
|
|
init( prefs );
|
|
}
|
|
|
|
return prefs;
|
|
}
|
|
|
|
private static Long getCookie( HttpServletRequest req ) {
|
|
Cookie[] cookieJar = req.getCookies();
|
|
if( null == cookieJar ) return null;
|
|
|
|
for( int i = 0; i < cookieJar.length; i++ ) {
|
|
if( COOKIE.equals( cookieJar[i].getName() ) ) {
|
|
try {
|
|
return Long.valueOf( cookieJar[i].getValue() );
|
|
} catch( NumberFormatException ex ) {
|
|
s_log.warn( "Bogus cookie value: " +
|
|
cookieJar[i].getValue() );
|
|
// Might as well keep looking
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static void setCookie( HttpServletResponse res, String value ) {
|
|
Cookie cookie = new Cookie( COOKIE, value );
|
|
cookie.setMaxAge( Integer.MAX_VALUE );
|
|
res.addCookie( cookie );
|
|
}
|
|
|
|
private static void removeCookie( HttpServletResponse res ) {
|
|
Cookie cookie = new Cookie( COOKIE, "" );
|
|
cookie.setMaxAge( 0 );
|
|
res.addCookie( cookie );
|
|
}
|
|
}
|