View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.om.preference.impl;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Locale;
24  import java.util.StringTokenizer;
25  import java.util.prefs.BackingStoreException;
26  import java.util.prefs.Preferences;
27  
28  import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
29  import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
30  import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
31  import org.apache.jetspeed.om.common.preference.PreferenceComposite;
32  import org.apache.jetspeed.om.impl.PreferenceDescriptionImpl;
33  import org.apache.pluto.om.common.Description;
34  
35  
36  public class PrefsPreference implements PreferenceComposite
37  {
38      protected static final String VALUES_PATH = "values";
39      protected static final String VALUES_SIZE = "size";
40    
41      public static final String PORTLET_PREFERENCES_ROOT = "preferences";
42      protected static final String LOCALE_TOKEN = "_";
43      protected Preferences prefValueNode;
44      protected Preferences prefValueSizeNode;
45      protected Preferences prefNode;
46      protected String name;
47      public static final String[] DEFAULT_OPEN_NODES = new String[] {MutablePortletEntity.PORTLET_ENTITY_ROOT, PortletDefinitionComposite.PORTLETS_PREFS_ROOT};
48  
49      
50      
51      public PrefsPreference(Preferences prefNode, String name)
52      {
53          super();
54          this.prefNode = prefNode;
55          if(prefNode == null)
56          {
57              throw new IllegalArgumentException("prefNode cannot be null for PrefsPreferences(Preference).");
58          }
59                  
60          this.name = name;
61          if(this.name == null)
62          {
63              throw new IllegalArgumentException("Preference does requires a \"name\" property.");
64          }
65          
66          this.prefValueNode = prefNode.node(VALUES_PATH);
67          this.prefValueSizeNode = prefNode.node(VALUES_SIZE);
68      }
69      
70      public PrefsPreference(PortletDefinitionComposite portlet, String name)
71      {
72          this(createPrefenceNode(portlet).node(name), name);
73      }
74  
75      
76      private int getPrefValueSize(boolean store)
77      {
78          int size = prefValueSizeNode.getInt(VALUES_SIZE, -1);
79          if ( size == -1 )
80          {
81              // prefSizeNode doesn't exist
82              // if values exists (upgrading issue), determine from number of values keys
83              try
84              {
85                  size = prefValueNode.keys().length;
86              }
87              catch (BackingStoreException e)
88              {
89                  String msg = "Preference backing store failed: "+e.toString();
90                  IllegalStateException ise = new IllegalStateException(msg);
91                  ise.initCause(e);
92                  throw ise;
93              }
94              if (store)
95              {
96                  prefValueSizeNode.putInt(VALUES_SIZE,size);
97              }
98          }
99          return size;
100     }
101     
102     /***
103      * <p>
104      * addDescription
105      * </p>
106      * 
107      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#addDescription(java.util.Locale,
108      *          java.lang.String)
109      * @param locale
110      * @param Description
111      */
112     public void addDescription( Locale locale, String description )
113     {
114         String localePath = locale.toString();
115         prefNode.node("description").put(localePath, description);
116     }
117 
118     /***
119      * <p>
120      * getDescription
121      * </p>
122      * 
123      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getDescription(java.util.Locale)
124      * @param locale
125      * @return
126      */
127     public Description getDescription( Locale locale )
128     {
129         String localePath = locale.toString();
130         String value = prefNode.node("description").get(localePath, null);
131         PreferenceDescriptionImpl desc = new PreferenceDescriptionImpl();
132         desc.setDescription(value);
133         desc.setLocale(locale);
134         desc.setLanguage(locale.getLanguage());
135         return desc;
136     }
137 
138     /***
139      * <p>
140      * getValueAt
141      * </p>
142      * 
143      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getValueAt(int)
144      * @param index
145      * @return
146      */
147     public String getValueAt( int index )
148     {
149         return prefValueNode.get(String.valueOf(index), null);
150     }
151     
152     public void removeValueAt(int index)
153     {
154         int size;
155         if (index > -1 && index < (size = getPrefValueSize(true)) )
156         {
157             String[] values = new String[size-1];
158             for (int i = 0; i < index; i++)
159             {
160                 values[i] = prefValueNode.get(String.valueOf(i),null);
161             }
162             for ( int i = index+1; i < size; i++)
163             {
164                 values[i] = prefValueNode.get(String.valueOf(i),null);
165             }
166             setValues(values);
167         }
168         else
169             throw new IndexOutOfBoundsException();
170     }
171 
172     /***
173      * <p>
174      * setValueAt
175      * </p>
176      * 
177      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#setValueAt(int,
178      *          java.lang.String)
179      * @param index
180      * @param value
181      */
182     public void setValueAt( int index, String value )
183     {
184         if ( index > -1 )
185         {
186             int size = getPrefValueSize(true);
187             if ( index < size )
188             {
189                 if ( value != null )
190                 {
191                     prefValueNode.put(String.valueOf(index), value);
192                 }
193                 else
194                 {
195                     prefValueNode.remove(String.valueOf(index));
196                 }
197             }
198             else
199             {
200                 prefValueSizeNode.putInt(VALUES_SIZE, index+1);
201                 if ( value != null )
202                 {
203                     prefValueNode.put(String.valueOf(index),value);
204                 }
205             }
206             
207         }
208         else
209             throw new IndexOutOfBoundsException();
210     }
211 
212     /***
213      * <p>
214      * addValue
215      * </p>
216      * 
217      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#addValue(java.lang.String)
218      * @param value
219      */
220     public void addValue( String value )
221     {
222        int size = getPrefValueSize(true);
223        prefValueSizeNode.putInt(VALUES_SIZE, size+1);
224        if ( value != null )
225        {
226            prefValueNode.put(String.valueOf(size),value);
227        }
228     }
229 
230     /***
231      * <p>
232      * getValueArray
233      * </p>
234      * 
235      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getValueArray()
236      * @return
237      */
238     public String[] getValueArray()
239     {
240         int size = getPrefValueSize(false);
241         String[] values = new String[size];
242         for (int i = 0; i < size; i++)
243         {
244             values[i] = prefValueNode.get(String.valueOf(i),null);
245         }
246         return values;
247     }
248 
249     /***
250      * <p>
251      * setValues
252      * </p>
253      * 
254      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#setValues(java.lang.String[])
255      * @param stringValues
256      */
257     public void setValues( String[] stringValues )
258     {
259         try
260         {
261             prefValueNode.clear();
262             int size = stringValues != null ? stringValues.length : 0;
263             prefValueSizeNode.putInt(VALUES_SIZE, size);
264             for (int i = 0; i < size; i++)
265             {
266                 if (stringValues[i] != null)
267                 {
268                     prefValueNode.put(String.valueOf(i), stringValues[i]);
269                 }
270             }
271         }
272         catch (BackingStoreException e)
273         {
274             String msg = "Preference backing store failed: "+e.toString();
275             IllegalStateException ise = new IllegalStateException(msg);
276             ise.initCause(e);
277             throw ise;
278         }
279     }
280 
281     /***
282      * <p>
283      * getType
284      * </p>
285      * 
286      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getType()
287      * @return
288      */
289     public String getType()
290     {
291         // TODO Auto-generated method stub
292         return null;
293     }
294 
295     /***
296      * <p>
297      * setType
298      * </p>
299      * 
300      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#setType(java.lang.String)
301      * @param string
302      */
303     public void setType( String string )
304     {
305         // TODO Auto-generated method stub
306 
307     }
308 
309     /***
310      * <p>
311      * setName
312      * </p>
313      * 
314      * @see org.apache.pluto.om.common.PreferenceCtrl#setName(java.lang.String)
315      * @param arg0
316      */
317     public void setName( String name )
318     {
319         this.name = name;
320 
321     }
322 
323     /***
324      * <p>
325      * setValues
326      * </p>
327      * 
328      * @see org.apache.pluto.om.common.PreferenceCtrl#setValues(java.util.List)
329      * @param arg0
330      */
331     public void setValues( List arg0 )
332     {
333         if (arg0 != null)
334         {
335             setValues((String[]) arg0.toArray(new String[arg0.size()]));
336         }
337 
338     }
339 
340     /***
341      * <p>
342      * setReadOnly
343      * </p>
344      * 
345      * @see org.apache.pluto.om.common.PreferenceCtrl#setReadOnly(java.lang.String)
346      * @param arg0
347      */
348     public void setReadOnly( String readOnly )
349     {
350         prefNode.put("read_only", readOnly);
351 
352     }
353     
354     public void setReadOnly( boolean readOnly )
355     {
356         if(readOnly)
357         {
358             prefNode.put("read_only", "true");
359         }
360         else
361         {
362             prefNode.put("read_only", "false");
363         }
364 
365     }
366 
367     /***
368      * <p>
369      * getName
370      * </p>
371      * 
372      * @see org.apache.pluto.om.common.Preference#getName()
373      * @return
374      */
375     public String getName()
376     {
377         return name;
378     }
379 
380     /***
381      * <p>
382      * getValues
383      * </p>
384      * 
385      * @see org.apache.pluto.om.common.Preference#getValues()
386      * @return
387      */
388     public Iterator getValues()
389     {
390         return Arrays.asList(getValueArray()).iterator();
391     }
392 
393     /***
394      * <p>
395      * isReadOnly
396      * </p>
397      * 
398      * @see org.apache.pluto.om.common.Preference#isReadOnly()
399      * @return
400      */
401     public boolean isReadOnly()
402     {
403         return Boolean.valueOf(prefNode.get("read_only", "false")).booleanValue();
404     }
405 
406     /***
407      * <p>
408      * isValueSet
409      * </p>
410      * 
411      * @see org.apache.pluto.om.common.Preference#isValueSet()
412      * @return
413      */
414     public boolean isValueSet()
415     {
416         return getPrefValueSize(false) > 0;
417     }
418 
419     protected Locale parseLocal( String localString )
420     {
421         StringTokenizer lcTk = new StringTokenizer(localString, LOCALE_TOKEN);
422         String lang = null;
423         String country = null;
424         String variant = null;
425         while (lcTk.hasMoreTokens())
426         {
427             if (lang == null)
428             {
429                 lang = lcTk.nextToken();
430             }
431             else if (country == null)
432             {
433                 country = lcTk.nextToken();
434             }
435             else if (variant == null)
436             {
437                 variant = lcTk.nextToken();
438             }
439         }
440 
441         return new Locale(lang, country, variant);
442     }
443     
444   
445     /***
446      * <p>
447      * clone
448      * </p>
449      * 
450      * @see java.lang.Object#clone()
451      * @return @throws
452      *              java.lang.CloneNotSupportedException
453      */
454     public String[] cloneValues()
455     {
456     	String[] clonedValues;
457     	synchronized (prefValueNode)
458         {
459             String[] currentValues = getValueArray();
460             clonedValues = new String[currentValues.length];
461 
462             System.arraycopy(currentValues, 0, clonedValues, 0, currentValues.length);
463         }
464 
465         return clonedValues;
466     }
467 
468     /***
469      * <p>
470      * equals
471      * </p>
472      * 
473      * @see java.lang.Object#equals(java.lang.Object)
474      * @param obj
475      * @return
476      */
477     public boolean equals( Object obj )
478     {
479         if (obj != null && obj instanceof PrefsPreference && name != null)
480         {
481             PrefsPreference pref = (PrefsPreference) obj;
482             return pref.name != null && this.name.equals(pref.name);
483 
484         }
485         else
486         {
487             return false;
488         }
489 
490     }
491 
492     /***
493      * <p>
494      * hashCode
495      * </p>
496      * 
497      * @see java.lang.Object#hashCode()
498      * @return
499      */
500     public int hashCode()
501     {        
502         return (getClass().getName()+"::"+name).hashCode();
503     }
504 
505     /***
506      * <p>
507      * toString
508      * </p>
509      * 
510      * @see java.lang.Object#toString()
511      * @return
512      */
513     public String toString()
514     {
515         return "Preference{"+name+"} values="+getValueArray().toString();
516     }
517     
518     /***
519      *
520      */
521     public void flush() throws BackingStoreException
522     {
523         prefValueNode.flush();
524     }
525     /***
526      * <p>
527      * getDescriptions
528      * </p>
529      *
530      * @see org.apache.jetspeed.om.common.preference.PreferenceComposite#getDescriptions()
531      * @return
532      */
533     public Iterator getDescriptions()
534     {
535         try
536         {
537             Preferences descNode = prefNode.node("description");
538            
539             String[] keys = descNode.keys();
540             ArrayList descs = new ArrayList(keys.length);
541             for(int i=0; i < keys.length; i++)
542             {
543                 PreferenceDescriptionImpl desc = new PreferenceDescriptionImpl();
544                 String localeKey = keys[i];
545                 desc.setDescription(descNode.get(localeKey, null));
546                 Locale locale = parseLocal(localeKey);
547                 desc.setLocale(locale);
548                 desc.setLanguage(locale.getLanguage());
549                 descs.add(desc);
550             }
551             
552             return descs.iterator();
553         }
554         catch (BackingStoreException e)
555         {
556             String msg = "Preference backing store failed: "+e.toString();
557             IllegalStateException ise = new IllegalStateException(msg);
558             ise.initCause(e);
559             throw ise;
560         }
561     }
562     
563     /***
564      * 
565      * <p>
566      * createPrefenceNode
567      * </p>
568      * 
569      * Creates a Preferences object for this portlet
570      *
571      * @param portlet
572      * @return
573      */
574     
575     public static Preferences createPrefenceNode(PortletDefinitionComposite portlet)
576     {
577         MutablePortletApplication app = (MutablePortletApplication) portlet.getPortletApplicationDefinition();
578         if(app == null)
579         {
580             throw new IllegalArgumentException("createPrefencePath() requires a PortletDefinition whose Application is not null.");
581         }
582         String portletDefPrefPath = MutablePortletApplication.PREFS_ROOT + "/" + app.getName() + "/"
583         + PortletDefinitionComposite.PORTLETS_PREFS_ROOT + "/" + portlet.getName() + "/"
584         + PrefsPreference.PORTLET_PREFERENCES_ROOT;
585         
586         return Preferences.systemRoot().node(portletDefPrefPath);
587     }
588 }