blob: 11f40097654656f5cd5d0bfcaa9756d90a69ffd9 [file] [log] [blame]
/*
* Copyright 2003,2004 The Apache Software Foundation.
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.apache.pluto.internal.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import javax.portlet.PortletPreferences;
import javax.portlet.PreferencesValidator;
import javax.portlet.ReadOnlyException;
import javax.portlet.ValidatorException;
import org.apache.pluto.Constants;
import org.apache.pluto.PortletContainer;
import org.apache.pluto.PortletContainerException;
import org.apache.pluto.util.StringManager;
import org.apache.pluto.internal.InternalPortletPreference;
import org.apache.pluto.internal.InternalPortletRequest;
import org.apache.pluto.internal.InternalPortletWindow;
import org.apache.pluto.internal.PortletEntity;
import org.apache.pluto.spi.optional.PortletPreferencesService;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
/**
* Implementation of the <code>javax.portlet.PortletPreferences</code>
* interface.
*
* @see org.apache.pluto.core.PortletPreference
* @see org.apache.pluto.core.impl.PortletPreferenceImpl
*
* @author <a href="mailto:ddewolf@apache.org">David H. DeWolf</a>
* @author <a href="mailto:zheng@apache.org">ZHENG Zhong</a>
*/
public class PortletPreferencesImpl implements PortletPreferences {
/** Logger. */
private static final Log LOG = LogFactory.getLog(PortletPreferencesImpl.class);
private static final StringManager EXCEPTIONS = StringManager.getManager(
PortletPreferencesImpl.class.getPackage().getName());
// Private Member Variables ------------------------------------------------
/** The portlet preferences service provided by the portal. */
private PortletPreferencesService preferencesService = null;
private InternalPortletWindow window = null;
private InternalPortletRequest request = null;
/**
* Default portlet preferences retrieved from portlet.xml, and used for
* resetting portlet preferences.
*/
private InternalPortletPreference[] defaultPreferences = null;
/**
* Current portlet preferences: key is the preference name as a string,
* value is the PortletPreference instance.
*/
private Map preferences = new HashMap();
/** Current method used for managing these preferences. */
private Integer methodId = null;
// Constructor -------------------------------------------------------------
/**
* Constructs an instance.
* @param container the portlet container.
* @param portletWindow the internal portlet window.
* @param request the internal portlet request.
* @param methodId the request method ID: render request or action request.
*/
public PortletPreferencesImpl(PortletContainer container,
InternalPortletWindow window,
InternalPortletRequest request,
Integer methodId) {
this.window = window;
this.request = request;
this.methodId = methodId;
// Get the portlet preferences service from container.
preferencesService = container.getOptionalContainerServices()
.getPortletPreferencesService();
if (LOG.isDebugEnabled()) {
LOG.debug("Using PortletPreferencesService: "
+ preferencesService.getClass().getName());
}
// Put default portlet preferences into preferences map.
PortletEntity entity = window.getPortletEntity();
defaultPreferences = entity.getDefaultPreferences();
for (int i = 0; i < defaultPreferences.length; i++) {
preferences.put(defaultPreferences[i].getName(),
(InternalPortletPreference) defaultPreferences[i].clone());
}
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded default preferences: " + toString());
}
// Merge stored portlet preferences into preferences map.
try {
InternalPortletPreference[] storedPreferences = preferencesService
.getStoredPreferences(window, request);
for (int i = 0; i < storedPreferences.length; i++) {
if (LOG.isDebugEnabled()) {
LOG.debug("Merging stored preference: "
+ storedPreferences[i].getName());
}
preferences.put(storedPreferences[i].getName(),
storedPreferences[i]);
}
// Store the preferences retrieved from portlet.xml.
// Portlet preferences are stored everytime when a
// PortletPreferencesImpl instance is created.
// So here we do not check the portlet request method ID.
internalStore();
} catch (PortletContainerException ex) {
LOG.error("Error retrieving preferences.", ex);
//TODO: Rethrow up the stack????
} catch (IOException ex) {
LOG.error("Error retrieving preferences.", ex);
//TODO: Rethrow up the stack????
} catch (ValidatorException ex) {
LOG.warn("ValidatorException initializing portlet preferences. "
+ "This is not illegal at this point "
+ "since we are just retreiving from portlet.xml.", ex);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Merged stored preferences: " + toString());
}
}
// PortletPreferences Impl -------------------------------------------------
public boolean isReadOnly(String key) {
if (key == null) {
throw new IllegalArgumentException(
EXCEPTIONS.getString("error.null", "Preference key "));
}
InternalPortletPreference pref = (InternalPortletPreference)
preferences.get(key);
return (pref != null && pref.isReadOnly());
}
public String getValue(String key, String defaultValue) {
String[] values = getValues(key, new String[] { defaultValue });
String value = null;
if (values != null && values.length > 0) {
value = values[0];
}
if (value == null) {
value = defaultValue;
}
return value;
}
public String[] getValues(String key, String[] defaultValues) {
if (key == null) {
throw new IllegalArgumentException(
EXCEPTIONS.getString("error.null", "Preference key "));
}
String[] values = null;
InternalPortletPreference pref = (InternalPortletPreference)
preferences.get(key);
if (pref != null) {
values = pref.getValues();
}
if (values == null) {
values = defaultValues;
}
return values;
}
public void setValue(String key, String value) throws ReadOnlyException {
if (isReadOnly(key)) {
throw new ReadOnlyException(EXCEPTIONS.getString(
"error.preference.readonly", key));
}
InternalPortletPreference pref = (InternalPortletPreference)
preferences.get(key);
if (pref != null) {
pref.setValues(new String[] { value });
} else {
pref = new PortletPreferenceImpl(key, new String[] { value });
preferences.put(key, pref);
}
}
public void setValues(String key, String[] values) throws ReadOnlyException {
if (isReadOnly(key)) {
throw new ReadOnlyException(EXCEPTIONS.getString(
"error.preference.readonly"));
}
InternalPortletPreference pref = (InternalPortletPreference)
preferences.get(key);
if (pref != null) {
pref.setValues(values);
} else {
pref = new PortletPreferenceImpl(key, values);
preferences.put(key, pref);
}
}
public Enumeration getNames() {
return new Vector(preferences.keySet()).elements();
}
public Map getMap() {
Map map = new HashMap();
Iterator it = preferences.keySet().iterator();
while (it.hasNext()) {
InternalPortletPreference pref = (InternalPortletPreference)
preferences.get(it.next());
map.put(pref.getName(),
pref.getValues() != null ? pref.getValues().clone() : null);
}
return Collections.unmodifiableMap(map);
}
public void reset(String key) throws ReadOnlyException {
// Read-only preferences cannot be reset.
if (isReadOnly(key)) {
throw new ReadOnlyException(EXCEPTIONS.getString(
"error.preference.readonly", "Preference key "));
}
// Try to reset preference to the default values.
boolean resetDone = false;
for (int i = 0; !resetDone && i < defaultPreferences.length; i++) {
if (key.equals(defaultPreferences[i].getName())) {
if (LOG.isDebugEnabled()) {
LOG.debug("Resetting preference for key: " + key);
}
preferences.put(key,
(InternalPortletPreference) defaultPreferences[i].clone());
resetDone = true;
}
}
// Remove preference if default values are not defined (PLT.14.1).
if (!resetDone) {
if (LOG.isDebugEnabled()) {
LOG.debug("Resetting preference to null for key: " + key);
}
preferences.remove(key);
}
}
/**
* Stores the portlet preferences to a persistent storage. This method
* should only be invoked within <code>processAction()</code> method.
*
* @see #internalStore()
*
* @throws IllegalStateException if this method is not invoked within
* <code>processAction()</code> method.
* @throws ValidatorException if the portlet preferences are not valid.
* @throws IOException if an error occurs with the persistence mechanism.
*/
public void store() throws IOException, ValidatorException {
if (!Constants.METHOD_ACTION.equals(methodId)) {
throw new IllegalStateException(
"store is only allowed inside a processAction call.");
}
internalStore();
}
// Private Methods ---------------------------------------------------------
/**
* Stores the portlet preferences to a persistent storage. If a preferences
* validator is defined for this portlet, this method firstly validates the
* portlet preferences.
* <p>
* This method is invoked internally, thus it does not check the portlet
* request method ID (METHOD_RENDER or METHOD_ACTION).
* </p>
* @throws ValidatorException if the portlet preferences are not valid.
* @throws IOException if an error occurs with the persistence mechanism.
*/
private void internalStore() throws IOException, ValidatorException {
// Validate the preferences before storing, if a validator is defined.
// If the preferences cannot pass the validation,
// an ValidatorException will be thrown out.
PreferencesValidator validator = window.getPortletEntity()
.getPreferencesValidator();
if (validator != null) {
validator.validate(this);
}
// Store the portlet preferences.
InternalPortletPreference[] prefs = (InternalPortletPreference[])
(new ArrayList(preferences.values())).toArray(
new InternalPortletPreference[preferences.size()]);
try {
preferencesService.store(window, request, prefs);
} catch (PortletContainerException ex) {
LOG.error("Error storing preferences.", ex);
throw new IOException("Error storing perferences: " + ex.getMessage());
}
}
// Object Methods ----------------------------------------------------------
/**
* Returns the string representation of this object. Preferences are
* separated by ';' character, while values in one preference are separated
* by ',' character.
* @return the string representation of this object.
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(getClass().getName()).append("[");
for (Enumeration en = getNames(); en.hasMoreElements(); ) {
String name = (String) en.nextElement();
buffer.append(name);
buffer.append("(readOnly:").append(isReadOnly(name)).append(")=");
String[] values = getValues(name, null);
if (values != null) {
for (int i = 0; i < values.length; i++) {
buffer.append(values[i]);
if (i < values.length - 1) {
buffer.append(",");
}
}
} else {
buffer.append("NULL");
}
buffer.append(";");
}
buffer.append("]");
return buffer.toString();
}
}