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
20  import org.apache.commons.lang.SerializationUtils;
21  import org.apache.jetspeed.om.profile.Profile;
22  import org.apache.jetspeed.om.profile.QueryLocator;
23  import org.apache.jetspeed.portal.Portlet;
24  import org.apache.jetspeed.portal.portlets.browser.DatabaseBrowserIterator;
25  import org.apache.jetspeed.services.Profiler;
26  import org.apache.jetspeed.util.PortletConfigState;
27  import org.apache.jetspeed.util.PortletUtils;
28  import org.apache.jetspeed.util.PortletSessionState;
29  import org.apache.jetspeed.services.security.PortalResource;
30  import org.apache.jetspeed.om.security.JetspeedUser;
31  import org.apache.jetspeed.services.JetspeedSecurity;
32  import org.apache.jetspeed.modules.actions.portlets.security.SecurityConstants;
33  import org.apache.jetspeed.om.profile.ProfileLocator;
34  import org.apache.jetspeed.om.profile.PSMLDocument;
35  import org.apache.jetspeed.om.profile.Portlets;
36  import org.apache.jetspeed.om.registry.Parameter;
37  import org.apache.jetspeed.om.registry.PortletEntry;
38  import org.apache.jetspeed.services.Registry;
39  import org.apache.jetspeed.services.PsmlManager;
40  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
41  import org.apache.jetspeed.services.logging.JetspeedLogger;
42  import org.apache.jetspeed.util.template.JetspeedLink;
43  import org.apache.jetspeed.util.template.JetspeedLinkFactory;
44  import org.apache.jetspeed.services.resources.JetspeedResources;
45  import org.apache.jetspeed.services.psmlmanager.PsmlManagerService;
46  import org.apache.jetspeed.om.profile.BasePSMLDocument;
47  import org.apache.jetspeed.om.security.Role;
48  import org.apache.jetspeed.om.security.Group;
49  import org.apache.jetspeed.services.rundata.JetspeedRunData;
50  
51  // Turbine stuff
52  import org.apache.turbine.util.RunData;
53  import org.apache.turbine.util.DynamicURI;
54  import org.apache.turbine.util.StringUtils;
55  import org.apache.turbine.util.security.EntityExistsException;
56  import org.apache.turbine.services.TurbineServices;
57  import org.apache.turbine.services.servlet.TurbineServlet;
58  import org.apache.turbine.services.resources.ResourceService;
59  
60  // Velocity Stuff
61  import org.apache.velocity.context.Context;
62  
63  // Java
64  import java.util.ArrayList;
65  import java.util.Hashtable;
66  import java.util.Iterator;
67  import java.io.File;
68  import java.io.FileWriter;
69  import java.io.FileReader;
70  import java.io.IOException;
71  import java.util.Vector;
72  import java.util.StringTokenizer;
73  
74  // castor support
75  import org.exolab.castor.xml.MarshalException;
76  import org.exolab.castor.xml.Marshaller;
77  import org.exolab.castor.xml.Unmarshaller;
78  import org.exolab.castor.xml.ValidationException;
79  import org.exolab.castor.mapping.Mapping;
80  import org.exolab.castor.mapping.MappingException;
81  import org.xml.sax.InputSource;
82  
83  // serialization support
84  import org.apache.xml.serialize.Serializer;
85  import org.apache.xml.serialize.XMLSerializer;
86  import org.apache.xml.serialize.OutputFormat;
87  
88  /***
89   * This action enables to manage psml entries
90   * within current user's security context
91   *
92   * @author <a href="mailto:morciuch@apache.org">Mark Orciuch</a>
93   * @version $Id: PsmlManagerAction.java,v 1.7 2004/02/23 02:56:58 jford Exp $
94   */
95  public class PsmlManagerAction extends GenericMVCAction
96  {
97      public static final String CACHED_PSML = "PsmlManagerAction.cached.psml";
98      protected static final String PSML_REFRESH_FLAG = "psmlRefreshFlag";
99      protected static final String TRUE = "true";
100     protected static final String FALSE = "false";
101     protected static final String PROFILE_ITERATOR = "profileIterator";
102     protected static final String LAST_SEARCH_TYPE = "lastSearchType";
103     protected static final String LAST_SEARCH_VALUE = "lastSearchValue";
104     protected static final String PAGE_SIZE = "page-size";
105     protected static final String DEFAULT_SEARCH = "default-search";
106     protected static final String CUSTOMIZE_TEMPLATE = "customize-template";
107     private static final String PEID = "js_peid";
108 
109     /*** name of the parameter that holds the filter value */
110     public static final String FILTER_VALUE = "filter_value";
111 
112     /*** name of the parameter that holds the regexp flag */
113     public static final String FILTER_REGEXP = "filter_regexp";
114 
115     /*** name of the parameter that holds the filter type */
116     public static final String FILTER_TYPE = "filter_type";
117 
118     /*** value of the filter type parameter for searching by username */
119     public static final String FILTER_TYPE_USER = "filter_type_user";
120 
121     /*** value of the filter type parameter for searching by role */
122     public static final String FILTER_TYPE_ROLE = "filter_type_role";
123 
124     /*** value of the filter type parameter for searching by group */
125     public static final String FILTER_TYPE_GROUP = "filter_type_group";
126 
127     private static Hashtable queryModes = new Hashtable();
128     static 
129     {        
130         queryModes.put("All", String.valueOf(QueryLocator.QUERY_ALL));
131         queryModes.put("User", String.valueOf(QueryLocator.QUERY_USER));
132         queryModes.put("Role", String.valueOf(QueryLocator.QUERY_ROLE));
133         queryModes.put("Group", String.valueOf(QueryLocator.QUERY_GROUP));
134     }
135 
136     protected static final String CATEGORY_NAME = "categoryName";
137     protected static final String CATEGORY_VALUE = "categoryValue";
138     protected static final String COPY_FROM = "copyFrom";
139     protected static final String COPY_TO = "copyTo";
140     protected static final String TEMP_LOCATOR = "tempLocator";
141     protected static final String PSML_UPDATE_PANE = "PsmlForm";
142 
143     /***
144      * Static initialization of the logger for this class
145      */    
146     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(PsmlManagerAction.class.getName());    
147     
148     /***
149      * Subclasses should override this method if they wish to
150      * provide their own customization behavior.
151      * Default is to use Portal base customizer action
152      */
153     protected void buildConfigureContext(Portlet portlet,
154                                          Context context,
155                                          RunData rundata)
156     {
157         try
158         {
159             super.buildConfigureContext(portlet, context, rundata);
160         }
161         catch (Exception ex)
162         {
163             logger.error("Exception", ex);
164         }
165         context.put(PAGE_SIZE, PortletConfigState.getParameter(portlet, rundata, PAGE_SIZE, "20"));
166         setTemplate(rundata, PortletConfigState.getParameter(portlet, rundata, CUSTOMIZE_TEMPLATE, null));
167     }
168 
169     /***
170      * Subclasses must override this method to provide default behavior
171      * for the portlet action
172      * 
173      * @param portlet
174      * @param context
175      * @param rundata
176      */
177     protected void buildNormalContext(Portlet portlet, Context context, RunData rundata)
178     {
179 
180         PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, portlet.getName());
181         context.put("can-search", canPerformAction(rundata, entry, entry.getParameter("can-search")));
182         context.put("can-clone", canPerformAction(rundata, entry, entry.getParameter("can-clone")));
183         context.put("can-import", canPerformAction(rundata, entry, entry.getParameter("can-import")));
184         context.put("can-export", canPerformAction(rundata, entry, entry.getParameter("can-export")));
185         context.put("can-import-all", canPerformAction(rundata, entry, entry.getParameter("can-import-all")));
186         context.put("can-export-all", canPerformAction(rundata, entry, entry.getParameter("can-export-all")));
187         context.put("can-add", canPerformAction(rundata, entry, entry.getParameter("can-add")));
188         context.put("can-remove", canPerformAction(rundata, entry, entry.getParameter("can-remove")));
189 
190         String mode = rundata.getParameters().getString("mode", "browse");
191         if (mode.equals("browse"))
192         {
193             this.setTemplate(rundata, PortletConfigState.getParameter(portlet, rundata, "template", "browser-psml"));
194             buildBrowseNormalContext(portlet, context, rundata);
195         }
196         else
197         {
198             this.setTemplate(rundata, PortletConfigState.getParameter(portlet, rundata, "detail-template", "psml-form"));
199             buildDetailNormalContext(portlet, context, rundata);
200         }
201 
202     }
203 
204     /***
205      * Performs building of normal context for browsing mode
206      * 
207      * @param portlet
208      * @param context
209      * @param rundata
210      */
211     private  void buildBrowseNormalContext(Portlet portlet, Context context, RunData rundata)
212     {
213 
214         context.put("queryModes", queryModes);
215 
216         int start = rundata.getParameters().getInt("start", 0);
217 
218         if (start < 0)
219         {
220             start = 0;
221         }
222 
223         String pageSize = PortletConfigState.getParameter(portlet, rundata, PAGE_SIZE, "20");
224         int size = Integer.parseInt(pageSize);
225 
226         int next = start + size + 1;
227         int prev = start - size - 1;
228 
229         //System.out.println("start="+start+" size="+size+" next="+next+" prev="+prev);
230 
231         //check to see if resultset has changed due to PsmlUpdateAction
232         //if so reconstruct the iterator and reset the flag
233 
234         boolean refreshFlag = getRefreshPsmlFlag(rundata);
235 
236         // By default, only return psml pages for the current user
237         String defaultSearch = PortletConfigState.getParameter(portlet, rundata, DEFAULT_SEARCH, "true");
238 
239         //Get the iterator
240         DatabaseBrowserIterator windowIterator =
241         (DatabaseBrowserIterator) PortletSessionState.getAttribute(portlet, rundata, PROFILE_ITERATOR);
242         if (refreshFlag)
243         {
244             setRefreshPsmlFlag(rundata, FALSE);
245             PortletSessionState.clearAttribute(portlet, rundata, PROFILE_ITERATOR);
246 
247             // Use last used search value to refresh
248             Integer type = (Integer) PortletSessionState.getAttribute(portlet, rundata, LAST_SEARCH_TYPE);
249             String value = (String) PortletSessionState.getAttribute(portlet, rundata, LAST_SEARCH_VALUE);
250 
251             if (type != null && value != null)
252             {
253                 windowIterator = performSearch(rundata, portlet, type.intValue(), value);
254             }
255 
256         }
257         else if (windowIterator != null)
258         {
259             windowIterator.setTop(start);
260         }
261         else if (defaultSearch != null && defaultSearch.equals("true"))
262         {
263             windowIterator = performSearch(rundata, portlet, QueryLocator.QUERY_USER, rundata.getUser().getUserName());
264         }
265 
266         if (windowIterator != null)
267         {
268             context.put("psml", windowIterator);
269             if (start > 0)
270             {
271                 context.put("prev", String.valueOf(prev + 1));
272             }
273             if (next <= windowIterator.getResultSetSize())
274             {
275                 context.put("next", String.valueOf(next - 1));
276             }
277 
278         }
279 
280     }
281 
282     /***
283      * Returns true if current user can peform specific profile action
284      * 
285      * @param data
286      * @param profile
287      * @return 
288      */
289     private String canPerformAction(RunData rundata, PortletEntry entry, Parameter actionParam)
290     {
291         String result = "true";
292 
293         if (actionParam != null && entry != null)
294         {
295             PortalResource portalResource = new PortalResource(entry, actionParam);
296 
297             result = new Boolean(JetspeedSecurity.checkPermission((JetspeedUser) rundata.getUser(), 
298                                                                   portalResource, 
299                                                                   JetspeedSecurity.PERMISSION_CUSTOMIZE)).toString();
300 
301             //System.out.println("parameter=" + actionParam.getName() + ", canAccess = " + result.toString());
302         }
303 
304         return result;
305     }
306 
307     /***
308      * This method is called when the user configures any of the parameters.
309      * 
310      * @param rundata
311      * @param context The velocity context for this request.
312      */
313     public void doUpdate(RunData rundata, Context context)
314     {
315         String pageSize = null;
316 
317         Portlet portlet = (Portlet) context.get("portlet");
318         if (portlet != null)
319         {
320             String peid = portlet.getID();
321             if ((peid != null)
322                 && peid.equals(rundata.getParameters().getString(PEID)))
323             {
324                 pageSize = rundata.getParameters().getString(PAGE_SIZE);
325             }
326             if (pageSize != null)
327             {
328                 PortletConfigState.setInstanceParameter(portlet, rundata, PAGE_SIZE, pageSize);
329                 PortletSessionState.clearAttribute(portlet, rundata, PROFILE_ITERATOR);
330             }
331         }
332 
333         buildNormalContext(portlet, context, rundata);
334     }
335 
336     /***
337      * This method is to refresh psml from disk or database.
338      * 
339      * @param rundata
340      * @param context The velocity context for this request.
341      */
342     public void doRefresh(RunData rundata, Context context)
343     {
344         Portlet portlet = (Portlet) context.get("portlet");
345         PortletSessionState.clearAttribute(portlet, rundata, PROFILE_ITERATOR);
346         PortletSessionState.clearAttribute(portlet, rundata, LAST_SEARCH_TYPE);
347         PortletSessionState.clearAttribute(portlet, rundata, LAST_SEARCH_VALUE);
348         rundata.getParameters().remove(FILTER_VALUE);
349         buildNormalContext(portlet, context, rundata);
350     }
351 
352     /***
353      * This method is to enter filtering mode.
354      * 
355      * @param rundata
356      * @param context The velocity context for this request.
357      */
358     public void doFilter(RunData rundata, Context context)
359     {
360         // Is filtering requested?
361         int filterType = rundata.getParameters().getInt(FILTER_TYPE, QueryLocator.QUERY_ALL);
362         String filterValue = rundata.getParameters().getString(FILTER_VALUE, null);
363 
364         Portlet portlet = (Portlet) context.get("portlet");
365 
366         performSearch(rundata, portlet, filterType, filterValue);
367 
368         buildNormalContext(portlet, context, rundata);
369     }
370 
371     /***
372      * 
373      * @param rundata
374      * @param portlet
375      * @param type
376      * @param value
377      * @return 
378      */
379     private DatabaseBrowserIterator performSearch(RunData rundata, Portlet portlet, int type, String value)
380     {
381         // Initialize the query locator
382         QueryLocator ql = new QueryLocator(type);
383         if (value != null)
384         {
385             switch (type)
386             {
387                 case QueryLocator.QUERY_USER:
388                 {
389                     try
390                     {
391                         ql.setUser(JetspeedSecurity.getUser(value));
392                     }
393                     catch (Exception e)
394                     {
395                     }
396                 }
397                 case QueryLocator.QUERY_ROLE:
398                 {
399                     try
400                     {
401                         ql.setRole(JetspeedSecurity.getRole(value));
402                     }
403                     catch (Exception e)
404                     {
405                     }
406                 }
407                 case QueryLocator.QUERY_GROUP:
408                 {
409                     try
410                     {
411                         ql.setGroup(JetspeedSecurity.getGroup(value));
412                     }
413                     catch (Exception e)
414                     {
415                     }
416                 }
417             }
418         }
419         //ql.setQueryString(value);
420 
421         ArrayList entries = new ArrayList();
422         Iterator i = Profiler.query(ql);
423 
424         try
425         {
426             while (i.hasNext())
427             {
428                 Profile profile = (Profile) i.next();
429 
430                 if (PortletUtils.canAccessProfile(rundata, profile))
431                 {
432                     entries.add(profile);                
433                 }
434             }
435         }
436         catch (Exception e)
437         {
438             logger.error("Exception", e);
439         }
440 
441         ArrayList entryType = new ArrayList();
442         entryType.add("Profile");
443 
444         int size = Integer.parseInt(PortletConfigState.getParameter(portlet, rundata, PAGE_SIZE, "20"));
445         DatabaseBrowserIterator windowIterator = new DatabaseBrowserIterator(entries, entryType, entryType, size);
446         PortletSessionState.clearAttribute(portlet, rundata, PROFILE_ITERATOR);
447         PortletSessionState.setAttribute(portlet, rundata, PROFILE_ITERATOR, windowIterator);
448         PortletSessionState.setAttribute(portlet, rundata, LAST_SEARCH_TYPE, new Integer(type));
449         PortletSessionState.setAttribute(portlet, rundata, LAST_SEARCH_VALUE, value);
450 
451         return windowIterator;
452 
453     }
454 
455     /***
456      * Build the normal state context for detail modes.
457      *
458      * @param portlet The template-based portlet that is being built.
459      * @param context The velocity context for this request.
460      * @param rundata The turbine rundata context for this request.
461      */
462     private void buildDetailNormalContext(Portlet portlet,
463                                           Context context,
464                                           RunData rundata)
465     {
466         try
467         {
468             //
469             // if there was an error, display the message
470             //
471             String msgid = rundata.getParameters().getString(SecurityConstants.PARAM_MSGID);
472             if (msgid != null)
473             {
474                 int id = Integer.parseInt(msgid);
475                 if (id < SecurityConstants.MESSAGES.length)
476                 {
477                     context.put(SecurityConstants.PARAM_MSG, SecurityConstants.MESSAGES[id]);
478                 }
479 
480                 // get the bad entered data and put it back for convenient update
481                 ProfileLocator locator = (ProfileLocator) rundata.getUser().getTemp(TEMP_LOCATOR);
482                 if (locator != null) 
483                 {
484                     context.put("profile", Profiler.createProfile(locator));                
485                 }
486             }
487 
488             String mode = rundata.getParameters().getString(SecurityConstants.PARAM_MODE);
489             context.put(SecurityConstants.PARAM_MODE, mode);
490             String path = rundata.getParameters().getString(SecurityConstants.PARAM_ENTITY_ID);
491 
492             if (mode != null && mode.equals(SecurityConstants.PARAM_MODE_DELETE))
493             {
494                 ProfileLocator locator = Profiler.createLocator();
495                 locator.createFromPath(path);
496                 Profile profile = Profiler.getProfile(locator);
497                 if (profile != null)
498                 {
499                     rundata.getUser().setTemp(TEMP_LOCATOR, locator);
500                     context.put("profile", profile);
501                 }
502                 else
503                 {
504                     logger.error("Profile for Path:" + path + " Not Found!");
505                 }
506             }
507 
508             if (mode != null && mode.equals(SecurityConstants.PARAM_MODE_INSERT))
509             {
510                 org.apache.jetspeed.om.registry.Registry mediaTypes = Registry.get(Registry.MEDIA_TYPE);
511                 context.put("mediaTypes", mediaTypes.listEntryNames());
512                 JetspeedRunData jdata = (JetspeedRunData) rundata;
513                 context.put("defMediaType", jdata.getCapability().getPreferredMediaType());
514                 if (msgid == null)
515                 {
516                     if (((String) context.get("can-clone")).equals("false"))
517                     {
518                         context.put(CATEGORY_NAME, "user");
519                         context.put("categoryValue", rundata.getUser().getUserName());
520                         context.put("copyFrom", "none");
521                         context.put("title", "My Page");
522                     }
523                     else if (path == null)
524                     {
525                         context.put(CATEGORY_NAME, "user");
526                         context.put("categoryValue", "anon");
527                         context.put("copyFrom", "user/anon/media-type/html/page/default.psml");
528                     }
529                     else
530                     {
531                         ProfileLocator tmpLocator = Profiler.createLocator();
532                         tmpLocator.createFromPath(path);
533                         Profile profile = Profiler.getProfile(tmpLocator);
534                         if (profile != null)
535                         {
536                             rundata.getUser().setTemp(TEMP_LOCATOR, tmpLocator);
537                             context.put("profile", profile);
538                             context.put("title", profile.getRootSet().getTitle());
539                         }
540                         String categoryName = "group";
541                         String categoryValue = tmpLocator.getGroupName();
542                         if (categoryValue == null)
543                         {
544                             categoryName = "role";
545                             categoryValue = tmpLocator.getRoleName();
546                             if (categoryValue == null)
547                             {
548                                 categoryName = "user";
549                                 categoryValue = tmpLocator.getUserName();
550                                 if (categoryValue == null)
551                                 {
552                                     categoryName = "user";
553                                     categoryValue = "anon";
554                                 }
555                             }
556 
557                         }
558                         context.put(CATEGORY_NAME, categoryName);
559                         context.put("categoryValue", categoryValue);
560                         context.put("copyFrom", path);
561                     }
562                 }
563                 else
564                 {
565                     context.put(CATEGORY_NAME, rundata.getUser().getTemp(CATEGORY_NAME));
566                     context.put(CATEGORY_VALUE, rundata.getUser().getTemp(CATEGORY_VALUE));
567                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
568                 }
569             }
570 
571             if (mode != null && mode.equals("export"))
572             {
573                 if (msgid == null)
574                 {
575                     String tmpPath = JetspeedResources.getString(JetspeedResources.TEMP_DIRECTORY_KEY, "/tmp");
576                     String exportPath = JetspeedResources.getString("psml.export.default.path",
577                                                                     TurbineServlet.getRealPath(tmpPath));
578                     if (path == null)
579                     {
580                         context.put(COPY_TO, exportPath);
581                         context.put(COPY_FROM,
582                                     Profiler.PARAM_USER +
583                                     File.separator +
584                                     Profiler.PARAM_ANON +
585                                     File.separator +
586                                     Profiler.PARAM_MEDIA_TYPE +
587                                     File.separator +
588                                     "html" +
589                                     File.separator +
590                                     Profiler.PARAM_PAGE +
591                                     File.separator +
592                                     Profiler.FULL_DEFAULT_PROFILE);
593                     }
594                     else
595                     {
596                         ProfileLocator tmpLocator = Profiler.createLocator();
597                         tmpLocator.createFromPath(path);
598                         Profile profile = Profiler.getProfile(tmpLocator);
599                         if (profile != null)
600                         {
601                             rundata.getUser().setTemp(TEMP_LOCATOR, tmpLocator);
602                             context.put("profile", profile);
603                         }
604 
605                         String categoryName = Profiler.PARAM_GROUP;
606                         String categoryValue = tmpLocator.getGroupName();
607                         if (categoryValue == null)
608                         {
609                             categoryName = Profiler.PARAM_ROLE;
610                             categoryValue = tmpLocator.getRoleName();
611                             if (categoryValue == null)
612                             {
613                                 categoryName = Profiler.PARAM_USER;
614                                 categoryValue = tmpLocator.getUserName();
615                                 if (categoryValue == null)
616                                 {
617                                     categoryName = Profiler.PARAM_USER;
618                                     categoryValue = Profiler.PARAM_ANON;
619                                 }
620                             }
621 
622                         }
623 
624                         context.put(COPY_TO, exportPath + File.separator + tmpLocator.getName());
625                         context.put(COPY_FROM, path);
626                     }
627                 }
628                 else
629                 {
630                     context.put(COPY_TO, rundata.getUser().getTemp(COPY_TO));
631                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
632                 }
633             }
634 
635             if (mode != null && mode.equals("export_all"))
636             {
637                 if (msgid == null)
638                 {
639                     // get the PSML Root Directory
640                     ResourceService serviceConf = ((TurbineServices) TurbineServices.getInstance())
641                                                   .getResources(PsmlManagerService.SERVICE_NAME);
642                     String root = serviceConf.getString("root", "/WEB-INF/psml");
643                     context.put(COPY_TO, TurbineServlet.getRealPath(root));
644                 }
645                 else
646                 {
647                     context.put(COPY_TO, rundata.getUser().getTemp(COPY_TO));
648                 }
649             }
650 
651             if (mode != null && mode.equals("import"))
652             {
653                 org.apache.jetspeed.om.registry.Registry mediaTypes = Registry.get(Registry.MEDIA_TYPE);
654                 context.put("mediaTypes", mediaTypes.listEntryNames());
655                 if (msgid == null)
656                 {
657                     // get the PSML Root Directory
658                     ResourceService serviceConf = ((TurbineServices) TurbineServices.getInstance())
659                                                   .getResources(PsmlManagerService.SERVICE_NAME);
660                     String root = serviceConf.getString("root", "/WEB-INF/psml");
661                     root = TurbineServlet.getRealPath(root);
662 
663                     if (path == null)
664                     {
665                         context.put(CATEGORY_NAME, Profiler.PARAM_USER);
666                         context.put("categoryValue", Profiler.PARAM_ANON);
667                         context.put("copyFrom",
668                                     root +
669                                     File.separator +
670                                     Profiler.PARAM_USER +
671                                     File.separator +
672                                     Profiler.PARAM_ANON +
673                                     File.separator +
674                                     Profiler.PARAM_MEDIA_TYPE +
675                                     File.separator +
676                                     "html" +
677                                     File.separator +
678                                     Profiler.PARAM_PAGE +
679                                     File.separator +
680                                     Profiler.FULL_DEFAULT_PROFILE);
681                     }
682                     else
683                     {
684                         ProfileLocator tmpLocator = Profiler.createLocator();
685                         tmpLocator.createFromPath(path);
686                         Profile profile = Profiler.getProfile(tmpLocator);
687                         if (profile != null)
688                         {
689                             rundata.getUser().setTemp(TEMP_LOCATOR, tmpLocator);
690                             context.put("profile", profile);
691                         }
692                         String categoryName = Profiler.PARAM_GROUP;
693                         String categoryValue = tmpLocator.getGroupName();
694                         if (categoryValue == null)
695                         {
696                             categoryName = Profiler.PARAM_ROLE;
697                             categoryValue = tmpLocator.getRoleName();
698                             if (categoryValue == null)
699                             {
700                                 categoryName = Profiler.PARAM_USER;
701                                 categoryValue = tmpLocator.getUserName();
702                                 if (categoryValue == null)
703                                 {
704                                     categoryName = Profiler.PARAM_USER;
705                                     categoryValue = Profiler.PARAM_ANON;
706                                 }
707                             }
708 
709                         }
710                         context.put(CATEGORY_NAME, categoryName);
711                         context.put("categoryValue", categoryValue);
712                         String filePath = this.mapLocatorToFile(tmpLocator);
713                         context.put("copyFrom", root + File.separator + filePath.toString());
714                     }
715                 }
716                 else
717                 {
718                     context.put(CATEGORY_NAME, rundata.getUser().getTemp(CATEGORY_NAME));
719                     context.put(CATEGORY_VALUE, rundata.getUser().getTemp(CATEGORY_VALUE));
720                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
721                 }
722             }
723 
724             if (mode != null && mode.equals("import_all"))
725             {
726                 if (msgid == null)
727                 {
728                     // get the PSML Root Directory
729                     ResourceService serviceConf = ((TurbineServices) TurbineServices.getInstance())
730                                                   .getResources(PsmlManagerService.SERVICE_NAME);
731                     String root = serviceConf.getString("root", "/WEB-INF/psml");
732                     context.put(COPY_FROM, TurbineServlet.getRealPath(root));
733                 }
734                 else
735                 {
736                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
737                 }
738             }
739 
740         }
741         catch (Exception e)
742         {
743             logger.error("Exception", e);
744             rundata.setMessage("Error in PsmlUpdateAction: " + e.toString());
745             rundata.setStackTrace(StringUtils.stackTrace(e), e);
746             rundata.setScreenTemplate(JetspeedResources.getString("template.error", "Error"));
747         }
748     }
749 
750     /***
751      * Database Insert Action for Psml.
752      *
753      * @param rundata The turbine rundata context for this request.
754      * @param context The velocity context for this request.
755      */
756     public void doInsert(RunData rundata, Context context)
757     throws Exception
758     {
759         Profile profile = null;
760         ProfileLocator locator = null;
761         String categoryName = null;
762         String categoryValue = null;
763         String copyFrom = null;
764         String name = null;
765         String title = null;
766 
767         try
768         {
769             categoryName = rundata.getParameters().getString("CategoryName");
770             categoryValue = rundata.getParameters().getString("CategoryValue");
771             copyFrom = rundata.getParameters().getString("CopyFrom");
772             name = rundata.getParameters().getString("name");
773             title = rundata.getParameters().getString("title");
774             //
775             //create a new locator and set its values according to users input
776             //
777             locator = Profiler.createLocator();
778             if (categoryName.equalsIgnoreCase(Profiler.PARAM_GROUP))
779             {
780                 locator.setGroupByName(categoryValue);
781             }
782             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_ROLE))
783             {
784                 locator.setRoleByName(categoryValue);
785             }
786             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_USER))
787             {
788                 locator.setUser(JetspeedSecurity.getUser(categoryValue));
789             }
790             else
791             {
792                 locator.setAnonymous(true);
793             }
794 
795             String tempVar = rundata.getParameters().getString("MediaType");
796             if (tempVar != null && tempVar.trim().length() > 0)
797             {
798                 locator.setMediaType(tempVar);
799             }
800 
801             tempVar = rundata.getParameters().getString("Language");
802             if (tempVar != null && tempVar.trim().length() > 0)
803             {
804                 locator.setLanguage(tempVar);
805             }
806 
807             tempVar = rundata.getParameters().getString("Country");
808             if (tempVar != null && tempVar.trim().length() > 0)
809             {
810                 locator.setCountry(tempVar);
811             }
812 
813             if (!name.endsWith(Profiler.DEFAULT_EXTENSION))
814             {
815                 name = name + Profiler.DEFAULT_EXTENSION;
816             }
817             locator.setName(name);
818 
819             //check if profile to be created already exists
820             if (PsmlManager.getDocument(locator) != null)
821             {
822                 throw new EntityExistsException("Profile:"+locator.getPath()+" Already Exists!");            
823             }
824 
825             //
826             // validate that its not an 'blank' profile -- not allowed
827             //
828             if (name == null || name.trim().length() == 0)
829             {
830                 JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
831                 DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
832                                                    SecurityConstants.PARAM_MODE_INSERT)
833                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
834                                                SecurityConstants.MID_INVALID_ENTITY_NAME);
835                 JetspeedLinkFactory.putInstance(link);
836                 rundata.setRedirectURI(duri.toString());
837 
838                 //save user entered values
839                 if (locator != null)
840                     rundata.getUser().setTemp(TEMP_LOCATOR, locator);
841                 if (categoryName != null)
842                     rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
843                 if (categoryValue != null)
844                     rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
845                 if (copyFrom != null)
846                     rundata.getUser().setTemp(COPY_FROM, copyFrom);
847                 return;
848             }
849 
850             //
851             // retrieve the profile to clone
852             //
853             Profile baseProfile = null;
854             if (copyFrom != null && !copyFrom.equals("none"))
855             {
856                 ProfileLocator baseLocator = Profiler.createLocator();
857                 baseLocator.createFromPath(copyFrom);
858                 baseProfile = Profiler.getProfile(baseLocator);
859             }
860 
861             //
862             // create a new profile
863             //
864 
865             // AT THIS POINT "portlet" is null ????
866             //Portlet portlet = (Portlet) context.get("portlet");
867             //PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, portlet.getName());
868 
869             if (copyFrom.equals("none"))
870             {
871                 profile = Profiler.createProfile(locator, null);
872                 profile.getDocument().getPortlets().setTitle(title);
873                 profile.store();
874                 //System.out.println("Profile title: " + profile.getDocument().getPortlets().getTitle() + " for " + profile.getDocument().getPortlets());
875                 setRefreshPsmlFlag(rundata, TRUE);
876             }
877             else if (baseProfile != null)
878             {
879                 PSMLDocument doc = baseProfile.getDocument();
880                 if (doc != null)
881                 {
882                     Portlets portlets = doc.getPortlets();
883                     
884                     Portlets clonedPortlets = (Portlets) SerializationUtils.clone(portlets);
885                     org.apache.jetspeed.util.PortletUtils.regenerateIds(clonedPortlets);
886                     profile = Profiler.createProfile(locator, clonedPortlets);
887                 }
888                 else
889                 {
890                     profile = Profiler.createProfile(locator, null);
891                 }
892                 setRefreshPsmlFlag(rundata, TRUE);
893             }
894             else
895             {
896                 logger.error("Profile listed in Copy From Not Found!");
897             }
898 
899             goBackToBrowser(rundata);
900         }
901         catch (EntityExistsException e)
902         {
903             // log the error msg
904             logger.error("Exception", e);
905 
906             //
907             // dup key found - display error message - bring back to same screen
908             //
909             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
910             DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
911                                                SecurityConstants.PARAM_MODE_INSERT)
912                               .addPathInfo(SecurityConstants.PARAM_MSGID,
913                                            SecurityConstants.MID_ENTITY_ALREADY_EXISTS);
914             JetspeedLinkFactory.putInstance(link);
915             rundata.setRedirectURI(duri.toString());
916         }
917         catch (Exception e)
918         {
919             // log the error msg
920             logger.error("Exception", e);
921 
922             //
923             // dup key found - display error message - bring back to same screen
924             //
925             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
926             DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
927                                                SecurityConstants.PARAM_MODE_INSERT)
928                               .addPathInfo(SecurityConstants.PARAM_MSGID,
929                                            SecurityConstants.MID_UPDATE_FAILED);
930             JetspeedLinkFactory.putInstance(link);
931             rundata.setRedirectURI(duri.toString());
932         }
933         // save values that user just entered so they don't have to re-enter
934         if (locator != null)
935             rundata.getUser().setTemp(TEMP_LOCATOR, locator);
936         if (categoryName != null)
937             rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
938         if (categoryValue != null)
939             rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
940         if (copyFrom != null)
941             rundata.getUser().setTemp(COPY_FROM, copyFrom);
942 
943     }
944 
945     /***
946      * Delete Psml entry
947      * 
948      * @param rundata
949      * @param context
950      * @exception Exception
951      */
952     public void doDelete(RunData rundata, Context context) throws Exception
953     {
954         try
955         {
956             ProfileLocator locator = (ProfileLocator)rundata.getUser().getTemp(TEMP_LOCATOR);
957             if (locator != null)
958             {
959                 Profiler.removeProfile(locator);
960                 setRefreshPsmlFlag(rundata, TRUE);
961             }
962             else
963             {
964                 logger.error("ProfileLocator not found!");
965             }
966         }
967         catch (Exception e)
968         {
969             // log the error msg
970             logger.error("Exception", e);
971 
972             //
973             // dup key found - display error message - bring back to same screen
974             //
975             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
976             DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE, SecurityConstants.PARAM_MODE_DELETE)
977                               .addPathInfo(SecurityConstants.PARAM_MSGID,
978                                            SecurityConstants.MID_DELETE_FAILED);
979             JetspeedLinkFactory.putInstance(link);
980             rundata.setRedirectURI(duri.toString());
981         }
982 
983     }
984 
985     /***
986      * 
987      * @param rundata
988      * @param value
989      */
990     private void setRefreshPsmlFlag(RunData rundata, String value)
991     {
992         rundata.getUser().setTemp(PSML_REFRESH_FLAG, value);
993         if (value.equals(TRUE))
994         {
995             rundata.getUser().removeTemp(CACHED_PSML);
996         }
997     }
998 
999     /***
1000      * 
1001      * @param rundata
1002      * @return 
1003      */
1004     private boolean getRefreshPsmlFlag(RunData rundata)
1005     {
1006         return (rundata.getUser().getTemp(PSML_REFRESH_FLAG, FALSE)).equals(TRUE);
1007     }
1008 
1009     /***
1010      * File Export Action for Psml.
1011      *
1012      * @param rundata The turbine rundata context for this request.
1013      * @param context The velocity context for this request.
1014      */
1015     public void doExport(RunData rundata, Context context)
1016     throws Exception
1017     {
1018         Profile profile = null;
1019         ProfileLocator locator = null;
1020         String copyTo = null;
1021         String copyFrom = null;
1022 
1023         try
1024         {
1025             copyFrom = rundata.getParameters().getString("CopyFrom");
1026             copyTo = rundata.getParameters().getString("CopyTo");
1027 
1028             //
1029             // retrieve the profile to clone
1030             //
1031             ProfileLocator baseLocator = Profiler.createLocator();
1032             baseLocator.createFromPath(copyFrom);
1033             Profile baseProfile = Profiler.getProfile(baseLocator);
1034 
1035             //
1036             // Export profile
1037             //
1038             if (baseProfile != null)
1039             {
1040                 PSMLDocument doc = baseProfile.getDocument();
1041                 if (doc != null)
1042                 {
1043                     if (!this.saveDocument(copyTo,doc))
1044                         throw new Exception("Failed to save PSML document");
1045                     rundata.addMessage("Profile [" + copyFrom + "] has been saved to disk in [" + copyTo + "]<br>");
1046                 }
1047             }
1048             else
1049             {
1050                 logger.error("Profile listed in Copy From Not Found!");
1051             }
1052         }
1053         catch (Exception e)
1054         {
1055             // log the error msg
1056             logger.error("Exception", e);
1057 
1058             //
1059             // dup key found - display error message - bring back to same screen
1060             //
1061             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1062             DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
1063                                                "export")
1064                               .addPathInfo(SecurityConstants.PARAM_MSGID,
1065                                            SecurityConstants.MID_UPDATE_FAILED);
1066             JetspeedLinkFactory.putInstance(link);
1067             rundata.setRedirectURI(duri.toString());
1068         }
1069         // save values that user just entered so they don't have to re-enter
1070         if (copyTo != null)
1071             rundata.getUser().setTemp(COPY_TO, copyTo);
1072         if (copyFrom != null)
1073             rundata.getUser().setTemp(COPY_FROM, copyFrom);
1074 
1075     }
1076 
1077     /***
1078      * File Export All Action for Psml.
1079      *
1080      * @param rundata The turbine rundata context for this request.
1081      * @param context The velocity context for this request.
1082      */
1083     public void doExportall(RunData rundata, Context context)
1084     throws Exception
1085     {
1086         String copyTo = null;
1087 
1088         logger.info("PsmlUpdateAction: Starting export all operation");
1089 
1090         try
1091         {
1092             copyTo = rundata.getParameters().getString("CopyTo");
1093 
1094             //
1095             // retrieve the profiles to export
1096             //
1097             Iterator i = Profiler.query(new QueryLocator(QueryLocator.QUERY_ALL));
1098             while (i.hasNext())
1099             {
1100                 Profile profile = (Profile) i.next();
1101                 PSMLDocument doc = profile.getDocument();
1102                 if (doc != null)
1103                 {
1104                     // Build the fully qualified file name
1105                     StringBuffer copyToFile = new StringBuffer(copyTo);
1106                     copyToFile.append(File.separator);
1107                     if (profile.getGroupName() != null)
1108                     {
1109                         copyToFile.append("group");
1110                         copyToFile.append(File.separator);
1111                         copyToFile.append(profile.getGroupName());
1112                         copyToFile.append(File.separator);
1113                     }
1114                     else if (profile.getRoleName() != null)
1115                     {
1116                         copyToFile.append("role");
1117                         copyToFile.append(File.separator);
1118                         copyToFile.append(profile.getRoleName());
1119                         copyToFile.append(File.separator);
1120                     }
1121                     else if (profile.getUserName() != null)
1122                     {
1123                         copyToFile.append("user");
1124                         copyToFile.append(File.separator);
1125                         copyToFile.append(profile.getUserName());
1126                         copyToFile.append(File.separator);
1127                     }
1128                     if (profile.getMediaType() != null)
1129                     {
1130                         copyToFile.append(profile.getMediaType());
1131                         copyToFile.append(File.separator);
1132                     }
1133                     if (profile.getLanguage() != null)
1134                     {
1135                         copyToFile.append(profile.getLanguage());
1136                         copyToFile.append(File.separator);
1137                     }
1138                     if (profile.getCountry() != null)
1139                     {
1140                         copyToFile.append(profile.getCountry());
1141                         copyToFile.append(File.separator);
1142                     }
1143                     copyToFile.append(profile.getName());
1144 
1145                     if (!this.saveDocument(copyToFile.toString(), doc))
1146                     {
1147                         logger.error("Failed to save PSML document for [" + profile.getPath());
1148                     }
1149                     else
1150                     {
1151                         String msg = "Profile [" + profile.getPath() + "] has been saved to disk in [" + copyToFile.toString() + "]<br>";
1152                         logger.info(msg);
1153                         rundata.addMessage(msg);
1154                     }
1155                 }
1156             }
1157 
1158         }
1159         catch (Exception e)
1160         {
1161             // log the error msg
1162             logger.error("Exception", e);
1163 
1164             //
1165             // dup key found - display error message - bring back to same screen
1166             //
1167             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1168             DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
1169                                                "export_all")
1170                               .addPathInfo(SecurityConstants.PARAM_MSGID,
1171                                            SecurityConstants.MID_UPDATE_FAILED);
1172             JetspeedLinkFactory.putInstance(link);
1173             rundata.setRedirectURI(duri.toString());
1174         }
1175         // save values that user just entered so they don't have to re-enter
1176         if (copyTo != null)
1177         {
1178             rundata.getUser().setTemp(COPY_TO, copyTo);
1179         }
1180 
1181         logger.info("PsmlUpdateAction: Ending export all operation");
1182     }
1183 
1184     /***
1185      * Save the PSML document on disk to the specififed fileOrUrl
1186      * 
1187      * @param fileOrUrl a String representing either an absolute URL
1188      *                  or an absolute filepath
1189      * @param doc       the document to save
1190      * @return 
1191      */
1192     private boolean saveDocument(String fileOrUrl, PSMLDocument doc)
1193     {
1194         boolean success = false;
1195 
1196         if (doc == null) return false;
1197         File f = new File(fileOrUrl);
1198         File d = new File(f.getParent());
1199         d.mkdirs();
1200 
1201         FileWriter writer = null;
1202 
1203         try
1204         {
1205             writer = new FileWriter(f);
1206             // create the serializer output format
1207             OutputFormat format = new OutputFormat();
1208             format.setIndenting(true);
1209             format.setIndent(4);
1210             Serializer serializer = new XMLSerializer(writer,format);
1211             Marshaller marshaller = new Marshaller(serializer.asDocumentHandler());
1212             marshaller.setMapping(this.loadMapping());
1213             marshaller.marshal(doc.getPortlets());
1214 
1215             success = true;
1216         }
1217         catch (MarshalException e)
1218         {
1219             logger.error("PsmlManagerAction: Could not marshal the file " + f.getAbsolutePath(), e);
1220         }
1221         catch (MappingException e)
1222         {
1223             logger.error("PsmlManagerAction: Could not marshal the file " + f.getAbsolutePath(), e);
1224         }
1225         catch (ValidationException e)
1226         {
1227             logger.error("PsmlManagerAction: document "+f.getAbsolutePath() + " is not valid", e);
1228         }
1229         catch (IOException e)
1230         {
1231             logger.error("PsmlManagerAction: Could not save the file " + f.getAbsolutePath(), e);
1232         }
1233         catch (Exception e)
1234         {
1235             logger.error("PsmlManagerAction: Error while saving  " + f.getAbsolutePath(), e);
1236         }
1237         finally
1238         {
1239             try
1240             {
1241                 writer.close();
1242             }
1243             catch (IOException e)
1244             {
1245             }
1246         }
1247 
1248         return success;
1249     }
1250 
1251     /***
1252      * Loads psml mapping file
1253      *
1254      * @exception Exception
1255      */
1256     private Mapping loadMapping()
1257     throws Exception
1258     {
1259         // get configuration parameters from Jetspeed Resources
1260         ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
1261                                       .getResources(PsmlManagerService.SERVICE_NAME);
1262 
1263         // test the mapping file and create the mapping object
1264         Mapping mapping = null;
1265         String mapFile = serviceConf.getString("mapping","${webappRoot}/WEB-INF/conf/psml-mapping.xml");
1266         mapFile = TurbineServlet.getRealPath( mapFile );
1267         if (mapFile != null)
1268         {
1269             File map = new File(mapFile);
1270             if (logger.isDebugEnabled())
1271             {
1272                 logger.debug( "Loading psml mapping file " + mapFile );
1273             }
1274             if (map.exists() && map.isFile() && map.canRead())
1275             {
1276                 try
1277                 {
1278                     mapping = new Mapping();
1279                     InputSource is = new InputSource( new FileReader(map) );
1280                     is.setSystemId( mapFile );
1281                     mapping.loadMapping( is );
1282                 }
1283                 catch (Exception e)
1284                 {
1285                     logger.error("Error in psml mapping creation", e);
1286                     throw new Exception("Error in mapping");
1287                 }
1288             }
1289             else
1290             {
1291                 throw new Exception("PSML Mapping not found or not a file or unreadable: " + mapFile);
1292             }
1293         }
1294 
1295         return mapping;
1296     }
1297 
1298     /***
1299      * File Import Action for Psml.
1300      *
1301      * TODO: Implement file upload.
1302      *
1303      * @param rundata The turbine rundata context for this request.
1304      * @param context The velocity context for this request.
1305      */
1306     public void doImport(RunData rundata, Context context)
1307     throws Exception
1308     {
1309         Profile profile = null;
1310         ProfileLocator locator = null;
1311         String categoryName = null;
1312         String categoryValue = null;
1313         String copyFrom = null;
1314         String name = null;
1315 
1316         try
1317         {
1318             categoryName = rundata.getParameters().getString("CategoryName");
1319             categoryValue = rundata.getParameters().getString("CategoryValue");
1320             copyFrom = rundata.getParameters().getString("CopyFrom");
1321             name = rundata.getParameters().getString("name");
1322             //
1323             //create a new locator and set its values according to users input
1324             //
1325             locator = Profiler.createLocator();
1326             if (categoryName.equalsIgnoreCase(Profiler.PARAM_GROUP))
1327             {
1328                 locator.setGroupByName(categoryValue);
1329             }
1330             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_ROLE))
1331             {
1332                 locator.setRoleByName(categoryValue);
1333             }
1334             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_USER))
1335             {
1336                 locator.setUser(JetspeedSecurity.getUser(categoryValue));
1337             }
1338             else
1339             {
1340                 locator.setAnonymous(true);
1341             }
1342 
1343             String tempVar = rundata.getParameters().getString("MediaType");
1344             if (tempVar != null && tempVar.trim().length() > 0)
1345             {
1346                 locator.setMediaType(tempVar);
1347             }
1348 
1349             tempVar = rundata.getParameters().getString("Language");
1350             if (tempVar != null && tempVar.trim().length() > 0)
1351             {
1352                 locator.setLanguage(tempVar);
1353             }
1354 
1355             tempVar = rundata.getParameters().getString("Country");
1356             if (tempVar != null && tempVar.trim().length() > 0)
1357             {
1358                 locator.setCountry(tempVar);
1359             }
1360 
1361             locator.setName(name);
1362 
1363             //
1364             // validate that its not an 'blank' profile -- not allowed
1365             //
1366             if (name == null || name.trim().length() == 0)
1367             {
1368                 JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1369                 DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
1370                                                    "import")
1371                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
1372                                                SecurityConstants.MID_INVALID_ENTITY_NAME);
1373                 JetspeedLinkFactory.putInstance(link);
1374                 rundata.setRedirectURI(duri.toString());
1375 
1376                 //save user entered values
1377                 if (locator != null)
1378                 {
1379                     rundata.getUser().setTemp(TEMP_LOCATOR, locator);
1380                 }
1381                 if (categoryName != null)
1382                 {
1383                     rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
1384                 }
1385                 if (categoryValue != null)
1386                 {
1387                     rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
1388                 }
1389                 if (copyFrom != null)
1390                 {
1391                     rundata.getUser().setTemp(COPY_FROM, copyFrom);
1392                 }
1393                 return;
1394             }
1395 
1396             //
1397             // Retrieve the document to import
1398             //
1399             PSMLDocument doc = this.loadDocument(copyFrom);
1400 
1401             //
1402             // create a new profile
1403             //
1404             if (doc != null)
1405             {
1406                 Portlets portlets = doc.getPortlets();
1407                 //
1408                 // Profiler does not provide update capability - must remove before replacing
1409                 //
1410                 if (PsmlManager.getDocument(locator) != null)
1411                 {
1412                     Profiler.removeProfile(locator);
1413                 }
1414                 profile = Profiler.createProfile(locator, portlets);
1415             }
1416             else
1417             {
1418                 throw new Exception("Failed to load PSML document from disk");
1419             }
1420             rundata.addMessage("Profile for [" + locator.getPath() + "] has been imported from file [" + copyFrom + "]<br>");
1421             setRefreshPsmlFlag(rundata, TRUE);
1422 
1423             goBackToBrowser(rundata);
1424 
1425         }
1426         catch (Exception e)
1427         {
1428             // log the error msg
1429             logger.error("Exception", e);
1430 
1431             //
1432             // dup key found - display error message - bring back to same screen
1433             //
1434             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1435             DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
1436                                                "import")
1437                               .addPathInfo(SecurityConstants.PARAM_MSGID,
1438                                            SecurityConstants.MID_UPDATE_FAILED);
1439             JetspeedLinkFactory.putInstance(link);
1440             rundata.setRedirectURI(duri.toString());
1441         }
1442         // save values that user just entered so they don't have to re-enter
1443         if (locator != null)
1444         {
1445             rundata.getUser().setTemp(TEMP_LOCATOR, locator);
1446         }
1447         if (categoryName != null)
1448         {
1449             rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
1450         }
1451         if (categoryValue != null)
1452         {
1453             rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
1454         }
1455         if (copyFrom != null)
1456         {
1457             rundata.getUser().setTemp(COPY_FROM, copyFrom);
1458         }
1459 
1460     }
1461 
1462     /***
1463      * File Import All Action for Psml.
1464      * 
1465      * @param rundata The turbine rundata context for this request.
1466      * @param context The velocity context for this request.
1467      * @exception Exception
1468      */
1469     public void doImportall(RunData rundata, Context context)
1470     throws Exception
1471     {
1472         String copyFrom = null;
1473 
1474         try
1475         {
1476             copyFrom = rundata.getParameters().getString("CopyFrom");
1477 
1478             //
1479             // Collect all .psml files from the root specified
1480             //
1481             Vector files = new Vector();
1482             this.collectPsml(files, copyFrom);
1483 
1484             //
1485             // Process each file
1486             //
1487             for (Iterator it = files.iterator(); it.hasNext();)
1488             {
1489                 // If error occurs processing one entry, continue on with the others
1490                 String path = null;
1491                 try
1492                 {
1493                     String psml = ((File) it.next()).getPath();
1494                     path = psml.substring(copyFrom.length() + 1);
1495                     ProfileLocator locator = this.mapFileToLocator(path);
1496 
1497                     PSMLDocument doc = this.loadDocument(psml);
1498 
1499                     //
1500                     // create a new profile
1501                     //
1502                     if (doc != null)
1503                     {
1504                         Portlets portlets = doc.getPortlets();
1505                         //
1506                         // Profiler does not provide update capability - must remove before replacing
1507                         //
1508                         if (PsmlManager.getDocument(locator) != null)
1509                         {
1510                             Profiler.removeProfile(locator);
1511                         }
1512                         
1513                         Portlets clonedPortlets = (Portlets) SerializationUtils.clone(portlets);
1514                         org.apache.jetspeed.util.PortletUtils.regenerateIds(clonedPortlets);
1515                         Profiler.createProfile(locator, clonedPortlets);
1516                     }
1517                     else
1518                     {
1519                         throw new Exception("Failed to load PSML document [" + psml + "] from disk");
1520                     }
1521                     rundata.addMessage("Profile for [" + locator.getPath() + "] has been imported from file [" + psml + "]<br>");
1522                     setRefreshPsmlFlag(rundata, TRUE);
1523                 }
1524                 catch (Exception ouch)
1525                 {
1526                     logger.error("Exception", ouch);
1527                     rundata.addMessage("ERROR importing file [" + path + "]: " + ouch.toString() + "<br>");
1528                 }
1529             }
1530 
1531         }
1532         catch (Exception e)
1533         {
1534             // log the error msg
1535             logger.error("Exception", e);
1536 
1537             //
1538             // dup key found - display error message - bring back to same screen
1539             //
1540             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1541             DynamicURI duri = link.addPathInfo(SecurityConstants.PARAM_MODE,
1542                                                "import_all")
1543                               .addPathInfo(SecurityConstants.PARAM_MSGID,
1544                                            SecurityConstants.MID_UPDATE_FAILED);
1545             JetspeedLinkFactory.putInstance(link);
1546             rundata.setRedirectURI(duri.toString());
1547         }
1548         // save values that user just entered so they don't have to re-enter
1549         if (copyFrom != null)
1550         {
1551             rundata.getUser().setTemp(COPY_FROM, copyFrom);
1552         }
1553 
1554     }
1555 
1556     /***
1557      * This method recursively collect all .psml documents starting at the given root
1558      *
1559      * @param v      Vector to put the file into
1560      * @param root   Root directory for import
1561      */
1562     private void collectPsml(Vector v, String root)
1563     {
1564 
1565         File dir = new File(root);
1566         File[] files = dir.listFiles();
1567         for (int i = 0; i < files.length; i++)
1568         {
1569             if (files[i].isDirectory())
1570             {
1571                 collectPsml(v, files[i].getPath());
1572             }
1573             else if (files[i].isFile() && files[i].getPath().endsWith(".psml"))
1574             {
1575                 v.add(files[i]);
1576             }
1577         }
1578 
1579     }
1580 
1581     /***
1582      * Creates profile locator from a given path in the format:
1583      *
1584      *   user/<name>/<mediaType>/<language>/<country>/<page>/
1585      *
1586      *   group/ ""
1587      *   role/  ""
1588      *
1589      * @param path The formatted profiler path string.
1590      * @param path   fully qualified .psml file name
1591      * @return profile locator
1592      */
1593     private ProfileLocator mapFileToLocator(String path)
1594     throws Exception
1595     {
1596         if (logger.isDebugEnabled())
1597         {
1598             logger.debug("PsmlUpdateAction.createFromPath: processing path = " + path);
1599         }
1600         ProfileLocator result = Profiler.createLocator();
1601 
1602         // Tokenize the file path into elements
1603         StringTokenizer tok = new StringTokenizer(path, File.separator);
1604 
1605         // Load path elements into a vector for random access
1606         Vector tokens = new Vector();
1607         while (tok.hasMoreTokens())
1608         {
1609             tokens.add(tok.nextToken());
1610         }
1611 
1612         // Assume that 1st element is the profile type (user|role|group) and 2nd is the name
1613         if (tokens.size() > 1)
1614         {
1615             String type = (String) tokens.elementAt(0);
1616             String name = (String) tokens.elementAt(1);
1617             if (type.equals(Profiler.PARAM_USER))
1618             {
1619                 result.setUser(JetspeedSecurity.getUser(name));
1620             }
1621             else if (type.equals(Profiler.PARAM_GROUP))
1622             {
1623                 result.setGroup(JetspeedSecurity.getGroup(name));
1624             }
1625             else if (type.equals(Profiler.PARAM_ROLE))
1626             {
1627                 result.setRole(JetspeedSecurity.getRole(name));
1628             }
1629         }
1630 
1631         // Assume that the last element is the page name
1632         if (tokens.size() > 0)
1633         {
1634             result.setName((String) tokens.lastElement());
1635         }
1636 
1637         // Based on the number of path elements set the other profile attributes
1638         switch (tokens.size())
1639         {
1640         case 3: // user|role|group/name/page.psml
1641             break;
1642         case 4: // user|role|group/name/media-type/page.psml
1643             result.setMediaType((String) tokens.elementAt(2));
1644             break;
1645         case 5: // user|role|group/name/media-type/language/page.psml
1646             result.setMediaType((String) tokens.elementAt(2));
1647             result.setLanguage((String) tokens.elementAt(3));
1648             break;
1649         case 6: // user|role|group/name/media-type/language/country/page.psml
1650             result.setMediaType((String) tokens.elementAt(2));
1651             result.setLanguage((String) tokens.elementAt(3));
1652             result.setCountry((String) tokens.elementAt(4));
1653             break;
1654         default:
1655             throw new Exception("Path must contain 3 to 6 elements: [" + path + "], and the size was: " + tokens.size());
1656         }
1657 
1658         return result;
1659     }
1660 
1661     /***
1662      * Maps a ProfileLocator to a file.
1663      *
1664      * @param locator The profile locator describing the PSML resource to be found.
1665      * @return the String path of the file.
1666      */
1667     private String mapLocatorToFile(ProfileLocator locator)
1668     {
1669         StringBuffer path = new StringBuffer();
1670 
1671         // move the base dir is either user or role is specified
1672         Role role = locator.getRole();
1673         Group group = locator.getGroup();
1674         JetspeedUser user = locator.getUser();
1675 
1676         if (user != null)
1677         {
1678             path.append(Profiler.PARAM_USER);
1679             String name = user.getUserName();
1680             if (null != name && name.length() > 0)
1681             {
1682                 path.append(File.separator)
1683                 .append(name);
1684             }
1685         }
1686         else if (group != null)
1687         {
1688             path.append(Profiler.PARAM_GROUP);
1689             String name = group.getName();
1690             if (null != name && name.length() > 0)
1691             {
1692                 path.append(File.separator)
1693                 .append(name);
1694             }
1695         }
1696         else if (null != role)
1697         {
1698             path.append(Profiler.PARAM_ROLE);
1699             String name = role.getName();
1700             if (null != name && name.length() > 0)
1701             {
1702                 path.append(File.separator)
1703                 .append(name);
1704             }
1705         }
1706 
1707         // Media
1708         if (null != locator.getMediaType())
1709         {
1710             path.append(File.separator)
1711             .append(locator.getMediaType());
1712         }
1713         // Language
1714         if (null != locator.getLanguage())
1715         {
1716             path.append(File.separator)
1717             .append(locator.getLanguage());
1718         }
1719         // Country
1720         if (null != locator.getCountry())
1721         {
1722             path.append(File.separator)
1723             .append(locator.getCountry());
1724         }
1725         // Resource Name
1726         if (null != locator.getName())
1727         {
1728             if (!(locator.getName().endsWith(Profiler.DEFAULT_EXTENSION)))
1729             {
1730                 path.append(File.separator)
1731                 .append(locator.getName()).append(Profiler.DEFAULT_EXTENSION);
1732             }
1733             else
1734             {
1735                 path.append(File.separator)
1736                 .append(locator.getName());
1737             }
1738         }
1739         else
1740         {
1741             path.append(File.separator)
1742             .append(Profiler.FULL_DEFAULT_PROFILE);
1743         }
1744 
1745         return  path.toString();
1746     }
1747 
1748     /***
1749      * Load a PSMLDOcument from disk
1750      *
1751      * @param fileOrUrl a String representing either an absolute URL or an
1752      * absolute filepath
1753      */
1754     private PSMLDocument loadDocument(String fileOrUrl)
1755     {
1756         PSMLDocument doc = null;
1757 
1758         if (fileOrUrl != null)
1759         {
1760 
1761             // we'll assume the name is the the location of the file
1762             File f = null;
1763 
1764             f = new File(fileOrUrl);
1765 
1766             if (!f.exists())
1767             {
1768                 return null;
1769             }
1770 
1771             doc = new BasePSMLDocument();
1772             doc.setName(fileOrUrl);
1773 
1774             // now that we have a file reference, try to load the serialized PSML
1775             Portlets portlets = null;
1776             FileReader reader = null;
1777             try
1778             {
1779                 reader = new FileReader(f);
1780 
1781                 Unmarshaller unmarshaller = new Unmarshaller(this.loadMapping());
1782                 portlets = (Portlets) unmarshaller.unmarshal(reader);
1783 
1784                 doc.setPortlets(portlets);
1785 
1786             }
1787             catch (IOException e)
1788             {
1789                 logger.error("PsmlManagerAction: Could not load the file " + f.getAbsolutePath(), e);
1790             }
1791             catch (MarshalException e)
1792             {
1793                 logger.error("PsmlManagerAction: Could not unmarshal the file " + f.getAbsolutePath(), e);
1794             }
1795             catch (MappingException e)
1796             {
1797                 logger.error("PsmlManagerAction: Could not unmarshal the file " + f.getAbsolutePath(), e);
1798             }
1799             catch (ValidationException e)
1800             {
1801                 logger.error("PsmlManagerAction: document " + f.getAbsolutePath() + " is not valid", e);
1802             }
1803             catch (Exception e)
1804             {
1805                 logger.error("PsmlManagerAction: Error while loading  " + f.getAbsolutePath(), e);
1806             }
1807             finally
1808             {
1809                 try
1810                 {
1811                     reader.close();
1812                 }
1813                 catch (IOException e)
1814                 {
1815                 }
1816             }
1817         }
1818 
1819         return doc;
1820     }
1821 
1822     /***
1823      * 
1824      * @param rundata
1825      */
1826     private void goBackToBrowser(RunData rundata) throws Exception
1827     {
1828         JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1829         rundata.setRedirectURI(link.toString());
1830         JetspeedLinkFactory.putInstance(link);
1831     }
1832 }