View Javadoc

1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.jetspeed.modules.actions.controllers;
18  
19  //Jetspeed Stuff
20  import org.apache.jetspeed.om.profile.Profile;
21  import org.apache.jetspeed.om.registry.RegistryEntry;
22  import org.apache.jetspeed.om.profile.Portlets;
23  import org.apache.jetspeed.om.profile.Entry;
24  import org.apache.jetspeed.om.profile.Layout;
25  import org.apache.jetspeed.om.profile.psml.PsmlLayout;
26  import org.apache.jetspeed.portal.PortletSet;
27  import org.apache.jetspeed.portal.PortletController;
28  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
29  import org.apache.jetspeed.services.logging.JetspeedLogger;
30  import org.apache.jetspeed.services.Registry;
31  import org.apache.jetspeed.services.rundata.JetspeedRunData;
32  import org.apache.jetspeed.util.AutoProfile;
33  
34  // Turbine stuff
35  //import org.apache.turbine.util.DynamicURI;
36  import org.apache.turbine.util.RunData;
37  import org.apache.turbine.modules.ActionLoader;
38  
39  // Velocity Stuff
40  import org.apache.velocity.context.Context;
41  
42  // Java stuff
43  import java.util.Vector;
44  import java.util.List;
45  import java.util.StringTokenizer;
46  import java.util.Iterator;
47  import java.util.ArrayList;
48  import java.util.Map;
49  import java.util.HashMap;
50  import java.util.Collections;
51  import java.util.Comparator;
52  
53  /***
54   * This action builds a context suitable for controllers handlings simple
55   * sorted lists of portlets
56   *
57   * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
58   * @author <a href="mailto:paulsp@apache.org">Paul Spencer</a>
59   */
60  public class RowColumnControllerAction extends VelocityControllerAction
61  {
62  
63      /***
64       * Static initialization of the logger for this class
65       */
66      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(RowColumnControllerAction.class.getName());
67      
68      /***
69       * Subclasses must override this method to provide default behavior
70       * for the portlet action
71       */
72      protected void buildNormalContext( PortletController controller,
73                                         Context context,
74                                         RunData rundata )
75      {
76          //retrieve the size for each of the element
77          String sizes = controller.getConfig().getInitParameter("sizes");
78          context.put("sizes", getCellSizes(sizes));
79      }
80  
81      /*** Parses the size config info and returns a list of
82       *  size values for the current set
83       *
84       *  @param sizeList java.lang.String a comma separated string a values
85       *  @return a List of values
86       */
87      public static List getCellSizes(String sizelist)
88      {
89          List list = new Vector();
90  
91          if (sizelist!=null)
92          {
93              StringTokenizer st = new StringTokenizer(sizelist,",");
94              while (st.hasMoreTokens())
95              {
96                  list.add(st.nextToken());
97              }
98          }
99  
100         return list;
101     }
102 
103     /***
104      * Adds a "pane" portlet object in the context which represents the
105      * currently selected pane
106      */
107     protected void buildCustomizeContext( PortletController controller,
108                                        Context context,
109                                        RunData rundata )
110     {
111         super.buildCustomizeContext(controller, context, rundata);
112 
113         JetspeedRunData jdata = (JetspeedRunData)rundata;
114         PortletSet set = (PortletSet)jdata.getCustomized();
115 
116         Portlets portlets = jdata.getCustomizedProfile()
117                                  .getDocument()
118                                  .getPortletsById(set.getID());
119 
120         List plist = new ArrayList();
121         List work = new ArrayList();
122         List filler = Collections.nCopies(portlets.getPortletsCount()+portlets.getEntryCount(),null);
123         plist.addAll(filler);
124 
125         for (int i=0; i < portlets.getPortletsCount(); i++)
126         {
127             Portlets p = portlets.getPortlets(i);
128             if (logger.isDebugEnabled())
129             {
130                 logger.debug("RowColumnControllerAction: processing portlet: " + p.getTitle());
131             }
132             Layout layout = p.getLayout();
133             if (layout == null)
134             {
135                 // Pane should always have a layout with correct position
136                 if (logger.isDebugEnabled())
137                 {
138                     logger.debug("RowColumnControllerAction: no layout, creating a new one");
139                 }
140                 layout = new PsmlLayout();
141                 layout.setPosition(i);
142                 p.setLayout(layout);
143             }
144             if (layout!=null)
145             {
146                 try
147                 {
148                     int pos = (int)layout.getPosition();
149                     if (logger.isDebugEnabled())
150                     {
151                         logger.debug("RowColumnControllerAction: layout has position: " + pos);
152                     }
153                     if (pos >= 0 && pos < plist.size())
154                     {
155                         plist.set(pos,p);
156                     }
157                     else
158                     {
159                         work.add(p);
160                     }
161                 }
162                 catch (Exception e)
163                 {
164                     logger.error("Layout error", e);
165                     layout.setPosition(-1);
166                     work.add(p);
167                 }
168             }
169             else
170             {
171                 work.add(p);
172             }
173         }
174 
175         for (int i=0; i < portlets.getEntryCount(); i++)
176         {
177             Entry p = portlets.getEntry(i);
178             Layout layout = p.getLayout();
179             if (layout!=null)
180             {
181                 try
182                 {
183                     int pos = (int)layout.getPosition();
184                     if (pos>=0)
185                     {
186                         plist.set(pos,p);
187                     }
188                     else
189                     {
190                         work.add(p);
191                     }
192                 }
193                 catch (Exception e)
194                 {
195                     layout.setPosition(-1);
196                     work.add(p);
197                 }
198             }
199             else
200             {
201                 work.add(p);
202             }
203         }
204 
205         Iterator i = work.iterator();
206         for(int idx=0;idx < plist.size(); idx++)
207         {
208             if (plist.get(idx)==null)
209             {
210                 if (i.hasNext())
211                 {
212                     plist.set(idx,i.next());
213                 }
214                 else
215                 {
216                     plist.remove(idx);
217                 }
218             }
219         }
220 
221         Map titles = new HashMap();
222         i = plist.iterator();
223         while(i.hasNext())
224         {
225             Object obj = i.next();
226 
227             if (obj instanceof Portlets)
228             {
229                 Portlets entry = (Portlets)obj;
230                 if ((entry.getMetaInfo()!=null)&&(entry.getMetaInfo().getTitle()!=null))
231                 {
232                     titles.put(entry.getId(),entry.getMetaInfo().getTitle());
233                 }
234             }
235             else
236             {
237                 Entry entry = (Entry)obj;
238                 if ((entry.getMetaInfo()!=null)&&(entry.getMetaInfo().getTitle()!=null))
239                 {
240 				   titles.put(entry.getId(), entry.getMetaInfo().getTitle());
241                 }
242                 else
243                 {
244                     RegistryEntry pentry = Registry.getEntry(Registry.PORTLET,entry.getParent());
245 
246                     if (pentry!=null)
247                     {
248 						titles.put(entry.getId(), pentry.getTitle());
249                     }
250                 }
251             }
252         }
253 
254 
255         context.put("portlets",plist);
256         context.put("titles",titles);
257 
258         /***
259          * Make a list of all used portlets available thru the 'runs' reference
260          * --------------------------------------------------------------------------
261          * last modified: 10/31/01
262          * Andreas Kempf, Siemens ICM S CP PE, Munich
263          * mailto: A.Kempf@web.de
264          */
265         context.put("runs", AutoProfile.getPortletList(rundata));
266         // --------------------------------------------------------------------------
267     }
268 
269     /***
270      * Cancel the current customizations.  If this was the last customization
271      * on the stack, then return the user to the home page.
272      */
273     public void doCancel(RunData data, Context context)
274     {
275          ((JetspeedRunData)data).setCustomized(null);
276 
277         if (((JetspeedRunData)data).getCustomized() == null)
278         {
279             try
280             {
281                 ActionLoader.getInstance().exec( data, "controls.EndCustomize" );
282             }
283             catch (Exception e)
284             {
285                 logger.error("Unable to load action controls.EndCustomize ",e);
286             }
287         }
288     }
289 
290     public void doSave(RunData data, Context context)
291     {
292         doApply(data, context);
293     }
294 
295     public void doApply(RunData data, Context context)
296     {
297         // move one level back in customization
298         ((JetspeedRunData) data).setCustomized(null);
299 
300         // if we are all done customization
301         if (((JetspeedRunData) data).getCustomized() == null)
302         {
303             // save the edit profile and make it current
304             try
305             {
306                 ((JetspeedRunData) data).getCustomizedProfile().store();
307             }
308             catch (Exception e)
309             {
310                 logger.error("Unable to save profile ",e);
311             }
312 
313             try
314             {
315                 ActionLoader.getInstance().exec( data, "controls.EndCustomize" );
316             }
317             catch (Exception e)
318             {
319                 logger.error("Unable to load action controls.EndCustomize ",e);
320             }
321         }
322     }
323 
324     /*** Remove a pane from the current set
325      *  This method expects the following parameters
326      * - paneid: the id a the pane to modify within the current profile
327      * - position: the position of the component to delete
328      */
329     public void doDelete(RunData data, Context context) throws Exception
330     {
331       JetspeedRunData jdata = (JetspeedRunData)data;
332       PortletSet customizedSet = (PortletSet)jdata.getCustomized();
333       int position = data.getParameters().getInt("position",-1);
334       Profile profile = jdata.getCustomizedProfile();
335 
336       // ADDED for WML
337       //boolean isWML = (profile.getMediaType().equalsIgnoreCase("wml"));
338 
339 
340         if (customizedSet == null) return;
341 
342         if (position > -1)
343         {
344             Portlets set = profile.getDocument()
345                                   .getPortletsById(customizedSet.getID());
346             if (set != null)
347             {
348                 // first try explicit portlets position
349                 for(int i=0; i < set.getPortletsCount(); i++)
350                 {
351                     Portlets p = set.getPortlets(i);
352                     Layout layout = p.getLayout();
353 //
354 //                    if (layout == null)
355 //                    {
356 //                      Layout nl = new Layout ();
357 //                      nl.setPosition (String.valueOf(i));
358 //
359 //                    }
360                     if ((layout!=null) && (layout.getPosition() != -1))
361                     {
362 
363                         int lpos = (int)layout.getPosition();
364                         if (lpos==position)
365                         {
366                             set.removePortlets(i);
367 
368                             updateLayoutPositions(set);
369 
370                             // MODIFIED: Save changes for wml profiles
371                             //if (isWML)
372                             //  doSave(data, null);
373 
374                             return;
375                         }
376                     }
377                 }
378 
379                 // try explicit entry position
380                 for(int i=0; i < set.getEntryCount(); i++)
381                 {
382                     Entry p = set.getEntry(i);
383                     Layout layout = p.getLayout();
384 
385                     if ((layout!=null) && (layout.getPosition() != -1))
386                     {
387                         int lpos = (int)layout.getPosition();
388 
389                         if (lpos==position)
390                         {
391                             set.removeEntry(i);
392 
393                             // MODIFIED: Save changes for wml profiles
394                             //if (isWML)
395                             //  doSave(data, null);
396                             return;
397                         }
398                     }
399                 }
400 
401                 //else use implicit position
402                 if (position < set.getPortletsCount())
403                 {
404                     set.removePortlets(position);
405 
406                     // MODIFIED: Save changes for wml profiles
407                     //if (isWML)
408                     //  doSave(data, null);
409                     return;
410                 }
411 
412                 if (position < set.getEntryCount())
413                 {
414                     set.removeEntry(position);
415 
416                     // MODIFIED: Save changes for wml profiles
417                     //if (isWML)
418                     //  doSave(data, null);
419                     return;
420                 }
421             }
422         }
423 
424 
425     }
426 
427     /***
428      * Updates the layout position based on physical order within the resorted portlet list. Assures that 
429      * layout position is always consecutive and within bounds.
430      * 
431      * @param set
432      */
433     private void updateLayoutPositions(Portlets set)
434     {
435         // Load the panes into a list
436         List list = new ArrayList();
437         for(int i = 0; i < set.getPortletsCount(); i++)
438         {
439             Portlets pane = set.getPortlets(i);
440             list.add(pane);
441         }
442 
443         // Sort list using the current layout position
444         Collections.sort(list, 
445                          new Comparator()
446                          {
447                              public int compare(Object pane1, Object pane2)
448                              {
449                                  Long pos1 = new Long(((Portlets) pane1).getLayout().getPosition());
450                                  Long pos2 = new Long(((Portlets) pane2).getLayout().getPosition());
451                                  return pos1.compareTo(pos2);
452                              }
453                          });
454 
455         // Update the layout position based on the physical order within the sorted list
456         int position = 0;
457         for (Iterator iter = list.iterator(); iter.hasNext();)
458         {
459             Portlets pane = (Portlets) iter.next();
460             Layout layout = pane.getLayout();
461             layout.setPosition(position++);
462         }
463     }
464 
465     /*** Move a component up within the pane
466      *  This method expects the following parameters
467      * - paneid: the id a the pane to modify within the current profile
468      * - position: move the component which occupies this position
469      */
470     public void doUp(RunData data, Context context) throws Exception
471     {
472         doMove(data,context,true);
473     }
474 
475     /*** Move a component down within the pane
476      *  This method expects the following parameters
477      * - paneid: the id a the pane to modify within the current profile
478      * - position: move the component which occupies this position
479      */
480     public void doDown(RunData data, Context context) throws Exception
481     {
482         doMove(data,context,false);
483     }
484 
485     /*** Move a component within the pane
486      *  This method expects the following parameters
487      * - paneid: the id a the pane to modify within the current profile
488      * - position: move the component which occupies this position
489      * The moveUp boolean determines the direction of the move
490      */
491     public void doMove(RunData data, Context context, boolean moveUp) throws Exception
492     {
493         JetspeedRunData jdata = (JetspeedRunData)data;
494         PortletSet customizedSet = (PortletSet)jdata.getCustomized();
495         int position = data.getParameters().getInt("position",-1);
496         Profile profile = jdata.getCustomizedProfile();
497 
498         // ADDED for WML
499         //boolean isWML = (profile.getMediaType().equalsIgnoreCase("wml"));
500 
501 
502         if (customizedSet == null) return;
503 
504         if (position > -1)
505         {
506             int target = -1;
507 
508             Portlets set = profile.getDocument()
509                                   .getPortletsById(customizedSet.getID());
510             Layout targetLayout = null;
511             Layout baseLayout = null;
512 
513             if (set != null)
514             {
515                 // check if we can possibly move as requested and calculate
516                 // target position
517                 if ( moveUp )
518                 {
519                     if ( (position >= set.getPortletsCount())
520                          && (position >= set.getEntryCount()) ) return;
521                     target = position + 1;
522                 }
523                 else
524                 {
525                     if (position ==0) return;
526                     target = position - 1;
527                 }
528 
529                 // first find objects at explicit portlets position
530                 for(int i=0; i < set.getPortletsCount(); i++)
531                 {
532                     if ((targetLayout!=null) && (baseLayout!=null)) break;
533 
534                     Portlets p = set.getPortlets(i);
535                     Layout layout = p.getLayout();
536                     if ((layout!=null)&&(layout.getPosition()!=-1))
537                     {
538                         int lpos = (int)layout.getPosition();
539                         if ((baseLayout == null) && (lpos==position))
540                         {
541                             baseLayout = layout;
542                         }
543 
544                         if ((targetLayout == null) && (lpos==target))
545                         {
546                             targetLayout = layout;
547                         }
548                     }
549                 }
550 
551                 // try explicit entry position
552                 for(int i=0; i < set.getEntryCount(); i++)
553                 {
554                     if ((targetLayout!=null) && (baseLayout!=null)) break;
555 
556                     Entry p = set.getEntry(i);
557                     Layout layout = p.getLayout();
558                     if ((layout!=null)&&(layout.getPosition()!=-1))
559                     {
560                         int lpos = (int)layout.getPosition();
561                         if ((baseLayout == null) && (lpos==position))
562                         {
563                             baseLayout = layout;
564                         }
565 
566                         if ((targetLayout == null) && (lpos==target))
567                         {
568                             targetLayout = layout;
569                         }
570                     }
571                 }
572 
573                 //else use implicit position
574                 if (baseLayout == null)
575                 {
576                     if (position < set.getPortletsCount())
577                     {
578                         Portlets p = set.getPortlets(position);
579                         if (p.getLayout()==null)
580                         {
581                             p.setLayout(new PsmlLayout());
582                         }
583                         baseLayout=p.getLayout();
584                     }
585 
586                     if (position < set.getEntryCount())
587                     {
588                         Entry p = set.getEntry(position);
589                         if (p.getLayout()==null)
590                         {
591                             p.setLayout(new PsmlLayout());
592                         }
593                         baseLayout=p.getLayout();
594                     }
595                 }
596 
597                 if (targetLayout == null)
598                 {
599                     if (target < set.getPortletsCount())
600                     {
601                         Portlets p = set.getPortlets(target);
602                         if (p.getLayout()==null)
603                         {
604                             p.setLayout(new PsmlLayout());
605                         }
606                         targetLayout=p.getLayout();
607                     }
608 
609                     if (target < set.getEntryCount())
610                     {
611                         Entry p = set.getEntry(target);
612                         if (p.getLayout()==null)
613                         {
614                             p.setLayout(new PsmlLayout());
615                         }
616                         targetLayout=p.getLayout();
617                     }
618                 }
619 
620                 //we should now have found both baseLayout and targetLayout, swap
621                 //their positions using explicit positioning
622 
623                 if ((baseLayout == null) || (targetLayout == null)) return;
624 
625                 baseLayout.setPosition(target);
626                 targetLayout.setPosition(position);
627             }
628         }
629 
630 
631     // MODIFIED: Save changes for wml profiles
632     //if (isWML)
633     //  doSave(data, null);
634     }
635 }