/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-render-impl/impl/src/java/org/sakaiproject/portal/render/portlet/services/state/EnhancedPortletStateEncoder.java $
* $Id: EnhancedPortletStateEncoder.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2005, 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.portal.render.portlet.services.state;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.portlet.PortletMode;
import javax.portlet.WindowState;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Enhanced version of the PortletStateEncoder. This implementation translates
* the PortletState into a properties file format for serialization. This
* results in a url parameters which is significatly shorter than ther simple
* version. This may be desirable in a cases where the url query string is
* allready significant and may surpass the limit of 2083 characters imposed by
* some browsers.
*
* @version $Id: EnhancedPortletStateEncoder.java 21641 2007-02-15 23:38:43Z
* csev@umich.edu $
* @since 2.2.3
*/
public class EnhancedPortletStateEncoder implements PortletStateEncoder
{
private static final Log LOG = LogFactory.getLog(EnhancedPortletStateEncoder.class);
//
// Implementation Note:
// - Map Keys below are qualified in order to prevent
// conflicts with portlet parameters
// - Keys have been abbreviated to shorten the query
// string parameter resulting
//
private static final String ID_PARAM = "o.s.p.r.s.ID";
private static final String ACTION_PARAM = "o.s.p.r.s.ACTION";
private static final String SECURE_PARAM = "o.s.p.r.s.SECURE";
private static final String PORTLET_MODE_PARAM = "o.s.p.r.s.PORTLET_MODE";
private static final String WINDOW_STATE_PARAM = "o.s.p.r.s.WINDOW_STATE";
private WebRecoder urlSafeEncoder = new Base64Recoder();
public WebRecoder getUrlSafeEncoder()
{
return urlSafeEncoder;
}
public void setUrlSafeEncoder(WebRecoder urlSafeEncoder)
{
this.urlSafeEncoder = urlSafeEncoder;
}
public String encode(PortletState portletState)
{
if (LOG.isDebugEnabled())
{
LOG.debug("Encoding PortletState [action=" + portletState.isAction() + "]");
}
Properties p = new Properties();
p.setProperty(ID_PARAM, portletState.getId());
p.setProperty(ACTION_PARAM, String.valueOf(portletState.isAction()));
p.setProperty(SECURE_PARAM, String.valueOf(portletState.isSecure()));
p.setProperty(WINDOW_STATE_PARAM, portletState.getWindowState().toString());
p.setProperty(PORTLET_MODE_PARAM, portletState.getPortletMode().toString());
Map parms = portletState.getParameters();
Iterator it = parms.entrySet().iterator();
String normalParms = "";
while (it.hasNext())
{
Map.Entry entry = (Map.Entry) it.next();
Object o = entry.getValue();
if (o instanceof String)
{
p.setProperty("" + entry.getKey(), o.toString());
normalParms = normalParms + "&" + entry.getKey() + "=" + o.toString();
}
else
{
String[] vals = (String[]) o;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < vals.length; i++)
{
if (vals[i] == null)
{
continue;
}
if (i > 0)
{
sb.append(",");
}
sb.append(vals[i]);
}
p.setProperty("" + entry.getKey(), sb.toString());
normalParms = normalParms + "&" + entry.getKey() + "=" + sb.toString();
}
}
if (LOG.isDebugEnabled())
{
LOG.debug("Encoded PortletState to properties for Tool '"
+ portletState.getId() + "'.");
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
p.store(out, "Sakai Portlet State");
}
catch (IOException e)
{
throw new IllegalStateException("This should never occor");
}
return urlSafeEncoder.encode(out.toByteArray());
//IEB Removed this, why are we encoding normal params raw when they are just a copy of the encoded ones + normalParms;
}
public PortletState decode(String uri)
{
byte[] bits = urlSafeEncoder.decode(uri);
ByteArrayInputStream in = new ByteArrayInputStream(bits);
Properties p = new Properties();
try
{
p.load(in);
}
catch (IOException e)
{
throw new IllegalStateException("This should never occor");
}
String id = p.getProperty(ID_PARAM);
PortletState state = new PortletState(id);
state.setAction(Boolean.valueOf(p.getProperty(ACTION_PARAM)).booleanValue());
state.setSecure(Boolean.valueOf(p.getProperty(SECURE_PARAM)).booleanValue());
state.setWindowState(new WindowState(p.getProperty(WINDOW_STATE_PARAM)));
state.setPortletMode(new PortletMode(p.getProperty(PORTLET_MODE_PARAM)));
p.remove(ID_PARAM);
p.remove(ACTION_PARAM);
p.remove(SECURE_PARAM);
p.remove(WINDOW_STATE_PARAM);
p.remove(PORTLET_MODE_PARAM);
Map map = new HashMap();
Iterator i = p.entrySet().iterator();
while (i.hasNext())
{
Map.Entry parm = (Map.Entry) i.next();
String key = parm.getKey().toString();
String val = parm.getValue().toString();
StringTokenizer st = new StringTokenizer(val, ",");
String[] parms = new String[st.countTokens()];
int j = 0;
while (st.hasMoreTokens())
{
parms[j++] = st.nextToken();
}
map.put(key, parms);
}
state.setParameters(map);
if (LOG.isDebugEnabled())
{
LOG.debug("Decoded PortletState for Tool '" + state.getId() + "'");
}
return state;
}
}