001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.pluto.internal.impl;
018:
019: import java.io.IOException;
020: import java.util.ArrayList;
021: import java.util.Collections;
022: import java.util.Enumeration;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.Map;
026: import java.util.Vector;
027:
028: import javax.portlet.PortletPreferences;
029: import javax.portlet.PreferencesValidator;
030: import javax.portlet.ReadOnlyException;
031: import javax.portlet.ValidatorException;
032:
033: import org.apache.pluto.Constants;
034: import org.apache.pluto.PortletContainer;
035: import org.apache.pluto.PortletContainerException;
036: import org.apache.pluto.util.StringManager;
037: import org.apache.pluto.internal.InternalPortletPreference;
038: import org.apache.pluto.internal.InternalPortletRequest;
039: import org.apache.pluto.internal.InternalPortletWindow;
040: import org.apache.pluto.internal.PortletEntity;
041: import org.apache.pluto.spi.optional.PortletPreferencesService;
042: import org.apache.commons.logging.LogFactory;
043: import org.apache.commons.logging.Log;
044:
045: /**
046: * Implementation of the <code>javax.portlet.PortletPreferences</code>
047: * interface.
048: *
049: * @see PortletPreferences
050: * @see PortletPreferenceImpl
051: *
052: */
053: public class PortletPreferencesImpl implements PortletPreferences {
054:
055: /** Logger. */
056: private static final Log LOG = LogFactory
057: .getLog(PortletPreferencesImpl.class);
058:
059: private static final StringManager EXCEPTIONS = StringManager
060: .getManager(PortletPreferencesImpl.class.getPackage()
061: .getName());
062:
063: // Private Member Variables ------------------------------------------------
064:
065: /** The portlet preferences service provided by the portal. */
066: private final PortletPreferencesService preferencesService;
067:
068: private final InternalPortletWindow window;
069:
070: private final InternalPortletRequest request;
071:
072: /**
073: * Default portlet preferences retrieved from portlet.xml, and used for
074: * resetting portlet preferences.
075: */
076: private final InternalPortletPreference[] defaultPreferences;
077:
078: /**
079: * Current portlet preferences: key is the preference name as a string,
080: * value is the PortletPreference instance.
081: */
082: private final Map preferences = new HashMap();
083:
084: /** Current method used for managing these preferences. */
085: private final Integer methodId;
086:
087: // Constructor -------------------------------------------------------------
088:
089: /**
090: * Constructs an instance.
091: * @param container the portlet container.
092: * @param window the internal portlet window.
093: * @param request the internal portlet request.
094: * @param methodId the request method ID: render request or action request.
095: */
096: public PortletPreferencesImpl(PortletContainer container,
097: InternalPortletWindow window,
098: InternalPortletRequest request, Integer methodId) {
099: this .window = window;
100: this .request = request;
101: this .methodId = methodId;
102:
103: // Get the portlet preferences service from container.
104: preferencesService = container.getOptionalContainerServices()
105: .getPortletPreferencesService();
106: if (LOG.isDebugEnabled()) {
107: LOG.debug("Using PortletPreferencesService: "
108: + preferencesService.getClass().getName());
109: }
110:
111: // Put default portlet preferences into preferences map.
112: PortletEntity entity = window.getPortletEntity();
113: defaultPreferences = entity.getDefaultPreferences();
114: for (int i = 0; i < defaultPreferences.length; i++) {
115: preferences.put(defaultPreferences[i].getName(),
116: defaultPreferences[i].clone());
117: }
118: if (LOG.isDebugEnabled()) {
119: LOG.debug("Loaded default preferences: " + toString());
120: }
121:
122: // Merge stored portlet preferences into preferences map.
123: try {
124: InternalPortletPreference[] storedPreferences = preferencesService
125: .getStoredPreferences(window, request);
126: for (int i = 0; i < storedPreferences.length; i++) {
127: if (LOG.isDebugEnabled()) {
128: LOG.debug("Merging stored preference: "
129: + storedPreferences[i].getName());
130: }
131: preferences.put(storedPreferences[i].getName(),
132: storedPreferences[i]);
133: }
134: // Store the preferences retrieved from portlet.xml.
135: // Portlet preferences are stored everytime when a
136: // PortletPreferencesImpl instance is created.
137: // So here we do not check the portlet request method ID.
138: internalStore();
139:
140: } catch (PortletContainerException ex) {
141: LOG.error("Error retrieving preferences.", ex);
142: //TODO: Rethrow up the stack????
143: } catch (IOException ex) {
144: LOG.error("Error retrieving preferences.", ex);
145: //TODO: Rethrow up the stack????
146: } catch (ValidatorException ex) {
147: LOG
148: .warn(
149: "ValidatorException initializing portlet preferences. "
150: + "This is not illegal at this point "
151: + "since we are just retreiving from portlet.xml.",
152: ex);
153: }
154: if (LOG.isDebugEnabled()) {
155: LOG.debug("Merged stored preferences: " + toString());
156: }
157: }
158:
159: // PortletPreferences Impl -------------------------------------------------
160:
161: public boolean isReadOnly(String key) {
162: if (key == null) {
163: throw new IllegalArgumentException(EXCEPTIONS.getString(
164: "error.null", "Preference key "));
165: }
166: InternalPortletPreference pref = (InternalPortletPreference) preferences
167: .get(key);
168: return (pref != null && pref.isReadOnly());
169: }
170:
171: public String getValue(String key, String defaultValue) {
172: String[] values = getValues(key, new String[] { defaultValue });
173: String value = null;
174: if (values != null && values.length > 0) {
175: value = values[0];
176: }
177: if (value == null) {
178: value = defaultValue;
179: }
180: return value;
181: }
182:
183: public String[] getValues(String key, String[] defaultValues) {
184: if (key == null) {
185: throw new IllegalArgumentException(EXCEPTIONS.getString(
186: "error.null", "Preference key "));
187: }
188: String[] values = null;
189: InternalPortletPreference pref = (InternalPortletPreference) preferences
190: .get(key);
191: if (pref != null) {
192: values = pref.getValues();
193: }
194: if (values == null) {
195: values = defaultValues;
196: }
197: return values;
198: }
199:
200: public void setValue(String key, String value)
201: throws ReadOnlyException {
202: if (isReadOnly(key)) {
203: throw new ReadOnlyException(EXCEPTIONS.getString(
204: "error.preference.readonly", key));
205: }
206: InternalPortletPreference pref = (InternalPortletPreference) preferences
207: .get(key);
208: if (pref != null) {
209: pref.setValues(new String[] { value });
210: } else {
211: pref = new PortletPreferenceImpl(key,
212: new String[] { value });
213: preferences.put(key, pref);
214: }
215: }
216:
217: public void setValues(String key, String[] values)
218: throws ReadOnlyException {
219: if (isReadOnly(key)) {
220: throw new ReadOnlyException(EXCEPTIONS
221: .getString("error.preference.readonly"));
222: }
223: InternalPortletPreference pref = (InternalPortletPreference) preferences
224: .get(key);
225: if (pref != null) {
226: pref.setValues(values);
227: } else {
228: pref = new PortletPreferenceImpl(key, values);
229: preferences.put(key, pref);
230: }
231: }
232:
233: public Enumeration getNames() {
234: return new Vector(preferences.keySet()).elements();
235: }
236:
237: public Map getMap() {
238: Map map = new HashMap();
239: Iterator it = preferences.keySet().iterator();
240: while (it.hasNext()) {
241: InternalPortletPreference pref = (InternalPortletPreference) preferences
242: .get(it.next());
243: map.put(pref.getName(), pref.getValues() != null ? pref
244: .getValues().clone() : null);
245: }
246: return Collections.unmodifiableMap(map);
247: }
248:
249: public void reset(String key) throws ReadOnlyException {
250: // Read-only preferences cannot be reset.
251: if (isReadOnly(key)) {
252: throw new ReadOnlyException(EXCEPTIONS.getString(
253: "error.preference.readonly", "Preference key "));
254: }
255: // Try to reset preference to the default values.
256: boolean resetDone = false;
257: for (int i = 0; !resetDone && i < defaultPreferences.length; i++) {
258: if (key.equals(defaultPreferences[i].getName())) {
259: if (LOG.isDebugEnabled()) {
260: LOG.debug("Resetting preference for key: " + key);
261: }
262: preferences.put(key, defaultPreferences[i].clone());
263: resetDone = true;
264: }
265: }
266: // Remove preference if default values are not defined (PLT.14.1).
267: if (!resetDone) {
268: if (LOG.isDebugEnabled()) {
269: LOG.debug("Resetting preference to null for key: "
270: + key);
271: }
272: preferences.remove(key);
273: }
274: }
275:
276: /**
277: * Stores the portlet preferences to a persistent storage. This method
278: * should only be invoked within <code>processAction()</code> method.
279: *
280: * @see #internalStore()
281: *
282: * @throws IllegalStateException if this method is not invoked within
283: * <code>processAction()</code> method.
284: * @throws ValidatorException if the portlet preferences are not valid.
285: * @throws IOException if an error occurs with the persistence mechanism.
286: */
287: public void store() throws IOException, ValidatorException {
288: if (!Constants.METHOD_ACTION.equals(methodId)) {
289: throw new IllegalStateException(
290: "store is only allowed inside a processAction call.");
291: }
292: internalStore();
293: }
294:
295: // Private Methods ---------------------------------------------------------
296:
297: /**
298: * Stores the portlet preferences to a persistent storage. If a preferences
299: * validator is defined for this portlet, this method firstly validates the
300: * portlet preferences.
301: * <p>
302: * This method is invoked internally, thus it does not check the portlet
303: * request method ID (METHOD_RENDER or METHOD_ACTION).
304: * </p>
305: * @throws ValidatorException if the portlet preferences are not valid.
306: * @throws IOException if an error occurs with the persistence mechanism.
307: */
308: private void internalStore() throws IOException, ValidatorException {
309: // Validate the preferences before storing, if a validator is defined.
310: // If the preferences cannot pass the validation,
311: // an ValidatorException will be thrown out.
312: PreferencesValidator validator = window.getPortletEntity()
313: .getPreferencesValidator();
314: if (validator != null) {
315: validator.validate(this );
316: }
317: // Store the portlet preferences.
318: InternalPortletPreference[] prefs = (InternalPortletPreference[]) (new ArrayList(
319: preferences.values()))
320: .toArray(new InternalPortletPreference[preferences
321: .size()]);
322: try {
323: preferencesService.store(window, request, prefs);
324: } catch (PortletContainerException ex) {
325: LOG.error("Error storing preferences.", ex);
326: throw new IOException("Error storing perferences: "
327: + ex.getMessage());
328: }
329: }
330:
331: // Object Methods ----------------------------------------------------------
332:
333: /**
334: * Returns the string representation of this object. Preferences are
335: * separated by ';' character, while values in one preference are separated
336: * by ',' character.
337: * @return the string representation of this object.
338: * @see java.lang.Object#toString()
339: */
340: public String toString() {
341: StringBuffer buffer = new StringBuffer();
342: buffer.append(getClass().getName()).append("[");
343: for (Enumeration en = getNames(); en.hasMoreElements();) {
344: String name = (String) en.nextElement();
345: buffer.append(name);
346: buffer.append("(readOnly:").append(isReadOnly(name))
347: .append(")=");
348: String[] values = getValues(name, null);
349: if (values != null) {
350: for (int i = 0; i < values.length; i++) {
351: buffer.append(values[i]);
352: if (i < values.length - 1) {
353: buffer.append(",");
354: }
355: }
356: } else {
357: buffer.append("NULL");
358: }
359: buffer.append(";");
360: }
361: buffer.append("]");
362: return buffer.toString();
363: }
364:
365: }
|