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