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.components.portletentity;
18  
19  import java.io.IOException;
20  import java.security.Principal;
21  import java.util.Arrays;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.ArrayList;
26  import java.util.Locale;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.prefs.BackingStoreException;
30  import java.util.prefs.Preferences;
31  
32  import javax.portlet.PortletMode;
33  
34  import org.apache.jetspeed.JetspeedActions;
35  import org.apache.jetspeed.aggregator.RenderTrackable;
36  import org.apache.jetspeed.components.persistence.store.PersistenceStore;
37  import org.apache.jetspeed.components.persistence.store.PersistenceStoreRuntimeExcpetion;
38  import org.apache.jetspeed.components.persistence.store.RemovalAware;
39  import org.apache.jetspeed.components.portletregistry.PortletRegistry;
40  import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
41  import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
42  import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
43  import org.apache.jetspeed.om.common.portlet.PrincipalAware;
44  import org.apache.jetspeed.om.page.Fragment;
45  import org.apache.jetspeed.om.portlet.impl.FragmentPortletDefinition;
46  import org.apache.jetspeed.om.preference.FragmentPreference;
47  import org.apache.jetspeed.om.preference.impl.PrefsPreference;
48  import org.apache.jetspeed.om.preference.impl.PrefsPreferenceSetImpl;
49  import org.apache.jetspeed.om.window.impl.PortletWindowListImpl;
50  import org.apache.jetspeed.page.PageManager;
51  import org.apache.jetspeed.request.RequestContext;
52  import org.apache.jetspeed.request.RequestContextComponent;
53  import org.apache.jetspeed.util.JetspeedObjectID;
54  import org.apache.pluto.om.common.Description;
55  import org.apache.pluto.om.common.ObjectID;
56  import org.apache.pluto.om.common.Preference;
57  import org.apache.pluto.om.common.PreferenceSet;
58  import org.apache.pluto.om.entity.PortletApplicationEntity;
59  import org.apache.pluto.om.portlet.PortletDefinition;
60  import org.apache.pluto.om.window.PortletWindow;
61  import org.apache.pluto.om.window.PortletWindowList;
62  import org.apache.pluto.util.StringUtils;
63  
64  /***
65   * Portlet Entity default implementation.
66   * 
67   * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
68   * @author <a href="mailto:weaver@apache.org">Scott T. Weaver </a>
69   * @version $Id: PortletEntityImpl.java,v 1.9 2005/04/29 13:59:08 weaver Exp $
70   */
71  public class PortletEntityImpl implements MutablePortletEntity, PrincipalAware, RemovalAware, RenderTrackable
72  {   
73      private long oid;
74      private JetspeedObjectID id;
75      protected static PortletEntityAccessComponent pac;    
76      protected static PortletRegistry registry;
77      protected static RequestContextComponent rcc;
78      protected static PageManager pm;
79      
80      protected PrefsPreferenceSetImpl pagePreferenceSet;
81      protected Map perPrincipalPrefs = new HashMap();
82      protected Map originalValues;
83      private PortletApplicationEntity applicationEntity = null;
84      private PortletWindowList portletWindows = new PortletWindowListImpl();
85      private PortletDefinitionComposite portletDefinition = null;  
86      protected String portletName;
87      protected String appName;
88      private boolean dirty = false;
89      private Fragment fragment;
90      private ThreadLocal fragmentPortletDefinition = new ThreadLocal();
91      
92      protected transient int timeoutCount = 0;
93      protected transient long expiration = 0;
94      
95      public PortletEntityImpl(Fragment fragment)
96      {
97          setFragment(fragment);
98      }
99  
100     public PortletEntityImpl()
101     {
102         super();
103     }
104 
105     public static final String NO_PRINCIPAL = "no-principal";
106     public static final String ENTITY_DEFAULT_PRINCIPAL = "entity-default";
107 
108     public ObjectID getId()
109     {
110         return id;
111     }
112 
113     public long getOid()
114     {
115         return oid;
116     }
117 
118     public void setId( String id )
119     {
120         this.id = JetspeedObjectID.createFromString(id);
121     }
122 
123     /***
124      * 
125      * <p>
126      * getPreferenceSet
127      * </p>
128      * 
129      * @see org.apache.pluto.om.entity.PortletEntity#getPreferenceSet()
130      * @return
131      */
132     public PreferenceSet getPreferenceSet()
133     {
134         if (isEditDefaultsMode())
135         {
136             return getPreferenceSetFromPage();
137         }
138         else
139         {
140             Principal currentUser = getPrincipal();
141             return getPreferenceSet(currentUser);
142         }
143     }
144 
145     public PreferenceSet getPreferenceSet(Principal principal)
146     {
147         PrefsPreferenceSetImpl preferenceSet = (PrefsPreferenceSetImpl) perPrincipalPrefs.get(principal);
148         try
149         {
150             if (preferenceSet == null || !dirty)
151             {
152                 String prefNodePath = MutablePortletEntity.PORTLET_ENTITY_ROOT + "/" + getId() +"/"+ principal.getName() +"/"
153                         + PrefsPreference.PORTLET_PREFERENCES_ROOT;
154                 Preferences prefNode = Preferences.userRoot().node(prefNodePath);               
155                 preferenceSet = new PrefsPreferenceSetImpl(prefNode);
156                 perPrincipalPrefs.put(principal, preferenceSet);
157                 if (pac.isMergeSharedPreferences())
158                 {
159                     mergePreferencesSet(preferenceSet);
160                 }
161                 backupValues(preferenceSet);
162                 dirty = true;
163             }
164         }
165         catch (BackingStoreException e)
166         {
167             String msg = "Preference backing store failed: " + e.toString();
168             IllegalStateException ise = new IllegalStateException(msg);
169             ise.initCause(e);
170             throw ise;
171         }
172         return preferenceSet;
173     }
174     
175     private PreferenceSet getPreferenceSetFromPage()
176     {
177         PrefsPreferenceSetImpl preferenceSet = this.pagePreferenceSet;
178         
179         try
180         {
181             if (preferenceSet == null || !dirty)
182             {
183                 String prefNodePath = MutablePortletEntity.PORTLET_ENTITY_ROOT + "/" + 
184                                             getId() +"/"+ PrefsPreference.PORTLET_PREFERENCES_ROOT;
185 
186                 Preferences prefNode = Preferences.systemRoot().node(prefNodePath);
187                 preferenceSet = new PrefsPreferenceSetImpl(prefNode);
188                 this.pagePreferenceSet = preferenceSet;
189                 
190                 List fragmentPreferences = this.fragment.getPreferences();
191                 
192                 if (fragmentPreferences != null)
193                 {
194                     for (Iterator it = fragmentPreferences.iterator(); it.hasNext(); )
195                     {
196                         FragmentPreference preference = (FragmentPreference) it.next();
197                         List preferenceValues = preference.getValueList();
198                         preferenceSet.add(preference.getName(), preferenceValues);
199                     }
200                 }
201                 
202                 backupValues(preferenceSet);
203                 dirty = true;
204             }
205         }
206         catch (BackingStoreException e)
207         {
208             String msg = "Preference backing store failed: " + e.toString();
209             IllegalStateException ise = new IllegalStateException(msg);
210             ise.initCause(e);
211             throw ise;
212         }
213         return preferenceSet;
214     }
215     
216     private void mergePreferencesSet(PrefsPreferenceSetImpl userPrefSet)
217     throws BackingStoreException
218     {
219         String sharedNodePath = MutablePortletEntity.PORTLET_ENTITY_ROOT + "/" + 
220                                 getId() +"/"+ NO_PRINCIPAL +"/" +
221                                 PrefsPreference.PORTLET_PREFERENCES_ROOT;                
222         Preferences sharedNode = Preferences.userRoot().node(sharedNodePath);     
223         if (sharedNode == null)
224             return;
225         PrefsPreferenceSetImpl sharedSet = new PrefsPreferenceSetImpl(sharedNode);
226         if (sharedSet.size() == 0)
227             return;
228         Set names = userPrefSet.getNames();
229         Iterator sharedPrefs = sharedSet.iterator();
230         int index = 0;
231         while (sharedPrefs.hasNext())
232         {
233             PrefsPreference sharedPref = (PrefsPreference) sharedPrefs.next();
234 // this seems limiting, removing if (names.contains(sharedPref.getName()))
235             List prefs = Arrays.asList(sharedPref.getValueArray());
236             userPrefSet.add(sharedPref.getName(), prefs);
237             index++;
238         }        
239     }
240 
241     /***
242      * <p>
243      * backupValues
244      * </p>
245      * 
246      *  
247      */
248     protected void backupValues( PreferenceSet preferenceSet )
249     {
250         originalValues = new HashMap();
251         Iterator itr = preferenceSet.iterator();
252         while (itr.hasNext())
253         {
254             PrefsPreference pref = (PrefsPreference) itr.next();
255 
256             String[] currentValues = pref.getValueArray();
257             String[] backUp = new String[currentValues.length];
258             System.arraycopy(currentValues, 0, backUp, 0, currentValues.length);
259             originalValues.put(pref.getName(), backUp);
260 
261         }
262     }
263 
264     public PortletDefinition getPortletDefinition()
265     {
266         // there are cases when jetspeed gets initialized before
267         // all of the portlet web apps have.  In this event, premature
268         // access to the portal would cause portlet entities to be cached
269         // with their associated window without there corresponding PortletDefinition
270         // (becuase the PortletApplication has yet to be registered).
271         if(this.portletDefinition == null)
272         {
273             PortletDefinition pd = registry.getPortletDefinitionByIdentifier(getPortletUniqueName());
274             if ( pd != null )
275             {
276               // only store a really found PortletDefinition
277               // to prevent an IllegalArgumentException to be thrown
278               setPortletDefinition(pd);
279             }
280             else
281             {
282                 return null;
283             }
284         }        
285         
286         // Wrap the portlet defintion every request thread
287         PortletDefinition fpd = (PortletDefinition)fragmentPortletDefinition.get();
288         if (fpd == null)
289         {
290             fpd = new FragmentPortletDefinition(this.portletDefinition, fragment);
291             fragmentPortletDefinition.set(fpd);
292         }        
293         return fpd;
294     }
295 
296     public PortletApplicationEntity getPortletApplicationEntity()
297     {
298         return applicationEntity;
299     }
300 
301     public PortletWindowList getPortletWindowList()
302     {
303         return portletWindows;
304     }
305 
306     /***
307      * 
308      * <p>
309      * store
310      * </p>
311      *  
312      */
313     public void store() throws IOException
314     {
315         if (isEditDefaultsMode())
316         {
317             storeToPage();
318         }
319         else
320         {
321             Principal currentUser = getPrincipal();
322             store(currentUser);
323         }
324     }
325     
326     public void store(Principal principal) throws IOException
327     {
328         if (pac == null)
329         {
330             throw new IllegalStateException("You must call PortletEntityImpl.setPorteltEntityDao() before "
331                     + "invoking PortletEntityImpl.store().");
332         }
333 
334         PreferenceSet preferenceSet = (PreferenceSet)perPrincipalPrefs.get(principal);
335         pac.storePreferenceSet(preferenceSet, this);
336         dirty = false;
337         if (preferenceSet != null)
338         {
339             backupValues(preferenceSet);
340         }
341     }
342     
343     private void storeToPage() throws IOException
344     {
345         if (pm == null)
346         {
347             throw new IllegalStateException("You must set pageManager before "
348                     + "invoking PortletEntityImpl.store().");
349         }
350         
351         PreferenceSet preferenceSet = this.pagePreferenceSet;
352         List preferences = new ArrayList();
353         
354         for (Iterator it = preferenceSet.iterator(); it.hasNext(); )
355         {
356             Preference pref = (Preference) it.next();
357             
358             FragmentPreference preference = pm.newFragmentPreference();
359             preference.setName(pref.getName());
360             List preferenceValues = new ArrayList();
361             
362             for (Iterator iterVals = pref.getValues(); iterVals.hasNext(); )
363             {
364                 preferenceValues.add(iterVals.next());
365             }
366             
367             preference.setValueList(preferenceValues);
368             preferences.add(preference);
369         }
370         
371         this.fragment.setPreferences(preferences);
372         
373         try
374         {
375             pm.updatePage(rcc.getRequestContext().getPage());
376         }
377         catch (Exception e)
378         {
379         }
380         
381         dirty = false;
382         if (preferenceSet != null)
383         {
384             backupValues(preferenceSet);
385         }
386     }
387 
388     /***
389      * 
390      * <p>
391      * reset
392      * </p>
393      *  
394      */
395 
396     public void reset() throws IOException
397     {
398         PrefsPreferenceSetImpl preferenceSet = (PrefsPreferenceSetImpl) perPrincipalPrefs.get(getPrincipal());
399         try
400         {
401             if (originalValues != null && preferenceSet != null)
402             {
403                 Iterator prefs = preferenceSet.iterator();
404 
405                 while (prefs.hasNext())
406                 {
407                     PrefsPreference pref = (PrefsPreference) prefs.next();
408                     if (originalValues.containsKey(pref.getName()))
409                     {
410                         pref.setValues((String[]) originalValues.get(pref.getName()));
411                     }
412                     else
413                     {
414                         preferenceSet.remove(pref);
415                     }
416                     preferenceSet.flush();
417                 }
418 
419                 Iterator keys = originalValues.keySet().iterator();
420                 while (keys.hasNext())
421                 {
422                     String key = (String) keys.next();
423                     if (preferenceSet.get(key) == null)
424                     {
425                         preferenceSet.add(key, Arrays.asList((String[]) originalValues.get(key)));
426                     }
427                 }
428             }
429             dirty = false;
430             backupValues(preferenceSet);
431         }
432         catch (BackingStoreException e)
433         {
434             String msg = "Preference backing store failed: " + e.toString();
435             IOException ioe = new IOException(msg);
436             ioe.initCause(e);
437             throw ioe;
438         }
439 
440     }
441 
442     // internal methods used for debugging purposes only
443 
444     public String toString()
445     {
446         return toString(0);
447     }
448 
449     public String toString( int indent )
450     {
451         StringBuffer buffer = new StringBuffer(1000);
452         StringUtils.newLine(buffer, indent);
453         buffer.append(getClass().toString());
454         buffer.append(":");
455         StringUtils.newLine(buffer, indent);
456         buffer.append("{");
457         StringUtils.newLine(buffer, indent);
458         buffer.append("id='");
459         buffer.append(oid);
460         buffer.append("'");
461         StringUtils.newLine(buffer, indent);
462         buffer.append("definition-id='");
463         if(portletDefinition != null)
464         {
465             buffer.append(portletDefinition.getId().toString());
466         }
467         else
468         {
469             buffer.append("null");
470         }
471         buffer.append("'");
472 
473         StringUtils.newLine(buffer, indent);
474         //buffer.append(((PreferenceSetImpl)preferences).toString(indent));
475 
476         StringUtils.newLine(buffer, indent);
477         buffer.append("}");
478         return buffer.toString();
479     }
480 
481     /***
482      * @see org.apache.pluto.om.entity.PortletEntity#getDescription(java.util.Locale)
483      */
484     public Description getDescription( Locale arg0 )
485     {
486         return portletDefinition.getDescription(arg0);
487     }
488 
489     /***
490      * <p>
491      * setPortletDefinition
492      * </p>
493      * 
494      * @param composite
495      *  
496      */
497     public void setPortletDefinition( PortletDefinition composite )
498     {
499         if(composite != null)
500         {
501             portletDefinition = (PortletDefinitionComposite) composite;
502             // if the portletDefinition is modified, clear threadlocal fragmentPortletDefinition cache
503             fragmentPortletDefinition.set(null);
504             this.appName = ((MutablePortletApplication)portletDefinition.getPortletApplicationDefinition()).getName();
505             this.portletName = portletDefinition.getName();
506         }
507         else
508         {
509             throw new IllegalArgumentException("Cannot pass a null PortletDefinition to a PortletEntity.");
510         }
511     }
512 
513     /***
514      * @return Returns the principal.
515      */
516     public Principal getPrincipal()
517     {
518         if (rcc == null)
519         {
520             return new PortletEntityUserPrincipal(NO_PRINCIPAL);
521         }            
522         RequestContext rc = rcc.getRequestContext();
523         Principal principal = rc.getUserPrincipal();
524         if (principal == null)
525         {
526             principal = new PortletEntityUserPrincipal(NO_PRINCIPAL);
527         }
528         return principal;
529     }
530 
531     class PortletEntityUserPrincipal implements Principal
532     {
533         String name;
534 
535         protected PortletEntityUserPrincipal( String name )
536         {
537             this.name = name;
538         }
539 
540         /***
541          * <p>
542          * getName
543          * </p>
544          * 
545          * @see java.security.Principal#getName()
546          * @return
547          */
548         public String getName()
549         {
550             return name;
551         }
552 
553         /***
554          * <p>
555          * equals
556          * </p>
557          * 
558          * @see java.lang.Object#equals(java.lang.Object)
559          * @param obj
560          * @return
561          */
562         public boolean equals( Object obj )
563         {
564             if (obj != null && obj instanceof Principal)
565             {
566                 Principal p = (Principal) obj;
567                 return name != null && p.getName() != null && name.equals(p.getName());
568             }
569             else
570             {
571                 return false;
572             }
573         }
574 
575         /***
576          * <p>
577          * hashCode
578          * </p>
579          * 
580          * @see java.lang.Object#hashCode()
581          * @return
582          */
583         public int hashCode()
584         {
585             if (name != null)
586             {
587                 return (getClass().getName()+ ":" + name).hashCode();
588             }
589             else
590             {
591                 return -1;
592             }
593         }
594 
595         /***
596          * <p>
597          * toString
598          * </p>
599          * 
600          * @see java.lang.Object#toString()
601          * @return
602          */
603         public String toString()
604         {
605             return name;
606         }
607     }
608     /***
609      * <p>
610      * postRemoval
611      * </p>
612      *
613      * @see org.apache.jetspeed.components.persistence.store.RemovalAware#postRemoval(org.apache.jetspeed.components.persistence.store.PersistenceStore)
614      * @param store
615      * @throws {@link org.apache.jetspeed.persistence.store.PersistenceStoreRuntimeExcpetion}
616      * if the removal of the {@link java.util.prefs.Preference} related to this entity fails
617      */
618     public void postRemoval( PersistenceStore store )
619     {
620       
621 
622     }
623     /***
624      * <p>
625      * preRemoval
626      * </p>
627      *	not implemented.
628      *
629      * @see org.apache.jetspeed.components.persistence.store.RemovalAware#preRemoval(org.apache.jetspeed.components.persistence.store.PersistenceStore)
630      * @param store
631      */
632     public void preRemoval( PersistenceStore store )
633     {
634         String rootForEntity = MutablePortletEntity.PORTLET_ENTITY_ROOT + "/" + getId();
635         try
636         {
637             if(Preferences.userRoot().nodeExists(rootForEntity))
638             {
639                 Preferences.userRoot().node(rootForEntity).removeNode();
640             }
641         }
642         catch (BackingStoreException e)
643         {           
644             throw new PersistenceStoreRuntimeExcpetion(e.toString(), e);
645         }        
646 
647     }
648     public String getPortletUniqueName()
649     {
650         if(this.appName != null && this.portletName != null)
651         {
652             return this.appName+"::"+this.portletName;
653         }
654         else if(fragment != null)
655         {
656             return fragment.getName();
657         }
658         else
659         {
660             return null;
661         }
662     }
663 
664     public void setFragment(Fragment fragment)
665     {
666         this.fragment = fragment;
667         // if the fragment is set, clear threadlocal fragmentPortletDefinition cache
668         fragmentPortletDefinition.set(null);
669     }
670 
671     public int getRenderTimeoutCount()
672     {
673         return timeoutCount;
674     }
675     
676     public synchronized void incrementRenderTimeoutCount()
677     {
678         timeoutCount++;
679     }
680     
681     public synchronized void setExpiration(long expiration)
682     {
683         this.expiration = expiration;
684     }
685     
686     public long getExpiration()
687     {
688         return this.expiration;
689     }
690     
691     public void success()
692     {
693         timeoutCount = 0;
694     }
695     
696     public void setRenderTimeoutCount(int timeoutCount)
697     {
698         this.timeoutCount = timeoutCount;
699     }
700 
701     private boolean isEditDefaultsMode()
702     {
703         boolean editDefaultsMode = false;
704         
705         PortletWindow curWindow = null;
706         
707         if (this.portletWindows != null)
708         {
709             try
710             {
711                 curWindow = (PortletWindow) this.portletWindows.iterator().next();
712             }
713             catch (Exception e)
714             {
715             }
716         }
717         
718         if (rcc != null)
719         {
720             RequestContext context = rcc.getRequestContext();
721             
722             try
723             {
724                 PortletMode curMode = context.getPortalURL().getNavigationalState().getMode(curWindow);
725                 editDefaultsMode = (JetspeedActions.EDIT_DEFAULTS_MODE.equals(curMode));
726             }
727             catch (Exception e)
728             {
729             }
730         }
731         
732         return editDefaultsMode;
733     }
734 }