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.jetspeed.om.preference.impl;
018:
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Locale;
024: import java.util.StringTokenizer;
025: import java.util.prefs.BackingStoreException;
026: import java.util.prefs.Preferences;
027:
028: import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
029: import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
030: import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
031: import org.apache.jetspeed.om.common.preference.PreferenceComposite;
032: import org.apache.jetspeed.om.impl.PreferenceDescriptionImpl;
033: import org.apache.pluto.om.common.Description;
034:
035: public class PrefsPreference implements PreferenceComposite {
036: protected static final String VALUES_PATH = "values";
037: protected static final String VALUES_SIZE = "size";
038:
039: public static final String PORTLET_PREFERENCES_ROOT = "preferences";
040: protected static final String LOCALE_TOKEN = "_";
041: protected Preferences prefValueNode;
042: protected Preferences prefValueSizeNode;
043: protected Preferences prefNode;
044: protected String name;
045: public static final String[] DEFAULT_OPEN_NODES = new String[] {
046: MutablePortletEntity.PORTLET_ENTITY_ROOT,
047: PortletDefinitionComposite.PORTLETS_PREFS_ROOT };
048:
049: public PrefsPreference(Preferences prefNode, String name) {
050: super ();
051: this .prefNode = prefNode;
052: if (prefNode == null) {
053: throw new IllegalArgumentException(
054: "prefNode cannot be null for PrefsPreferences(Preference).");
055: }
056:
057: this .name = name;
058: if (this .name == null) {
059: throw new IllegalArgumentException(
060: "Preference does requires a \"name\" property.");
061: }
062:
063: this .prefValueNode = prefNode.node(VALUES_PATH);
064: this .prefValueSizeNode = prefNode.node(VALUES_SIZE);
065: }
066:
067: public PrefsPreference(PortletDefinitionComposite portlet,
068: String name) {
069: this (createPrefenceNode(portlet).node(name), name);
070: }
071:
072: private int getPrefValueSize(boolean store) {
073: int size = prefValueSizeNode.getInt(VALUES_SIZE, -1);
074: if (size == -1) {
075: // prefSizeNode doesn't exist
076: // if values exists (upgrading issue), determine from number of values keys
077: try {
078: size = prefValueNode.keys().length;
079: } catch (BackingStoreException e) {
080: String msg = "Preference backing store failed: "
081: + e.toString();
082: IllegalStateException ise = new IllegalStateException(
083: msg);
084: ise.initCause(e);
085: throw ise;
086: }
087: if (store) {
088: prefValueSizeNode.putInt(VALUES_SIZE, size);
089: }
090: }
091: return size;
092: }
093:
094: /**
095: * <p>
096: * addDescription
097: * </p>
098: *
099: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#addDescription(java.util.Locale,
100: * java.lang.String)
101: * @param locale
102: * @param Description
103: */
104: public void addDescription(Locale locale, String description) {
105: String localePath = locale.toString();
106: prefNode.node("description").put(localePath, description);
107: }
108:
109: /**
110: * <p>
111: * getDescription
112: * </p>
113: *
114: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getDescription(java.util.Locale)
115: * @param locale
116: * @return
117: */
118: public Description getDescription(Locale locale) {
119: String localePath = locale.toString();
120: String value = prefNode.node("description").get(localePath,
121: null);
122: PreferenceDescriptionImpl desc = new PreferenceDescriptionImpl();
123: desc.setDescription(value);
124: desc.setLocale(locale);
125: desc.setLanguage(locale.getLanguage());
126: return desc;
127: }
128:
129: /**
130: * <p>
131: * getValueAt
132: * </p>
133: *
134: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getValueAt(int)
135: * @param index
136: * @return
137: */
138: public String getValueAt(int index) {
139: return prefValueNode.get(String.valueOf(index), null);
140: }
141:
142: public void removeValueAt(int index) {
143: int size;
144: if (index > -1 && index < (size = getPrefValueSize(true))) {
145: String[] values = new String[size - 1];
146: for (int i = 0; i < index; i++) {
147: values[i] = prefValueNode.get(String.valueOf(i), null);
148: }
149: for (int i = index + 1; i < size; i++) {
150: values[i] = prefValueNode.get(String.valueOf(i), null);
151: }
152: setValues(values);
153: } else
154: throw new IndexOutOfBoundsException();
155: }
156:
157: /**
158: * <p>
159: * setValueAt
160: * </p>
161: *
162: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#setValueAt(int,
163: * java.lang.String)
164: * @param index
165: * @param value
166: */
167: public void setValueAt(int index, String value) {
168: if (index > -1) {
169: int size = getPrefValueSize(true);
170: if (index < size) {
171: if (value != null) {
172: prefValueNode.put(String.valueOf(index), value);
173: } else {
174: prefValueNode.remove(String.valueOf(index));
175: }
176: } else {
177: prefValueSizeNode.putInt(VALUES_SIZE, index + 1);
178: if (value != null) {
179: prefValueNode.put(String.valueOf(index), value);
180: }
181: }
182:
183: } else
184: throw new IndexOutOfBoundsException();
185: }
186:
187: /**
188: * <p>
189: * addValue
190: * </p>
191: *
192: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#addValue(java.lang.String)
193: * @param value
194: */
195: public void addValue(String value) {
196: int size = getPrefValueSize(true);
197: prefValueSizeNode.putInt(VALUES_SIZE, size + 1);
198: if (value != null) {
199: prefValueNode.put(String.valueOf(size), value);
200: }
201: }
202:
203: /**
204: * <p>
205: * getValueArray
206: * </p>
207: *
208: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getValueArray()
209: * @return
210: */
211: public String[] getValueArray() {
212: int size = getPrefValueSize(false);
213: String[] values = new String[size];
214: for (int i = 0; i < size; i++) {
215: values[i] = prefValueNode.get(String.valueOf(i), null);
216: }
217: return values;
218: }
219:
220: /**
221: * <p>
222: * setValues
223: * </p>
224: *
225: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#setValues(java.lang.String[])
226: * @param stringValues
227: */
228: public void setValues(String[] stringValues) {
229: try {
230: prefValueNode.clear();
231: int size = stringValues != null ? stringValues.length : 0;
232: prefValueSizeNode.putInt(VALUES_SIZE, size);
233: for (int i = 0; i < size; i++) {
234: if (stringValues[i] != null) {
235: prefValueNode.put(String.valueOf(i),
236: stringValues[i]);
237: }
238: }
239: } catch (BackingStoreException e) {
240: String msg = "Preference backing store failed: "
241: + e.toString();
242: IllegalStateException ise = new IllegalStateException(msg);
243: ise.initCause(e);
244: throw ise;
245: }
246: }
247:
248: /**
249: * <p>
250: * getType
251: * </p>
252: *
253: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getType()
254: * @return
255: */
256: public String getType() {
257: // TODO Auto-generated method stub
258: return null;
259: }
260:
261: /**
262: * <p>
263: * setType
264: * </p>
265: *
266: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#setType(java.lang.String)
267: * @param string
268: */
269: public void setType(String string) {
270: // TODO Auto-generated method stub
271:
272: }
273:
274: /**
275: * <p>
276: * setName
277: * </p>
278: *
279: * @see org.apache.pluto.om.common.PreferenceCtrl#setName(java.lang.String)
280: * @param arg0
281: */
282: public void setName(String name) {
283: this .name = name;
284:
285: }
286:
287: /**
288: * <p>
289: * setValues
290: * </p>
291: *
292: * @see org.apache.pluto.om.common.PreferenceCtrl#setValues(java.util.List)
293: * @param arg0
294: */
295: public void setValues(List arg0) {
296: if (arg0 != null) {
297: setValues((String[]) arg0.toArray(new String[arg0.size()]));
298: }
299:
300: }
301:
302: /**
303: * <p>
304: * setReadOnly
305: * </p>
306: *
307: * @see org.apache.pluto.om.common.PreferenceCtrl#setReadOnly(java.lang.String)
308: * @param arg0
309: */
310: public void setReadOnly(String readOnly) {
311: prefNode.put("read_only", readOnly);
312:
313: }
314:
315: public void setReadOnly(boolean readOnly) {
316: if (readOnly) {
317: prefNode.put("read_only", "true");
318: } else {
319: prefNode.put("read_only", "false");
320: }
321:
322: }
323:
324: /**
325: * <p>
326: * getName
327: * </p>
328: *
329: * @see org.apache.pluto.om.common.Preference#getName()
330: * @return
331: */
332: public String getName() {
333: return name;
334: }
335:
336: /**
337: * <p>
338: * getValues
339: * </p>
340: *
341: * @see org.apache.pluto.om.common.Preference#getValues()
342: * @return
343: */
344: public Iterator getValues() {
345: return Arrays.asList(getValueArray()).iterator();
346: }
347:
348: /**
349: * <p>
350: * isReadOnly
351: * </p>
352: *
353: * @see org.apache.pluto.om.common.Preference#isReadOnly()
354: * @return
355: */
356: public boolean isReadOnly() {
357: return Boolean.valueOf(prefNode.get("read_only", "false"))
358: .booleanValue();
359: }
360:
361: /**
362: * <p>
363: * isValueSet
364: * </p>
365: *
366: * @see org.apache.pluto.om.common.Preference#isValueSet()
367: * @return
368: */
369: public boolean isValueSet() {
370: return getPrefValueSize(false) > 0;
371: }
372:
373: protected Locale parseLocal(String localString) {
374: StringTokenizer lcTk = new StringTokenizer(localString,
375: LOCALE_TOKEN);
376: String lang = null;
377: String country = null;
378: String variant = null;
379: while (lcTk.hasMoreTokens()) {
380: if (lang == null) {
381: lang = lcTk.nextToken();
382: } else if (country == null) {
383: country = lcTk.nextToken();
384: } else if (variant == null) {
385: variant = lcTk.nextToken();
386: }
387: }
388:
389: return new Locale(lang, country, variant);
390: }
391:
392: /**
393: * <p>
394: * clone
395: * </p>
396: *
397: * @see java.lang.Object#clone()
398: * @return @throws
399: * java.lang.CloneNotSupportedException
400: */
401: public String[] cloneValues() {
402: String[] clonedValues;
403: synchronized (prefValueNode) {
404: String[] currentValues = getValueArray();
405: clonedValues = new String[currentValues.length];
406:
407: System.arraycopy(currentValues, 0, clonedValues, 0,
408: currentValues.length);
409: }
410:
411: return clonedValues;
412: }
413:
414: /**
415: * <p>
416: * equals
417: * </p>
418: *
419: * @see java.lang.Object#equals(java.lang.Object)
420: * @param obj
421: * @return
422: */
423: public boolean equals(Object obj) {
424: if (obj != null && obj instanceof PrefsPreference
425: && name != null) {
426: PrefsPreference pref = (PrefsPreference) obj;
427: return pref.name != null && this .name.equals(pref.name);
428:
429: } else {
430: return false;
431: }
432:
433: }
434:
435: /**
436: * <p>
437: * hashCode
438: * </p>
439: *
440: * @see java.lang.Object#hashCode()
441: * @return
442: */
443: public int hashCode() {
444: return (getClass().getName() + "::" + name).hashCode();
445: }
446:
447: /**
448: * <p>
449: * toString
450: * </p>
451: *
452: * @see java.lang.Object#toString()
453: * @return
454: */
455: public String toString() {
456: return "Preference{" + name + "} values="
457: + getValueArray().toString();
458: }
459:
460: /**
461: *
462: */
463: public void flush() throws BackingStoreException {
464: prefValueNode.flush();
465: }
466:
467: /**
468: * <p>
469: * getDescriptions
470: * </p>
471: *
472: * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getDescriptions()
473: * @return
474: */
475: public Iterator getDescriptions() {
476: try {
477: Preferences descNode = prefNode.node("description");
478:
479: String[] keys = descNode.keys();
480: ArrayList descs = new ArrayList(keys.length);
481: for (int i = 0; i < keys.length; i++) {
482: PreferenceDescriptionImpl desc = new PreferenceDescriptionImpl();
483: String localeKey = keys[i];
484: desc.setDescription(descNode.get(localeKey, null));
485: Locale locale = parseLocal(localeKey);
486: desc.setLocale(locale);
487: desc.setLanguage(locale.getLanguage());
488: descs.add(desc);
489: }
490:
491: return descs.iterator();
492: } catch (BackingStoreException e) {
493: String msg = "Preference backing store failed: "
494: + e.toString();
495: IllegalStateException ise = new IllegalStateException(msg);
496: ise.initCause(e);
497: throw ise;
498: }
499: }
500:
501: /**
502: *
503: * <p>
504: * createPrefenceNode
505: * </p>
506: *
507: * Creates a Preferences object for this portlet
508: *
509: * @param portlet
510: * @return
511: */
512:
513: public static Preferences createPrefenceNode(
514: PortletDefinitionComposite portlet) {
515: MutablePortletApplication app = (MutablePortletApplication) portlet
516: .getPortletApplicationDefinition();
517: if (app == null) {
518: throw new IllegalArgumentException(
519: "createPrefencePath() requires a PortletDefinition whose Application is not null.");
520: }
521: String portletDefPrefPath = MutablePortletApplication.PREFS_ROOT
522: + "/"
523: + app.getName()
524: + "/"
525: + PortletDefinitionComposite.PORTLETS_PREFS_ROOT
526: + "/"
527: + portlet.getName()
528: + "/"
529: + PrefsPreference.PORTLET_PREFERENCES_ROOT;
530:
531: return Preferences.systemRoot().node(portletDefPrefPath);
532: }
533: }
|