View Javadoc

1   /*
2    * Copyright 2000-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.portlets;
18  
19  // Jetspeed imports
20  import org.apache.jetspeed.portal.PortletSet;
21  import org.apache.jetspeed.portal.PortletSkin;
22  import org.apache.jetspeed.portal.PortletController;
23  import org.apache.jetspeed.portal.PortletSetController;
24  import org.apache.jetspeed.portal.portlets.VelocityPortlet;
25  import org.apache.jetspeed.services.Profiler;
26  import org.apache.jetspeed.services.Registry;
27  import org.apache.jetspeed.services.PortalToolkit;
28  import org.apache.jetspeed.services.TemplateLocator;
29  import org.apache.jetspeed.services.rundata.JetspeedRunData;
30  import org.apache.jetspeed.om.BaseSecurityReference;
31  import org.apache.jetspeed.om.SecurityReference;
32  import org.apache.jetspeed.om.profile.Profile;
33  import org.apache.jetspeed.om.profile.ProfileLocator;
34  import org.apache.jetspeed.om.profile.ProfileException;
35  import org.apache.jetspeed.om.profile.QueryLocator;
36  import org.apache.jetspeed.om.registry.RegistryEntry;
37  import org.apache.jetspeed.om.registry.PortletEntry;
38  import org.apache.jetspeed.om.registry.PortletInfoEntry;
39  import org.apache.jetspeed.om.registry.base.BaseCategory;
40  import org.apache.jetspeed.om.profile.Portlets;
41  import org.apache.jetspeed.om.profile.psml.PsmlPortlets;
42  import org.apache.jetspeed.om.profile.Entry;
43  import org.apache.jetspeed.om.profile.psml.PsmlEntry;
44  import org.apache.jetspeed.om.profile.Reference;
45  import org.apache.jetspeed.om.profile.psml.PsmlReference;
46  import org.apache.jetspeed.om.profile.Skin;
47  import org.apache.jetspeed.om.profile.psml.PsmlSkin;
48  import org.apache.jetspeed.om.profile.MetaInfo;
49  import org.apache.jetspeed.om.profile.psml.PsmlMetaInfo;
50  import org.apache.jetspeed.om.profile.Controller;
51  import org.apache.jetspeed.om.profile.psml.PsmlController;
52  import org.apache.jetspeed.om.profile.Control;
53  import org.apache.jetspeed.om.profile.psml.PsmlControl;
54  import org.apache.jetspeed.om.profile.PSMLDocument;
55  import org.apache.jetspeed.om.security.JetspeedUser;
56  import org.apache.jetspeed.services.customlocalization.CustomLocalization;
57  import org.apache.jetspeed.services.idgenerator.JetspeedIdGenerator;
58  import org.apache.jetspeed.services.JetspeedSecurity;
59  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
60  import org.apache.jetspeed.services.logging.JetspeedLogger;
61  import org.apache.jetspeed.services.security.PortalResource;
62  import org.apache.jetspeed.util.AutoProfile;
63  import org.apache.jetspeed.util.PortletSessionState;
64  import org.apache.jetspeed.util.template.JetspeedLink;
65  import org.apache.jetspeed.util.template.JetspeedLinkFactory;
66  import org.apache.jetspeed.services.statemanager.SessionState;
67  import org.apache.jetspeed.services.resources.JetspeedResources;
68  
69  // Turbine stuff
70  import org.apache.turbine.util.DynamicURI;
71  import org.apache.turbine.util.RunData;
72  
73  
74  // Velocity Stuff
75  import org.apache.velocity.context.Context;
76  
77  // Java imports
78  import java.util.ArrayList;
79  import java.util.Map;
80  import java.util.HashMap;
81  import java.util.TreeMap;
82  import java.util.LinkedList;
83  import java.util.List;
84  import java.util.Iterator;
85  import java.util.Collections;
86  import java.util.Comparator;
87  import java.text.MessageFormat;
88  
89  /***
90   * This action implements the default portletset behavior customizer 
91   * 
92   * <p>Don't call it from the URL, the Portlet and the Action are automatically
93   * associated through the registry PortletName
94   * 
95   * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
96   * @version $Id: CustomizeSetAction.java,v 1.51 2004/02/23 02:56:58 jford Exp $
97   */
98  public class CustomizeSetAction extends VelocityPortletAction
99  {
100 
101     private static final String USER_SELECTIONS = "session.portlets.user.selections";
102     private static final String UI_PORTLETS_SELECTED = "portletsSelected";
103     private static final String PORTLET_LIST = "session.portlets.list";
104     private static final String ALL_PORTLET_LIST = "session.all.portlets.list";
105     private static final String PORTLET_LIST_PAGE_SIZE = "session.portlets.page.size";
106     private static final String HIDE_EMPTY_CATEGORIES = "customizer.hide.empty.categories";
107     
108     public static final String FILTER_FIELDS = "filter_fields";
109     public static final String FILTER_VALUES = "filter_values";
110 
111     /***
112      * Static initialization of the logger for this class
113      */    
114     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(CustomizeSetAction.class.getName());    
115     
116     /*** 
117      * Subclasses must override this method to provide default behavior 
118      * for the portlet action
119      */
120     protected void buildNormalContext(VelocityPortlet portlet, 
121                                       Context context,
122                                       RunData rundata) throws Exception
123     {
124         JetspeedRunData jdata = (JetspeedRunData) rundata;
125         SessionState customizationState = jdata.getPageSessionState();
126         Profile profile = jdata.getCustomizedProfile();
127         String mediaType = profile.getMediaType ();
128 
129         // set velocity variable of mediatype (displayed in the customizer menu)
130         context.put("mtype", profile.getMediaType());
131 
132         // make the list of already used panes/portlets available through the 'runs' reference
133         context.put("runs", AutoProfile.getPortletList(rundata));
134         
135         // we should first retrieve the portlet to customize
136         PortletSet set = (PortletSet) (jdata).getCustomized();
137 
138         //identify the portlet submode and build the appropriate subt-template path
139         String mode = rundata.getParameters().getString("mode");
140         if (mode == null)
141         {
142           mode = (String) customizationState.getAttribute("customize-mode");
143           if ((mode == null) || (mode.equalsIgnoreCase("addset")) || (mode.equalsIgnoreCase("general")))
144           {
145             mode = "layout";
146           }
147           
148         }
149         else
150         {
151           if ((mediaType.equalsIgnoreCase("wml")) && (!mode.equalsIgnoreCase("add")))
152           {
153             mode = "layout";
154           }
155 
156           customizationState.setAttribute("customize-mode", mode);
157         }
158 
159         String template = (String) context.get("template");
160 
161         if (template != null)
162         {
163             int idx = template.lastIndexOf(".");
164             
165             if (idx > 0)
166             {
167                 template = template.substring(0, idx);
168             }
169             
170             StringBuffer buffer = new StringBuffer(template);
171             buffer.append("-").append(mode).append(".vm");
172             
173             template = TemplateLocator.locatePortletTemplate(rundata, buffer.toString());
174             context.put("feature", template);
175 
176         }
177     
178         if (set == null)
179         {
180             return;
181         }
182 
183         // get the customization state for this page
184         String customizedPaneName = (String) customizationState.getAttribute("customize-paneName");
185         if (customizedPaneName == null) 
186         {
187             customizedPaneName = "*";
188         }
189 
190         // generic context stuff
191         context.put("panename", customizedPaneName);
192         context.put("skin", set.getPortletConfig().getPortletSkin());
193         context.put("set", set);
194         context.put("action", "portlets.CustomizeSetAction");        
195         context.put("controllers", buildInfoList(rundata, Registry.PORTLET_CONTROLLER, mediaType));
196         //context.put("skins", buildList(rundata, Registry.SKIN));
197         //context.put("securitys", buildList(rundata, Registry.SECURITY));
198         context.put("customizer", portlet);
199     
200         String controllerName = set.getController().getConfig().getName();
201         context.put("currentController", controllerName);
202 
203         context.put("currentSecurityRef", set.getPortletConfig().getSecurityRef());
204 
205        /*** 
206         * Special handling for wml profiles
207         * no skins, no properties menuentry, no panes 
208         * --------------------------------------------------------------------------
209         * last modified: 12/10/01
210         * Andreas Kempf, Siemens ICM S CP OP, Munich
211         * mailto: A.Kempf@web.de
212         */
213 
214         if (mediaType.equalsIgnoreCase("wml"))
215         {
216           context.put("currentSkin", "Not for wml!");
217           context.put("allowproperties", "false");
218         }
219         else
220         {
221           if (set.getPortletConfig().getSkin() != null)
222           {
223             context.put("currentSkin", set.getPortletConfig().getPortletSkin().getName());
224           }
225           context.put("allowproperties", "true");
226         }
227 
228 
229         context.put("allowpane", "false");
230         
231         // do not allow panes for wml profiles
232         if ((!mediaType.equalsIgnoreCase("wml")) && (set.getController() instanceof PortletSetController))
233         {
234           if (customizedPaneName != null)
235           {
236             context.put("allowpane", "true");
237           }
238         }
239         else
240         {
241             context.put("allowportlet", "true");
242         }
243         // --------------------------------------------------------------------------
244             
245 
246 
247         if ("add".equals(mode)) // build context for add mode
248         {
249             int start = rundata.getParameters().getInt("start", -1);
250             if (start < 0)
251             {
252                 //System.out.println("Clearing session variables");
253                 start = 0;
254                 PortletSessionState.clearAttribute(rundata, USER_SELECTIONS);
255                 PortletSessionState.clearAttribute(rundata, PORTLET_LIST);
256             }
257             
258             ArrayList allPortlets = new ArrayList();
259             List portlets  = buildPortletList(rundata, set, mediaType, allPortlets);
260             Map userSelections = getUserSelections(rundata); 
261             // Build a list of categories from the available portlets
262             List categories = buildCategoryList(rundata, mediaType, allPortlets);
263             context.put("categories", categories);
264             
265             context.put("parents", PortletFilter.buildParentList(allPortlets));
266             addFiltersToContext(rundata, context);
267             
268             int size = getSize(portlet);               
269             int end = Math.min(start + size, portlets.size());
270                 
271             if (start > 0)
272             {
273                 context.put("prev", String.valueOf(Math.max(start - size, 0)));
274             }
275                 
276             if (start + size < portlets.size())
277             {
278                 context.put("next", String.valueOf(start + size));
279             }
280                 
281             context.put("browser", portlets.subList(start, end));
282             context.put("size", new Integer(size));
283             context.put(UI_PORTLETS_SELECTED, userSelections);
284             
285 			context.put("portlets", portlets);
286         }
287         else if ("addref".equals(mode))
288         {
289             Iterator psmlIterator = null;
290             psmlIterator = Profiler.query(new QueryLocator(QueryLocator.QUERY_ALL));
291             
292             // Set Start and End
293             int start = rundata.getParameters().getInt("start", 0);                
294             int size = getSize(portlet);
295  
296 
297             // Only include entries in compatibale with the Media-type/Country/Language
298             List psmlList = new LinkedList();
299             Profile refProfile = null;
300             int profileCounter = 0;
301             while (psmlIterator.hasNext())
302             {
303                 refProfile = (Profile) psmlIterator.next();
304                 
305                 if (refProfile.getMediaType() != null)
306                 {
307                     if (profile.getMediaType().equals(refProfile.getMediaType()) == false)
308                     {
309                         continue;
310                     }
311                 }
312                 
313                 if (profile.getLanguage() != null)
314                 {
315                     if (refProfile.getLanguage() != null)
316                     {
317                         if (profile.getLanguage().equals(refProfile.getLanguage()) == true)
318                         {
319                             if (profile.getCountry() != null)
320                             {
321                                 if (refProfile.getCountry() != null)
322                                 {
323                                     if (profile.getCountry().equals(refProfile.getCountry()) == false)
324                                     {
325                                         // Profile and Ref are different countries
326                                         continue;
327                                     }
328                                 }
329                             }
330                             else
331                             {
332                                 if (refProfile.getCountry() != null)
333                                 {
334                                     // Profile has no country and Ref has a country
335                                     continue;
336                                 }
337                             }
338                         }
339                         else
340                         {
341                             // Profile and Ref are different languages
342                             continue;
343                         }
344                     }
345                 }
346                 else
347                 {
348                     if (refProfile.getLanguage() != null)
349                     {
350                         // Profile has no Language and Ref has a country
351                         continue;
352                     }
353                 }
354                 
355                 if (profile.getPath().equals(refProfile.getPath()) == true)
356                 {
357                     // Do not allow Profile to reference it self
358                     continue;
359                 }
360                 
361                 // Only add profiles to list that will be displayed
362                 if (profileCounter >= (start + size))
363                 {
364                     break;
365                 }
366                 if (profileCounter >= start)
367                 {
368                     psmlList.add(refProfile);
369                 }
370                 profileCounter++;
371             }
372                
373             // Add Start to context
374             if (start > 0)
375             {
376                 context.put("prev", String.valueOf(Math.max(start - size, 0)));
377             }
378                 
379             // Set end to context
380             if ((size == psmlList.size()) && (psmlIterator.hasNext()))
381             {
382                 context.put("next", String.valueOf(start + size));
383             }
384             
385             context.put("psml", psmlList.iterator());
386         }
387         else // build context for layout mode
388         {
389             // nothing specific to do
390         }
391 
392     }
393 
394     public int getSize(VelocityPortlet portlet)
395     {
396         int size = 15;
397         try
398         {
399             size = Integer.parseInt(portlet.getPortletConfig()
400                                            .getInitParameter("size"));
401         }
402         catch (Exception e)
403         {
404             logger.debug("CustomizeSetAction: Init param 'size' not parsed");
405         }
406         return size;
407     }
408 
409     /*** Clean up the customization state */
410     public void doCancel(RunData rundata, Context context)
411     {
412         //((JetspeedRunData)rundata).setCustomized(null);
413         //rundata.setScreenTemplate("Home");
414         SessionState customizationState = ((JetspeedRunData) rundata).getPageSessionState();
415         customizationState.setAttribute("customize-mode", "layout");
416     }
417 
418     /*** Save the general informations for this set */
419     public void doSave(RunData rundata, Context context)
420     {
421         doMetainfo(rundata, context);
422         doSkin(rundata, context);
423         doLayout(rundata, context);
424         doSecurity(rundata, context);
425         
426         Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile();
427         try
428         {
429             String mtype = rundata.getParameters().getString("mtype");
430 
431             if (mtype != null)
432             {
433                 profile.setMediaType(mtype);
434             }
435             profile.store();
436         }
437         catch (Exception e)
438         {
439             logger.error("Exception occured while saving PSML", e);
440         }
441 
442     }
443     
444     /*** Save customizations and get out of customization state */
445     public void doApply(RunData rundata, Context context)
446     {
447         doSave(rundata, context);
448     }
449     
450     /*** Add a new portlets element in the customized set */
451     public void doAddset(RunData rundata, Context context)
452     {
453         PortletSet set = (PortletSet) ((JetspeedRunData) rundata).getCustomized();
454         String title = rundata.getParameters().getString("title", "My Pane");
455         
456         if (set != null)
457         {
458             Portlets portlets = ((JetspeedRunData) rundata).getCustomizedProfile()
459                                                            .getDocument()
460                                                            .getPortletsById(set.getID());
461             
462             if (portlets != null)
463             {
464                 Portlets p = new PsmlPortlets();
465                 p.setMetaInfo(new PsmlMetaInfo());
466                 p.getMetaInfo().setTitle(title);
467                 p.setId(JetspeedIdGenerator.getNextPeid());
468                 SecurityReference defaultRef = PortalToolkit.getDefaultSecurityRef(
469                     ((JetspeedRunData) rundata).getCustomizedProfile());
470                 if (defaultRef != null)
471                 {
472                     if (logger.isDebugEnabled())
473                     {
474                         logger.debug("CustomizeSetAction: setting default portlet set security to [" + defaultRef.getParent() + "]");
475                     }
476                     p.setSecurityRef(defaultRef);
477                 }
478                 portlets.addPortlets(p);
479             }
480         }
481 
482         SessionState customizationState = ((JetspeedRunData) rundata).getPageSessionState();
483         customizationState.setAttribute("customize-mode", "layout");
484     }
485     
486    public void doPrevious(RunData rundata, Context context) throws Exception
487    {
488        int queryStart = rundata.getParameters().getInt("previous", 0);
489        String mtype = rundata.getParameters().getString("mtype", null);
490        maintainUserSelections(rundata);
491        JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
492        DynamicURI duri = null;
493        if (mtype == null)
494        {
495            duri = link.setTemplate("Customize").addQueryData("start", String.valueOf(queryStart));
496        }
497        else
498        {
499            duri = link.setTemplate("Customize").
500                addQueryData("start", String.valueOf(queryStart)).
501                addQueryData("mtype", mtype);
502        }
503        JetspeedLinkFactory.putInstance(link);
504        rundata.setRedirectURI(duri.toString());
505        return;
506    }
507 
508    public void doNext(RunData rundata, Context context) throws Exception
509    {
510        int queryStart = rundata.getParameters().getInt("next", 0);
511        String mtype = rundata.getParameters().getString("mtype", null);
512        maintainUserSelections(rundata);
513        JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
514        DynamicURI duri = null;
515        if (mtype == null)
516        {
517            duri = link.setTemplate("Customize").addQueryData("start", String.valueOf(queryStart));
518        }
519        else
520        {
521            duri = link.setTemplate("Customize").
522                addQueryData("start", String.valueOf(queryStart)).
523                addQueryData("mtype", mtype);
524        }
525        JetspeedLinkFactory.putInstance(link);
526        rundata.setRedirectURI(duri.toString());
527        return;
528    }
529 
530    protected void maintainUserSelections(RunData rundata) throws Exception
531    {
532        int size = rundata.getParameters().getInt("size", 0);
533        int previous = rundata.getParameters().getInt("previous", -1);
534        int start = 0;
535        if (previous >= 0)
536        {
537            start = previous + size;
538        }
539 
540        String[] pnames = rundata.getParameters().getStrings("pname");
541        //System.out.println("start = "+start+" size = "+size);
542        //System.out.println("pnames = "+rundata.getParameters());
543        Map userSelections = getUserSelections(rundata);
544        List portlets = (List) PortletSessionState.getAttribute(rundata, PORTLET_LIST, null);
545        if (portlets != null)
546        {
547            int end = Math.min(start + size, portlets.size());
548            int pnamesIndex = 0;
549            //Go through all the portlets on this page and figure out which ones have been 
550            //checked and which ones unchecked and accordingly update the userSelectionMap
551            for (int portletIndex = start; portletIndex < end; portletIndex++)
552            {
553                PortletEntry entry = (PortletEntry) portlets.get(portletIndex);
554                if (pnames != null 
555                    && pnamesIndex < pnames.length 
556                    && pnames[pnamesIndex].equals(entry.getName()))
557                {
558                     userSelections.put(entry.getName(), entry);
559                     pnamesIndex++;
560                }
561                else
562                {
563                     userSelections.remove(entry.getName());
564                }
565            }
566            PortletSessionState.setAttribute(rundata, USER_SELECTIONS, userSelections);
567            /*
568            Iterator it = userSelections.keySet().iterator();           
569            System.out.print("User Selections: ");
570            while (it.hasNext())
571            {
572                System.out.print(", "+it.next());
573            }
574            System.out.println("\n");
575            */
576        }
577        else
578        {
579            throw new Exception("Master Portlet List is null!");
580        }
581 
582    }
583 
584     /*** Add new portlets in the customized set */
585     public void doAdd(RunData rundata, Context context) throws Exception
586     {
587         /*** 
588          * Special handling for wml profiles
589          * no skins, no properties menuentry, no panes 
590          * --------------------------------------------------------------------------
591          * last modified: 10/31/01
592          * Andreas Kempf, Siemens ICM S CP PE, Munich
593          * mailto: A.Kempf@web.de
594          */
595         //boolean isWML = AutoProfile.doIt (rundata, true).getMediaType().equalsIgnoreCase("wml");
596         PortletSet set = (PortletSet) ((JetspeedRunData) rundata).getCustomized();
597         
598         maintainUserSelections(rundata);
599         Map userSelections = getUserSelections(rundata);
600         String[] pnames = new String[userSelections.size()];
601         userSelections.keySet().toArray(pnames);
602         //String[] pnames = rundata.getParameters().getStrings("pname");
603 
604         // Create a ClearPortletControl
605         Control ctrl = new PsmlControl();
606         ctrl.setName ("ClearPortletControl");
607 
608         
609         if ((pnames != null) && (set != null))
610         {
611             Portlets portlets = ((JetspeedRunData) rundata).getCustomizedProfile()
612                                                            .getDocument()
613                                                            .getPortletsById(set.getID());
614 
615             List usedPortlets = AutoProfile.getPortletList(rundata);
616             boolean addIt;
617             int cc;
618             Entry usedEntry;
619                                           
620             for (int i = 0; i < pnames.length; i++)
621             {
622                 PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, pnames[i]);
623 
624                 // add only new portlets!
625                 if ((entry != null) && (portlets != null))
626                 {
627                 
628                     addIt = true;
629  /*
630                     for (cc=0; cc<usedPortlets.size(); cc++)
631                     {
632                       usedEntry = (Entry) usedPortlets.get(cc);
633                       if (entry.getName().equals(usedEntry.getParent()))
634                       {
635                         addIt = false;
636                         break;
637                       }
638                       
639                     }
640 */
641                     if (addIt)
642                     {
643                       Entry p = new PsmlEntry();
644                       // add the ClearPortletControl to wml entries      
645                       //if (isWML)
646                       //  p.setControl (ctrl);
647                     
648                       p.setParent(pnames[i]);
649                       p.setId(JetspeedIdGenerator.getNextPeid());
650 //                      SecurityReference defaultRef = PortalToolkit.getDefaultSecurityRef(
651 //                          ((JetspeedRunData) rundata).getCustomizedProfile());
652 //                      if (defaultRef != null)
653 //                      {
654 //                          if (Log.getLogger().isDebugEnabled())
655 //                          {
656 //                              Log.debug("CustomizeSetAction: setting default portlet security to [" + defaultRef.getParent() + "]");
657 //                          }
658 //                          p.setSecurityRef(defaultRef);
659 //                      }
660                       portlets.addEntry(p);
661                     }
662                 }
663             }
664         }
665         // --------------------------------------------------------------------------
666 
667         SessionState customizationState = ((JetspeedRunData) rundata).getPageSessionState();
668         customizationState.setAttribute("customize-mode", "layout");
669 
670         /*** 
671          * Save changed wml profile
672          * --------------------------------------------------------------------------
673          * last modified: 10/31/01
674          * Andreas Kempf, Siemens ICM S CP PE, Munich
675          * mailto: A.Kempf@web.de
676         if (isWML)
677         {
678           ((JetspeedRunData)rundata).getCustomizedProfile().store();
679           //rundata.save();
680         }
681          */
682         
683     }
684 
685     /*** Add new Reference in the customized set */
686     public void doAddref(RunData rundata, Context context) throws Exception
687     {
688         PortletSet set = (PortletSet) ((JetspeedRunData) rundata).getCustomized();
689         String[] refNames = rundata.getParameters().getStrings("refname");
690         
691         // Create a ClearPortletControl
692         Control ctrl = new PsmlControl();
693         ctrl.setName ("ClearPortletControl");
694 
695         
696         if ((refNames != null) && (set != null))
697         {
698             Portlets portlets = ((JetspeedRunData) rundata).getCustomizedProfile()
699                                                            .getDocument()
700                                                            .getPortletsById(set.getID());
701 
702             for (int i = 0; i < refNames.length; i++)
703             {
704                 SecurityReference sref = getSecurityReference(rundata, refNames[i]);
705                 if (sref != null)
706                 {
707                     Reference ref = new PsmlReference();
708                     ref.setPath(refNames[i]);              
709                     ref.setSecurityRef(sref);
710                     portlets.addReference(ref);
711                 }
712                 else
713                 {
714                     String tmpl = CustomLocalization.getString("CUSTOMIZER_ADD_REF_ERROR", rundata);
715                     Object[] args = {
716                         refNames[i]
717                     };
718                     String message = MessageFormat.format(tmpl, args).toString();
719 
720                     rundata.addMessage(message.concat("<br>"));
721                     if (logger.isWarnEnabled())
722                     {
723                         logger.warn(message);
724                     }
725                 }
726             }
727         }
728         SessionState customizationState = ((JetspeedRunData) rundata).getPageSessionState();
729         customizationState.setAttribute("customize-mode", "layout");
730     }
731 
732     /***
733      * Get the security reference from the outer portlet set
734      *
735      * @param path the psml locator path
736      * @return the security reference of the referenced resource     
737      */
738     protected SecurityReference getSecurityReference(RunData rundata, String path)
739     {
740         try
741         {
742             ProfileLocator locator = Profiler.createLocator();
743             locator.createFromPath(path);
744             Profile profile = Profiler.getProfile(locator);
745             if (profile != null)
746             {
747                 PSMLDocument doc = profile.getDocument();
748                 if (doc != null)
749                 {
750                     Portlets rootSet = doc.getPortlets();
751                     /*
752                     There is no way to do a check on a Portlets element, only a Entry element.
753                     This can easily be added, but Im just under a release right now and it 
754                     could be perceived as too destabilizing -- david
755                     
756                     if (JetspeedSecurity.checkPermission((JetspeedUser) rundata.getUser(),
757                                                          rootSet,
758                                                          JetspeedSecurity.PERMISSION_VIEW))
759                     {
760                     */
761                         return rootSet.getSecurityRef();    
762         //            }
763                 }
764             }
765         }
766         catch (ProfileException e)
767         {
768             logger.error("Exception", e);
769         }
770         return null;
771     }
772     
773     /*** Sets the metainfo for this entry */
774     public void doMetainfo(RunData rundata, Context context)
775     {
776         PortletSet set = (PortletSet) ((JetspeedRunData) rundata).getCustomized();
777         String title = rundata.getParameters().getString("title");
778         String description = rundata.getParameters().getString("description");
779 
780         if (set != null)
781         {
782             Portlets portlets = ((JetspeedRunData) rundata).getCustomizedProfile()
783                                                            .getDocument()
784                                                            .getPortletsById(set.getID());
785             
786             if (portlets != null)
787             {
788                 MetaInfo meta = portlets.getMetaInfo();
789                 if (meta == null)
790                 {
791                     meta = new PsmlMetaInfo();
792                     portlets.setMetaInfo(meta);
793                 }
794             
795                 if (title != null)
796                 {
797                     meta.setTitle(title);
798                     set.setTitle(title);
799                 }
800 
801                 if(description != null)
802                 {
803                     meta.setDescription(description);
804                     set.setDescription(description);
805                 }
806             }
807         }
808     }
809 
810     /*** Updates the customized portlet entry */
811     public void doLayout(RunData rundata, Context context)
812     {
813         // we should first retrieve the portlet to customize and its parameters
814         // definition
815         PortletSet set = (PortletSet) ((JetspeedRunData) rundata).getCustomized();
816         
817         try
818         {            
819             String controller = rundata.getParameters().getString("controller");
820             
821             if (controller != null)
822             {
823                 Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile();
824                 PortletController pc = PortalToolkit.getController(controller);
825 
826                 if (pc != null)
827                 {
828                     set.setController(pc);
829 
830                     Portlets portlets = profile.getDocument().getPortletsById(set.getID());
831 
832                     Controller c = portlets.getController();
833                     if (c == null)
834                     {
835                         c = new PsmlController();
836                         portlets.setController(c);
837                     }
838                     c.setName(controller);
839                     
840                     String linkedControl = pc.getConfig().getInitParameter("control");
841 
842                     if (linkedControl != null)
843                     {
844                         Control ctl = new PsmlControl();
845                         ctl.setName(linkedControl);
846                         portlets.setControl(ctl);
847                     }
848                     else
849                     {
850                         portlets.setControl(null);
851                     }
852                 }
853             }
854         }
855         catch (Exception e)
856         {
857             logger.error("Exception", e);
858         }
859         
860     }
861 
862     /***
863      * Set the skin in the PSML and the current PortletConfig
864      * using the HTML parameter "skin".  If the parmeter is
865      * missing or 'blank', then the skin is set to null.
866      *
867      */
868 
869     /***
870      * Set the skin in the PSML and the current PortletConfig
871      * using the HTML parameter "skin".  If the parmeter is
872      * missing or 'blank', then the skin is set to null.
873      *
874      */
875     public void doSkin(RunData rundata, Context context)
876     {
877         // we should first retrieve the portlet to customize and its parameters
878         // definition
879         PortletSet set = (PortletSet) ((JetspeedRunData) rundata).getCustomized();
880         
881         try
882         {            
883             String skin = rundata.getParameters().getString("skin");
884             Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile();
885             Portlets portlets = profile.getDocument().getPortletsById(set.getID());
886             
887             // skin is neither null nor zero-length
888             if ((skin != null) && (skin.trim().length() > 0))
889             {
890                 PortletSkin s = PortalToolkit.getSkin(skin);
891 
892                 if (s != null)
893                 {
894                     set.getPortletConfig().setPortletSkin(s);
895 
896                     Skin psmlSkin = portlets.getSkin();
897                     if (psmlSkin == null)
898                     {
899                         portlets.setSkin(new PsmlSkin());
900                     }
901                     portlets.getSkin().setName(skin);
902                 }
903                 else
904                 {
905                     logger.warn("Unable to update skin for portlet set " 
906                              + set.getID() + " because skin " + skin 
907                              + " does not exist.");
908                     return;
909                 }
910             }
911             else
912             {
913               // skin is either null or zero-length
914               String custPortletSetID = portlets.getId();
915               String rootPortletSetID = profile.getRootSet().getID();
916               
917               // set system default skin for root PSML element
918               if (custPortletSetID != null && rootPortletSetID != null &&
919                   custPortletSetID.equals(rootPortletSetID))
920               {
921                 // get system default skin
922                 String defaultSkinName = JetspeedResources.getString("services.PortalToolkit.default.skin");
923                 PortletSkin defaultSkin = PortalToolkit.getSkin(defaultSkinName);
924                 
925                 if (defaultSkin != null)
926                 {
927                   set.getPortletConfig().setPortletSkin((PortletSkin) defaultSkin);
928                   Skin psmlSkin = portlets.getSkin();
929                   
930                   if (psmlSkin == null)
931                   {
932                     portlets.setSkin(new PsmlSkin());
933                   }
934                 
935                   portlets.getSkin().setName(defaultSkin.getName());
936                 }
937                 else
938                 {
939                     logger.warn("Unable to set default skin for root portlet set " 
940                              + set.getID() + " because skin " + skin 
941                              + " does not exist.");
942                     return;
943                 }
944               }
945               else
946               {
947                 // By setting the skin to null, the parent's skin will be used.
948                 set.getPortletConfig().setPortletSkin((PortletSkin) null);
949                 portlets.setSkin(null);
950               }
951             }
952         }
953         catch (Exception e)
954         {
955             logger.error(e);
956         }        
957     }
958 
959     /***
960      * Set the SecuirtyRef in the PSML and the current PortletConfig
961      * using the HTML parameter "securityRef".  If the parmeter is
962      * missing or 'blank', then the SecuriyReference is set to null.
963      *
964      */
965     public void doSecurity(RunData rundata, Context context)
966     {
967         // we should first retrieve the portlet to customize and its parameters
968         // definition
969         PortletSet set = (PortletSet) ((JetspeedRunData) rundata).getCustomized();
970         
971         try
972         {            
973             String securityRefName = rundata.getParameters().getString("securityRef");
974             SecurityReference securityRef = null;
975             Profile profile = ((JetspeedRunData) rundata).getCustomizedProfile();
976             Portlets portlets = profile.getDocument().getPortletsById(set.getID());
977 
978             if ((securityRefName != null) && (securityRefName.trim().length() > 0))
979             {
980                 securityRef = new BaseSecurityReference();
981                 securityRef.setParent(securityRefName);
982             }
983             set.getPortletConfig().setSecurityRef(securityRef);
984             portlets.setSecurityRef(securityRef);
985         }
986         catch (Exception e)
987         {
988             logger.error("Exception", e);
989         }        
990     }
991     
992 
993     // Create a list of all available portlets
994     public static List buildPortletList(RunData data, PortletSet set, String mediaType, List allPortlets)
995     {
996         List list = new ArrayList();                                                                 
997         Iterator i = Registry.get(Registry.PORTLET).listEntryNames();
998         
999         while (i.hasNext())
1000         {
1001             PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET,
1002                                                                  (String) i.next());
1003             
1004             Iterator medias;
1005             //Make a master portlet list, we will eventually us this to build a category list
1006             allPortlets.add(entry);
1007             // MODIFIED: Selection now takes care of the specified mediatype!
1008             if (JetspeedSecurity.checkPermission((JetspeedUser) data.getUser(), 
1009                                                  new PortalResource(entry), 
1010                                                  JetspeedSecurity.PERMISSION_VIEW)
1011               && ((!entry.isHidden()) 
1012                 && (!entry.getType().equals(PortletEntry.TYPE_ABSTRACT))
1013                 && entry.hasMediaType(mediaType)))
1014             {
1015                 list.add(entry);
1016             }
1017         }
1018         
1019         String[] filterFields = (String[]) PortletSessionState.getAttribute(data, FILTER_FIELDS);
1020         String[] filterValues = (String[]) PortletSessionState.getAttribute(data, FILTER_VALUES);
1021         list = PortletFilter.filterPortlets(list, filterFields, filterValues);
1022         
1023         Collections.sort(list,
1024                 new Comparator() {
1025                     public int compare(Object o1, Object o2)
1026                     {
1027                         String t1 = (((PortletEntry) o1).getTitle() != null)
1028                             ? ((PortletEntry) o1).getTitle().toLowerCase()
1029                             : ((PortletEntry) o1).getName().toLowerCase();
1030                         String t2 = (((PortletEntry) o2).getTitle() != null)
1031                             ? ((PortletEntry) o2).getTitle().toLowerCase()
1032                             : ((PortletEntry) o2).getName().toLowerCase();
1033                                                    
1034                         return t1.compareTo(t2);
1035                     }
1036                 });
1037         //this is used only by maintainUserSelection - which does not need the 
1038         //portlet list to be regenrated       
1039         PortletSessionState.setAttribute(data, PORTLET_LIST, list);
1040         return list;
1041     }
1042 
1043     public static Map getUserSelections(RunData data)
1044     {
1045         Map userSelections = (Map) PortletSessionState.getAttribute(data, USER_SELECTIONS, null);
1046         if (userSelections == null)
1047         {
1048             userSelections = new HashMap();
1049             PortletSessionState.setAttribute(data, USER_SELECTIONS, userSelections);
1050         }
1051         return userSelections;
1052     }
1053     
1054     public static List buildInfoList(RunData data, String regName, String mediaType)
1055     {
1056         List list = new ArrayList();
1057         
1058         String mime = ((JetspeedRunData) data).getCapability()
1059                                               .getPreferredType()
1060                                               .toString();
1061                                              
1062         Iterator m = Registry.get(Registry.MEDIA_TYPE).listEntryNames();
1063 //        String mediaName = "html";
1064 //        
1065 //        while(m.hasNext())
1066 //        {
1067 //            MediaTypeEntry me = (MediaTypeEntry)
1068 //                Registry.getEntry(Registry.MEDIA_TYPE,(String)m.next());
1069 //            
1070 //            if (me!=null)
1071 //            {
1072 //                if (mime.equals(me.getMimeType()))
1073 //                {
1074 //                    mediaName = me.getName();
1075 //                    break;
1076 //                }
1077 //            }
1078 //        }
1079                     
1080         Iterator i = Registry.get(regName).listEntryNames();
1081         
1082         while (i.hasNext())
1083         {
1084             PortletInfoEntry entry = (PortletInfoEntry) Registry.getEntry(regName,
1085                                                                  (String) i.next());
1086             
1087             // MODIFIED: Selection now takes care of the specified mediatype!
1088             if (JetspeedSecurity.checkPermission((JetspeedUser) data.getUser(), 
1089                                                   new PortalResource(entry), 
1090                                                   JetspeedSecurity.PERMISSION_CUSTOMIZE)
1091                && ((!entry.isHidden())
1092                  && entry.hasMediaType(mediaType)))
1093             {
1094                 list.add(entry);
1095             }
1096         }
1097         
1098         Collections.sort(list,
1099                 new Comparator() {
1100                     public int compare(Object o1, Object o2)
1101                     {
1102                         String t1 = (((RegistryEntry) o1).getTitle() != null)
1103                             ? ((RegistryEntry) o1).getTitle()
1104                             : ((RegistryEntry) o1).getName();
1105                         String t2 = (((RegistryEntry) o2).getTitle() != null)
1106                             ? ((RegistryEntry) o2).getTitle()
1107                             : ((RegistryEntry) o2).getName();
1108                         
1109                         return t1.compareTo(t2);
1110                     }
1111                 });
1112         
1113         return list;
1114     }
1115     
1116     public static List buildList(RunData data, String regName)
1117     {
1118         List list = new ArrayList();
1119         
1120         Iterator i = Registry.get(regName).listEntryNames();        
1121         while (i.hasNext())
1122         {
1123             RegistryEntry entry = Registry.getEntry(regName, (String) i.next());
1124             
1125             if (JetspeedSecurity.checkPermission((JetspeedUser) data.getUser(),
1126                                                  new PortalResource(entry),
1127                                                  JetspeedSecurity.PERMISSION_CUSTOMIZE)
1128                && (!entry.isHidden()))
1129             {
1130                 list.add(entry);
1131             }
1132         }
1133         
1134         Collections.sort(list,
1135                 new Comparator() {
1136                     public int compare(Object o1, Object o2)
1137                     {
1138                         String t1 = (((RegistryEntry) o1).getTitle() != null)
1139                             ? ((RegistryEntry) o1).getTitle()
1140                             : ((RegistryEntry) o1).getName();
1141                         String t2 = (((RegistryEntry) o2).getTitle() != null)
1142                             ? ((RegistryEntry) o2).getTitle()
1143                             : ((RegistryEntry) o2).getName();
1144                         
1145                         return t1.compareTo(t2);
1146                     }
1147                 });
1148         
1149         return list;
1150     }
1151     
1152     /***
1153      * Builds a list of all portlet categories
1154      * @param RunData current requests RunData object
1155      * @param List portlets All available portlets
1156      */    
1157     public static List buildCategoryList(RunData data, String mediaType, List portlets)
1158     {
1159         boolean hideEmpties = JetspeedResources.getBoolean(HIDE_EMPTY_CATEGORIES, true);
1160         TreeMap catMap = new TreeMap();
1161         Iterator pItr = portlets.iterator();
1162         while (pItr.hasNext())
1163         {
1164             PortletEntry entry =  (PortletEntry) pItr.next();
1165             if (hideEmpties)
1166             {
1167                 if (JetspeedSecurity.checkPermission((JetspeedUser) data.getUser(), 
1168                                          new PortalResource(entry), 
1169                                          JetspeedSecurity.PERMISSION_VIEW)
1170                     && ((!entry.isHidden()) 
1171                     && (!entry.getType().equals(PortletEntry.TYPE_ABSTRACT))
1172                     && entry.hasMediaType(mediaType)))
1173                 {
1174                     Iterator cItr = entry.listCategories();
1175                     while (cItr.hasNext())
1176                     {
1177                         BaseCategory cat = (BaseCategory) cItr.next();
1178                         catMap.put(cat.getName(), cat);
1179                     }            
1180                 }
1181             }
1182             else
1183             {
1184                 Iterator cItr = entry.listCategories();
1185                 while (cItr.hasNext())
1186                 {
1187                     BaseCategory cat = (BaseCategory) cItr.next();
1188                     catMap.put(cat.getName(), cat);
1189                 }            
1190             }
1191         }
1192         
1193         //BaseCategory allCat = new BaseCategory();
1194           //      allCat.setName("All Portlets");
1195             //    catMap.put(allCat.getName(), allCat);
1196         return new ArrayList(catMap.values());
1197         
1198     }
1199     
1200     /***
1201      * Adds a filter over the available portlets list based on category
1202      */
1203     public void doFiltercategory(RunData rundata, Context context) throws Exception
1204     {
1205         String filterCat = rundata.getParameters().getString("filter_category", "All Portlets");
1206         PortletSessionState.setAttribute(rundata, "filter_category", filterCat);
1207         maintainUserSelections(rundata);
1208         
1209         String mtype = rundata.getParameters().getString("mtype", null);
1210         JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1211         DynamicURI duri = null;
1212         if (mtype == null)
1213         {
1214             duri = link.setTemplate("Customize").addQueryData("start", "0");
1215         }
1216         else
1217         {
1218             duri = link.setTemplate("Customize").addQueryData("start", "0").addQueryData("mtype", mtype);
1219         }
1220         JetspeedLinkFactory.putInstance(link);
1221         rundata.setRedirectURI(duri.toString());
1222         return;
1223     }
1224     
1225     /***
1226      * Adds a filter over the available portlets list based on category
1227      */
1228     public void doFilter(RunData rundata, Context context) throws Exception
1229     {
1230         String[] filterFields = rundata.getParameters().getStrings("filter_field");
1231         String[] filterValues = new String[filterFields.length];
1232         for(int i=0; i<filterFields.length; i++)
1233         {
1234             String filterField = filterFields[i];
1235             if(filterField != null)
1236             {
1237                 String filterValue = rundata.getParameters().getString(filterField + ":filter_value");
1238                 filterValues[i] = filterValue;
1239             }
1240          }
1241         
1242         PortletSessionState.setAttribute(rundata, FILTER_FIELDS, filterFields);
1243         PortletSessionState.setAttribute(rundata, FILTER_VALUES, filterValues);
1244          
1245         maintainUserSelections(rundata);
1246     
1247         String mtype = rundata.getParameters().getString("mtype", null);
1248         JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1249         DynamicURI duri = null;
1250         if (mtype == null)
1251         {
1252             duri = link.setTemplate("Customize").addQueryData("start", "0");
1253         }
1254         else
1255         {
1256             duri = link.setTemplate("Customize").addQueryData("start", "0").addQueryData("mtype", mtype);
1257         }
1258         JetspeedLinkFactory.putInstance(link);
1259         rundata.setRedirectURI(duri.toString());
1260         return;
1261     }
1262     
1263     private void addFiltersToContext(RunData data, Context context)
1264     {
1265         String[] filterFields = (String[]) PortletSessionState.getAttribute(data, FILTER_FIELDS);
1266         String[] filterValues = (String[]) PortletSessionState.getAttribute(data, FILTER_VALUES);
1267         if(filterFields != null && filterValues != null && filterFields.length == filterValues.length)
1268         {
1269             for(int i=0; i<filterFields.length; i++)
1270             {
1271                 String field = filterFields[i];
1272                 String value = filterValues[i];
1273         
1274                 context.put(field + "_filter_value", value);
1275             }
1276         }
1277     }
1278         
1279 }