/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2005 Danet GmbH (www.danet.de), BU BTS.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: PortletEnvironment.java 2390 2007-05-26 21:54:29Z mlipp $
*
* $Log$
* Revision 1.15 2007/05/25 16:45:04 drmlipp
* Improved comment.
*
* Revision 1.14 2006/10/22 20:12:48 mlipp
* Fixed problems with empty preferences.
*
* Revision 1.13 2006/09/29 12:32:11 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.12 2006/09/14 07:41:23 drmlipp
* Removed old code.
*
* Revision 1.11 2006/09/13 21:53:31 mlipp
* Improved preferences handling.
*
* Revision 1.8 2006/09/13 11:01:34 drmlipp
* Fixed caching scope.
*
* Revision 1.7 2006/09/12 15:55:28 drmlipp
* Added canonical time zone retrieval.
*
* Revision 1.6 2005/10/14 08:57:08 drmlipp
* Fixed.
*
* Revision 1.5 2005/10/13 21:53:07 mlipp
* Simplified by using commons-collections.
*
* Revision 1.4 2005/09/19 21:14:41 mlipp
* Added boolean access to preferences.
*
* Revision 1.3 2005/09/09 13:31:03 drmlipp
* Added possibility to access preferences as Integer.
*
* Revision 1.2 2005/09/09 10:47:47 drmlipp
* Imroved.
*
* Revision 1.1 2005/09/08 15:13:00 drmlipp
* New approach to store() problem.
*
*/
package de.danet.an.util.jsf;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import javax.faces.FactoryFinder;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.ReadOnlyException;
import javax.portlet.ValidatorException;
import org.apache.commons.collections.map.AbstractMapDecorator;
import de.danet.an.util.CollectionsUtil;
/**
* A bean that provides access to the portlet environment from a JSF page.
*/
public class PortletEnvironment implements PhaseListener {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory
.getLog (PortletEnvironment.class);
private static final String PREFS_CACHE
= PortletEnvironment.class.getName() + "_PREFS_CACHE";
private Lifecycle lifecycle = null;
/**
* Return the portlet preferences from the current request as map.
* If a preference consists of multiple values, only the first
* will be returned.
*
* @return the preferences.
*/
public Map portletPreferences() {
ExternalContext extCtx = FacesContext
.getCurrentInstance().getExternalContext();
Map prefsCache = (Map)extCtx.getSessionMap().get(PREFS_CACHE);
if (prefsCache == null) {
Object req = extCtx.getRequest();
if (req instanceof PortletRequest) {
// Get a map of preferences where
// the entries hold only the first string from the
// array of preferences values.
Map prefsMap = new HashMap ();
for (Iterator i = ((PortletRequest)req).getPreferences()
.getMap().entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry)i.next();
String[] entryVal = (String[])entry.getValue();
if (entryVal != null && entryVal.length > 0) {
prefsMap.put (entry.getKey(), entryVal[0]);
}
}
// Track the map to allow update later.
prefsCache = CollectionsUtil.trackedMap(prefsMap);
} else {
prefsCache = new HashMap ();
}
extCtx.getSessionMap().put(PREFS_CACHE, prefsCache);
}
return prefsCache;
}
/**
* Return the preferences defined for the portlet.
* @return the preferences
*/
public Map getPreferences () {
registerForCleanup();
return portletPreferences();
}
/**
* Return the time zone for this user. The value is derived from
* the "user.timezone" preference. If this is not set, the system default
* is returned.
*
* @return result
*/
public TimeZone getTimeZone () {
String timeZoneId = (String)getPreferences().get("user.timezone");
if (timeZoneId != null) {
TimeZone found = TimeZone.getTimeZone(timeZoneId);
if (found.getID().equals(timeZoneId)) {
return found;
}
logger.warn("Time zone with id=\"" + timeZoneId + "\" not found");
}
try {
Class usuc = Thread.currentThread().getContextClassLoader()
.loadClass("com.liferay.portal.service.UserServiceUtil");
Method gum = usuc.getMethod
("getUserById", new Class[] { String.class });
ExternalContext extCtx = FacesContext
.getCurrentInstance().getExternalContext();
String userId = (String)
((PortletRequest)extCtx.getRequest()).getPortletSession()
.getAttribute("USER_ID", PortletSession.APPLICATION_SCOPE);
if (userId != null) {
Object user = gum.invoke(null, new Object[] { userId });
Method gtz = user.getClass().getMethod("getTimeZone", null);
TimeZone tz = (TimeZone)gtz.invoke(user, null);
return tz;
}
} catch (ClassNotFoundException e1) {
// Was just a try anyway...
} catch (SecurityException e) {
// Was just a try anyway...
} catch (NoSuchMethodException e) {
// Was just a try anyway...
} catch (IllegalArgumentException e) {
// Was just a try anyway...
} catch (IllegalAccessException e) {
// Was just a try anyway...
} catch (InvocationTargetException e) {
// Was just a try anyway...
}
return TimeZone.getDefault();
}
public static class IntegerWrapper extends AbstractMapDecorator {
/**
* @param delegee
*/
public IntegerWrapper(Map delegee) {
super(delegee);
}
/* (non-Javadoc)
* @see java.util.Map#get(java.lang.Object)
*/
public Object get(Object key) {
return Integer.decode((String)map.get(key));
}
/* (non-Javadoc)
* @see org.apache.commons.collections.map.AbstractMapDecorator#put(java.lang.Object, java.lang.Object)
*/
public Object put(Object key, Object value) {
// TODO Auto-generated method stub
return super.put(key, value.toString());
}
}
/**
* Return the preferences with an Integer wrapper. Accessing
* a preference will return an Integer if the string is convertible.
* @return the wrapped preferences
*/
public Map getPreferencesAsIntegers () {
return new IntegerWrapper(getPreferences ());
}
public static class BooleanWrapper extends AbstractMapDecorator {
/**
* @param delegee
*/
public BooleanWrapper(Map delegee) {
super(delegee);
}
/* (non-Javadoc)
* @see java.util.Map#get(java.lang.Object)
*/
public Object get(Object key) {
return Boolean.valueOf((String)map.get(key));
}
/* (non-Javadoc)
* @see org.apache.commons.collections.map.AbstractMapDecorator#put(java.lang.Object, java.lang.Object)
*/
public Object put(Object key, Object value) {
// TODO Auto-generated method stub
return super.put(key, value.toString());
}
}
/**
* Return the preferences with a Boolean wrapper. Accessing
* a preference will return an Integer if the string is convertible.
* @return the wrapped preferences
*/
public Map getPreferencesAsBooleans () {
return new BooleanWrapper(getPreferences ());
}
// Implementation of PhaseListener issues
/**
* Register for cleanup.
*/
protected void registerForCleanup () {
if (lifecycle != null) {
return;
}
LifecycleFactory factory = (LifecycleFactory)
FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
lifecycle = factory.getLifecycle
(LifecycleFactory.DEFAULT_LIFECYCLE);
lifecycle.addPhaseListener(this);
}
/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#getPhaseId()
*/
public PhaseId getPhaseId() {
return PhaseId.UPDATE_MODEL_VALUES;
}
/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
*/
public void afterPhase(PhaseEvent event) {
try {
ExternalContext extCtx = FacesContext
.getCurrentInstance().getExternalContext();
Map prefsCache = (Map)extCtx.getSessionMap().get(PREFS_CACHE);
Object req = extCtx.getRequest();
if (prefsCache != null && req instanceof PortletRequest) {
PortletPreferences prefs
= ((PortletRequest)req).getPreferences();
try {
Set mods = CollectionsUtil.modifiedEntries(prefsCache);
for (Iterator i = mods.iterator(); i.hasNext();) {
String mod = (String)i.next();
if (!prefsCache.containsKey(mod)) {
prefs.reset(mod);
} else {
prefs.setValue(mod, (String)prefsCache.get(mod));
}
}
} catch (ReadOnlyException e) {
logger.warn("Cannot set read-only preference: "
+ e.getMessage(), e);
}
prefs.store();
}
} catch (ValidatorException e) {
logger.error("Cannot store preferences: " + e.getMessage(), e);
} catch (IOException e) {
logger.error("Cannot store preferences: " + e.getMessage(), e);
}
// De-register
lifecycle.removePhaseListener(this);
lifecycle = null;
}
/* (non-Javadoc)
* @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
*/
public void beforePhase(PhaseEvent event) {
}
}