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  // Turbine stuff
20  import org.apache.turbine.util.DynamicURI;
21  import org.apache.turbine.util.RunData;
22  import org.apache.turbine.util.StringUtils;
23  import org.apache.turbine.util.security.EntityExistsException;
24  import org.apache.turbine.services.TurbineServices;
25  import org.apache.turbine.services.servlet.TurbineServlet;
26  import org.apache.turbine.services.resources.ResourceService;
27  
28  // Velocity Stuff
29  import org.apache.velocity.context.Context;
30  
31  //Java
32  import java.io.File;
33  import java.io.FileWriter;
34  import java.io.FileReader;
35  import java.io.IOException;
36  import java.util.Iterator;
37  import java.util.Vector;
38  import java.util.StringTokenizer;
39  
40  //Jetspeed
41  import org.apache.commons.lang.SerializationUtils;
42  import org.apache.jetspeed.modules.actions.portlets.security.SecurityConstants;
43  import org.apache.jetspeed.om.profile.Profile;
44  import org.apache.jetspeed.om.profile.ProfileLocator;
45  import org.apache.jetspeed.om.profile.QueryLocator;
46  import org.apache.jetspeed.om.profile.PSMLDocument;
47  import org.apache.jetspeed.om.profile.Portlets;
48  import org.apache.jetspeed.portal.portlets.VelocityPortlet;
49  import org.apache.jetspeed.services.Profiler;
50  import org.apache.jetspeed.services.Registry;
51  import org.apache.jetspeed.services.JetspeedSecurity;
52  import org.apache.jetspeed.services.PsmlManager;
53  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
54  import org.apache.jetspeed.services.logging.JetspeedLogger;
55  import org.apache.jetspeed.util.template.JetspeedLink;
56  import org.apache.jetspeed.util.template.JetspeedLinkFactory;
57  import org.apache.jetspeed.services.resources.JetspeedResources;
58  import org.apache.jetspeed.services.psmlmanager.PsmlManagerService;
59  import org.apache.jetspeed.om.profile.BasePSMLDocument;
60  import org.apache.jetspeed.om.security.JetspeedUser;
61  import org.apache.jetspeed.om.security.Role;
62  import org.apache.jetspeed.om.security.Group;
63  
64  //castor support
65  import org.exolab.castor.xml.MarshalException;
66  import org.exolab.castor.xml.Marshaller;
67  import org.exolab.castor.xml.Unmarshaller;
68  import org.exolab.castor.xml.ValidationException;
69  import org.exolab.castor.mapping.Mapping;
70  import org.exolab.castor.mapping.MappingException;
71  import org.xml.sax.InputSource;
72  
73  // serialization support
74  import org.apache.xml.serialize.Serializer;
75  import org.apache.xml.serialize.XMLSerializer;
76  import org.apache.xml.serialize.OutputFormat;
77  
78  /***
79   * This action enables to update the psml entries
80   *
81   * @author <a href="mailto:david@apache.org">David Sean Taylor</a>
82   * @version $Id: PsmlUpdateAction.java,v 1.18 2004/03/31 04:49:10 morciuch Exp $
83   */
84  public class PsmlUpdateAction extends SecureVelocityPortletAction
85  {
86  
87      protected static final String PSML_REFRESH_FLAG = "psmlRefreshFlag";
88      protected static final String TRUE = "true";
89      protected static final String FALSE = "false";
90      protected static final String CATEGORY_NAME = "categoryName";
91      protected static final String CATEGORY_VALUE = "categoryValue";
92      protected static final String COPY_FROM = "copyFrom";
93      protected static final String COPY_TO = "copyTo";
94      protected static final String TEMP_LOCATOR = "tempLocator";
95      protected static final String PSML_UPDATE_PANE = "PsmlForm";
96      
97      /***
98       * Static initialization of the logger for this class
99       */    
100     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(PsmlUpdateAction.class.getName());    
101     
102     /***
103      * Subclasses must override this method to provide default behavior
104      * for the portlet action
105      */
106     /***
107      * Build the normal state content for this portlet.
108      *
109      * @param portlet The velocity-based portlet that is being built.
110      * @param context The velocity context for this request.
111      * @param rundata The turbine rundata context for this request.
112      */
113     protected void buildNormalContext( VelocityPortlet portlet,
114                                        Context context,
115                                        RunData rundata )
116     {
117         try
118         {
119             //
120             // if there was an error, display the message
121             //
122             String msgid = rundata.getParameters().getString(SecurityConstants.PARAM_MSGID);
123             if (msgid != null)
124             {
125                 int id = Integer.parseInt(msgid);
126                 if (id < SecurityConstants.MESSAGES.length)
127                     context.put(SecurityConstants.PARAM_MSG, SecurityConstants.MESSAGES[id]);
128 
129                 // get the bad entered data and put it back for convenient update
130                  ProfileLocator locator = (ProfileLocator)rundata.getUser().getTemp(TEMP_LOCATOR);
131                 if (locator != null)
132                     context.put("profile", Profiler.createProfile(locator));
133             }
134 
135             String mode = rundata.getParameters().getString(SecurityConstants.PARAM_MODE);
136             context.put(SecurityConstants.PARAM_MODE, mode);
137             String path = rundata.getParameters().getString(SecurityConstants.PARAM_ENTITY_ID);
138 
139             if(mode != null && mode.equals(SecurityConstants.PARAM_MODE_DELETE))
140             {
141                 ProfileLocator locator = Profiler.createLocator();
142                 locator.createFromPath(path);
143                 Profile profile = Profiler.getProfile(locator);
144                if (profile != null)
145                {
146                    rundata.getUser().setTemp(TEMP_LOCATOR, locator);
147                    context.put("profile", profile);
148                }
149                else
150                    logger.error("Profile for Path:"+path+" Not Found!");
151             }
152 
153             if(mode != null && mode.equals(SecurityConstants.PARAM_MODE_INSERT))
154             {
155                 org.apache.jetspeed.om.registry.Registry mediaTypes = Registry.get(Registry.MEDIA_TYPE);
156                 context.put("mediaTypes", mediaTypes.listEntryNames());
157                 if (msgid == null)
158                 {
159                     if(path == null)
160                     {
161                         context.put(CATEGORY_NAME, "user");
162                         context.put("categoryValue", "anon");
163                         context.put("copyFrom", "user/anon/media-type/html/page/default.psml");
164                     }
165                     else
166                     {
167                         ProfileLocator tmpLocator = Profiler.createLocator();
168                         tmpLocator.createFromPath(path);
169                         Profile profile = Profiler.getProfile(tmpLocator);
170                         if (profile != null)
171                         {
172                             rundata.getUser().setTemp(TEMP_LOCATOR, tmpLocator);
173                             context.put("profile", profile);
174                         }
175                         String categoryName = "group";
176                         String categoryValue = tmpLocator.getGroupName();
177                         if (categoryValue == null)
178                         {
179                             categoryName = "role";
180                             categoryValue = tmpLocator.getRoleName();
181                             if (categoryValue == null)
182                             {
183                                 categoryName = "user";
184                                 categoryValue = tmpLocator.getUserName();
185                                 if (categoryValue == null)
186                                 {
187                                     categoryName = "user";
188                                     categoryValue = "anon";
189                                 }
190                             }
191 
192                         }
193                         context.put(CATEGORY_NAME, categoryName);
194                         context.put("categoryValue", categoryValue);
195                         context.put("copyFrom", path);
196                     }
197                 }
198                 else
199                 {
200                     context.put(CATEGORY_NAME, rundata.getUser().getTemp(CATEGORY_NAME));
201                     context.put(CATEGORY_VALUE, rundata.getUser().getTemp(CATEGORY_VALUE));
202                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
203                 }
204             }
205 
206             if(mode != null && mode.equals("export"))
207             {
208                 if (msgid == null)
209                 {
210                     String tmpPath = JetspeedResources.getString(JetspeedResources.TEMP_DIRECTORY_KEY, "/tmp");
211                     String exportPath = JetspeedResources.getString("psml.export.default.path",
212                                                                     TurbineServlet.getRealPath(tmpPath));
213                     if(path == null)
214                     {
215                         context.put(COPY_TO, exportPath);
216                         context.put(COPY_FROM,
217                                     Profiler.PARAM_USER +
218                                     File.separator +
219                                     Profiler.PARAM_ANON +
220                                     File.separator +
221                                     Profiler.PARAM_MEDIA_TYPE +
222                                     File.separator +
223                                     "html" +
224                                     File.separator +
225                                     Profiler.PARAM_PAGE +
226                                     File.separator +
227                                     Profiler.FULL_DEFAULT_PROFILE);
228                     }
229                     else
230                     {
231                         ProfileLocator tmpLocator = Profiler.createLocator();
232                         tmpLocator.createFromPath(path);
233                         Profile profile = Profiler.getProfile(tmpLocator);
234                         if (profile != null)
235                         {
236                             rundata.getUser().setTemp(TEMP_LOCATOR, tmpLocator);
237                             context.put("profile", profile);
238                         }
239 
240                         String categoryName = Profiler.PARAM_GROUP;
241                         String categoryValue = tmpLocator.getGroupName();
242                         if (categoryValue == null)
243                         {
244                             categoryName = Profiler.PARAM_ROLE;
245                             categoryValue = tmpLocator.getRoleName();
246                             if (categoryValue == null)
247                             {
248                                 categoryName = Profiler.PARAM_USER;
249                                 categoryValue = tmpLocator.getUserName();
250                                 if (categoryValue == null)
251                                 {
252                                     categoryName = Profiler.PARAM_USER;
253                                     categoryValue = Profiler.PARAM_ANON;
254                                 }
255                             }
256 
257                         }
258 
259                         context.put(COPY_TO, exportPath + File.separator + tmpLocator.getName());
260                         context.put(COPY_FROM, path);
261                     }
262                 }
263                 else
264                 {
265                     context.put(COPY_TO, rundata.getUser().getTemp(COPY_TO));
266                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
267                 }
268             }
269 
270             if(mode != null && mode.equals("export_all"))
271             {
272                 if (msgid == null)
273                 {
274                     // get the PSML Root Directory
275                     ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
276                                                                  .getResources(PsmlManagerService.SERVICE_NAME);
277                     String root = serviceConf.getString("root", "/WEB-INF/psml");
278                     context.put(COPY_TO, TurbineServlet.getRealPath(root));
279                 }
280                 else
281                 {
282                     context.put(COPY_TO, rundata.getUser().getTemp(COPY_TO));
283                 }
284             }
285 
286             if(mode != null && mode.equals("import"))
287             {
288                 org.apache.jetspeed.om.registry.Registry mediaTypes = Registry.get(Registry.MEDIA_TYPE);
289                 context.put("mediaTypes", mediaTypes.listEntryNames());
290                 if (msgid == null)
291                 {
292                     // get the PSML Root Directory
293                     ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
294                                                                  .getResources(PsmlManagerService.SERVICE_NAME);
295                     String root = serviceConf.getString("root", "/WEB-INF/psml");
296                     root = TurbineServlet.getRealPath(root);
297 
298                     if(path == null)
299                     {
300                         context.put(CATEGORY_NAME, Profiler.PARAM_USER);
301                         context.put("categoryValue", Profiler.PARAM_ANON);
302                         context.put("copyFrom",
303                                     root +
304                                     File.separator +
305                                     Profiler.PARAM_USER +
306                                     File.separator +
307                                     Profiler.PARAM_ANON +
308                                     File.separator +
309                                     Profiler.PARAM_MEDIA_TYPE +
310                                     File.separator +
311                                     "html" +
312                                     File.separator +
313                                     Profiler.PARAM_PAGE +
314                                     File.separator +
315                                     Profiler.FULL_DEFAULT_PROFILE);
316                     }
317                     else
318                     {
319                         ProfileLocator tmpLocator = Profiler.createLocator();
320                         tmpLocator.createFromPath(path);
321                         Profile profile = Profiler.getProfile(tmpLocator);
322                         if (profile != null)
323                         {
324                             rundata.getUser().setTemp(TEMP_LOCATOR, tmpLocator);
325                             context.put("profile", profile);
326                         }
327                         String categoryName = Profiler.PARAM_GROUP;
328                         String categoryValue = tmpLocator.getGroupName();
329                         if (categoryValue == null)
330                         {
331                             categoryName = Profiler.PARAM_ROLE;
332                             categoryValue = tmpLocator.getRoleName();
333                             if (categoryValue == null)
334                             {
335                                 categoryName = Profiler.PARAM_USER;
336                                 categoryValue = tmpLocator.getUserName();
337                                 if (categoryValue == null)
338                                 {
339                                     categoryName = Profiler.PARAM_USER;
340                                     categoryValue = Profiler.PARAM_ANON;
341                                 }
342                             }
343 
344                         }
345                         context.put(CATEGORY_NAME, categoryName);
346                         context.put("categoryValue", categoryValue);
347                         String filePath = this.mapLocatorToFile(tmpLocator);
348                         context.put("copyFrom", root + File.separator + filePath.toString());
349                     }
350                 }
351                 else
352                 {
353                     context.put(CATEGORY_NAME, rundata.getUser().getTemp(CATEGORY_NAME));
354                     context.put(CATEGORY_VALUE, rundata.getUser().getTemp(CATEGORY_VALUE));
355                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
356                 }
357             }
358 
359             if(mode != null && mode.equals("import_all"))
360             {
361                 if (msgid == null)
362                 {
363                     // get the PSML Root Directory
364                     ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
365                                                                  .getResources(PsmlManagerService.SERVICE_NAME);
366                     String root = serviceConf.getString("root", "/WEB-INF/psml");
367                     context.put(COPY_FROM, TurbineServlet.getRealPath(root));
368                 }
369                 else
370                 {
371                     context.put(COPY_FROM, rundata.getUser().getTemp(COPY_FROM));
372                 }
373             }
374 
375         }
376         catch (Exception e)
377         {
378             logger.error("Exception", e);
379             rundata.setMessage("Error in PsmlUpdateAction: " + e.toString());
380             rundata.setStackTrace(StringUtils.stackTrace(e), e);
381             rundata.setScreenTemplate(JetspeedResources.getString("template.error","Error"));
382         }
383     }
384 
385     /***
386      * Database Insert Action for Psml.
387      *
388      * @param rundata The turbine rundata context for this request.
389      * @param context The velocity context for this request.
390      */
391     public void doInsert(RunData rundata, Context context)
392         throws Exception
393     {
394         Profile profile = null;
395         ProfileLocator locator = null;
396         String categoryName = null;
397         String categoryValue = null;
398         String copyFrom = null;
399         String name = null;
400 
401         try
402         {
403             categoryName = rundata.getParameters().getString("CategoryName");
404             categoryValue = rundata.getParameters().getString("CategoryValue");
405             copyFrom = rundata.getParameters().getString("CopyFrom");
406             name = rundata.getParameters().getString("name");
407             //
408             //create a new locator and set its values according to users input
409             //
410             locator = Profiler.createLocator();
411             if (categoryName.equalsIgnoreCase(Profiler.PARAM_GROUP))
412             {
413                 locator.setGroupByName(categoryValue);
414             }
415             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_ROLE))
416             {
417                 locator.setRoleByName(categoryValue);
418             }
419             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_USER))
420             {
421                 locator.setUser(JetspeedSecurity.getUser(categoryValue));
422             }
423             else
424             {
425                 locator.setAnonymous(true);
426             }
427 
428             String tempVar = rundata.getParameters().getString("psml_mediatype");
429             if (tempVar != null && tempVar.trim().length() > 0)
430             {
431                 locator.setMediaType(tempVar);
432             }
433 
434             tempVar = rundata.getParameters().getString("psml_language");
435             if (tempVar != null && tempVar.trim().length() > 0)
436             {
437                 locator.setLanguage(tempVar);
438             }
439 
440             tempVar = rundata.getParameters().getString("psml_country");
441             if (tempVar != null && tempVar.trim().length() > 0)
442             {
443                 locator.setCountry(tempVar);
444             }
445 
446             locator.setName(name);
447 
448             //check if profile to be created already exists
449             if (PsmlManager.getDocument(locator) != null )
450                 throw new EntityExistsException("Profile:"+locator.getPath()+" Already Exists!");
451             //
452             // validate that its not an 'blank' profile -- not allowed
453             //
454             if (name == null || name.trim().length() == 0)
455             {
456                 JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
457                 DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
458                                       .addPathInfo(SecurityConstants.PARAM_MODE,
459                                                    SecurityConstants.PARAM_MODE_INSERT)
460                                       .addPathInfo(SecurityConstants.PARAM_MSGID,
461                                                    SecurityConstants.MID_INVALID_ENTITY_NAME);
462                 JetspeedLinkFactory.putInstance(link);
463                 rundata.setRedirectURI(duri.toString());
464 
465                 //save user entered values
466                 if (locator != null)
467                     rundata.getUser().setTemp(TEMP_LOCATOR, locator);
468                 if (categoryName != null)
469                     rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
470                 if (categoryValue != null)
471                     rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
472                 if (copyFrom != null)
473                     rundata.getUser().setTemp(COPY_FROM, copyFrom);
474                 return;
475             }
476 
477             //
478             // retrieve the profile to clone
479             //
480             ProfileLocator baseLocator = Profiler.createLocator();
481             baseLocator.createFromPath(copyFrom);
482             Profile baseProfile = Profiler.getProfile(baseLocator);
483 
484             //
485             // create a new profile
486             //
487             if(baseProfile != null)
488             {
489                 PSMLDocument doc = baseProfile.getDocument();
490                 if(doc != null)
491                 {
492                     Portlets portlets = doc.getPortlets();
493                     
494                     Portlets clonedPortlets = (Portlets) SerializationUtils.clone(portlets);
495                     org.apache.jetspeed.util.PortletUtils.regenerateIds(clonedPortlets);
496                     profile = Profiler.createProfile(locator, clonedPortlets);
497                 }
498                 else
499                 {
500                     profile = Profiler.createProfile(locator, null);
501                 }
502                 setRefreshPsmlFlag(rundata, TRUE);
503             }
504             else
505             {
506                 logger.error("Profile listed in Copy From Not Found!");
507             }
508         }
509         catch (EntityExistsException e)
510         {
511             // log the error msg
512             logger.error("Exception", e);
513 
514             //
515             // dup key found - display error message - bring back to same screen
516             //
517             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
518             DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
519                                   .addPathInfo(SecurityConstants.PARAM_MODE,
520                                                SecurityConstants.PARAM_MODE_INSERT)
521                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
522                                                SecurityConstants.MID_ENTITY_ALREADY_EXISTS);
523             JetspeedLinkFactory.putInstance(link);
524             rundata.setRedirectURI(duri.toString());
525         }
526         catch (Exception e)
527         {
528             // log the error msg
529             logger.error("Exception", e);
530 
531             //
532             // dup key found - display error message - bring back to same screen
533             //
534             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
535             DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
536                                   .addPathInfo(SecurityConstants.PARAM_MODE,
537                                                SecurityConstants.PARAM_MODE_INSERT)
538                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
539                                                SecurityConstants.MID_UPDATE_FAILED);
540             JetspeedLinkFactory.putInstance(link);
541             rundata.setRedirectURI(duri.toString());
542         }
543         // save values that user just entered so they don't have to re-enter
544         if (locator != null)
545            rundata.getUser().setTemp(TEMP_LOCATOR, locator);
546         if (categoryName != null)
547             rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
548         if (categoryValue != null)
549             rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
550         if (copyFrom != null)
551             rundata.getUser().setTemp(COPY_FROM, copyFrom);
552 
553     }
554 
555     /***
556      * Delete Psml entry
557      */
558     public void doDelete(RunData rundata, Context context) throws Exception
559     {
560         try
561         {
562             ProfileLocator locator = (ProfileLocator)rundata.getUser().getTemp(TEMP_LOCATOR);
563             if (locator != null)
564             {
565                 Profiler.removeProfile(locator);
566                 setRefreshPsmlFlag(rundata, TRUE);
567             }
568             else
569             {
570                 logger.error("ProfileLocator not found!");
571             }
572         }
573         catch(Exception e)
574         {
575             // log the error msg
576             logger.error("Exception", e);
577 
578             //
579             // dup key found - display error message - bring back to same screen
580             //
581             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
582             DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
583                                   .addPathInfo(SecurityConstants.PARAM_MODE, SecurityConstants.PARAM_MODE_DELETE)
584                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
585                                                SecurityConstants.MID_DELETE_FAILED);
586             JetspeedLinkFactory.putInstance(link);
587             rundata.setRedirectURI(duri.toString());
588         }
589 
590     }
591 
592     public void setRefreshPsmlFlag(RunData rundata, String value)
593     {
594         rundata.getUser().setTemp(PSML_REFRESH_FLAG, TRUE);
595     }
596 
597     /***
598      * File Export Action for Psml.
599      *
600      * @param rundata The turbine rundata context for this request.
601      * @param context The velocity context for this request.
602      */
603     public void doExport(RunData rundata, Context context)
604         throws Exception
605     {
606         Profile profile = null;
607         ProfileLocator locator = null;
608         String copyTo = null;
609         String copyFrom = null;
610 
611         try
612         {
613             copyFrom = rundata.getParameters().getString("CopyFrom");
614             copyTo = rundata.getParameters().getString("CopyTo");
615 
616             //
617             // retrieve the profile to clone
618             //
619             ProfileLocator baseLocator = Profiler.createLocator();
620             baseLocator.createFromPath(copyFrom);
621             Profile baseProfile = Profiler.getProfile(baseLocator);
622 
623             //
624             // Export profile
625             //
626             if(baseProfile != null)
627             {
628                 PSMLDocument doc = baseProfile.getDocument();
629                 if(doc != null)
630                 {
631                     if (!this.saveDocument(copyTo,doc))
632                         throw new Exception("Failed to save PSML document");
633                     rundata.addMessage("Profile [" + copyFrom + "] has been saved to disk in [" + copyTo + "]<br>");
634                 }
635             }
636             else
637             {
638                 logger.error("Profile listed in Copy From Not Found!");
639             }
640         }
641         catch (Exception e)
642         {
643             // log the error msg
644             logger.error("Exception", e);
645 
646             //
647             // dup key found - display error message - bring back to same screen
648             //
649             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
650             DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
651                                   .addPathInfo(SecurityConstants.PARAM_MODE,
652                                                "export")
653                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
654                                                SecurityConstants.MID_UPDATE_FAILED);
655             JetspeedLinkFactory.putInstance(link);
656             rundata.setRedirectURI(duri.toString());
657         }
658         // save values that user just entered so they don't have to re-enter
659         if (copyTo != null)
660             rundata.getUser().setTemp(COPY_TO, copyTo);
661         if (copyFrom != null)
662             rundata.getUser().setTemp(COPY_FROM, copyFrom);
663 
664     }
665 
666     /***
667      * File Export All Action for Psml.
668      *
669      * @param rundata The turbine rundata context for this request.
670      * @param context The velocity context for this request.
671      */
672     public void doExportall(RunData rundata, Context context)
673         throws Exception
674     {
675         String copyTo = null;
676 
677         logger.info("PsmlUpdateAction: Starting export all operation");
678 
679         try
680         {
681             copyTo = rundata.getParameters().getString("CopyTo");
682 
683             //
684             // retrieve the profiles to export
685             //
686             Iterator i = Profiler.query(new QueryLocator(QueryLocator.QUERY_ALL));
687             while (i.hasNext())
688             {
689                 Profile profile = (Profile) i.next();
690                 PSMLDocument doc = profile.getDocument();
691                 if(doc != null)
692                 {
693                     // Build the fully qualified file name
694                     StringBuffer copyToFile = new StringBuffer(copyTo);
695                     copyToFile.append(File.separator);
696                     if (profile.getGroupName() != null)
697                     {
698                         copyToFile.append("group");
699                         copyToFile.append(File.separator);
700                         copyToFile.append(profile.getGroupName());
701                         copyToFile.append(File.separator);
702                     }
703                     else if (profile.getRoleName() != null)
704                     {
705                         copyToFile.append("role");
706                         copyToFile.append(File.separator);
707                         copyToFile.append(profile.getRoleName());
708                         copyToFile.append(File.separator);
709                     }
710                     else if (profile.getUserName() != null)
711                     {
712                         copyToFile.append("user");
713                         copyToFile.append(File.separator);
714                         copyToFile.append(profile.getUserName());
715                         copyToFile.append(File.separator);
716                     }
717                     if (profile.getMediaType() != null)
718                     {
719                         copyToFile.append(profile.getMediaType());
720                         copyToFile.append(File.separator);
721                     }
722                     if (profile.getLanguage() != null)
723                     {
724                         copyToFile.append(profile.getLanguage());
725                         copyToFile.append(File.separator);
726                     }
727                     if (profile.getCountry() != null)
728                     {
729                         copyToFile.append(profile.getCountry());
730                         copyToFile.append(File.separator);
731                     }
732                     copyToFile.append(profile.getName());
733 
734                     if (!this.saveDocument(copyToFile.toString(), doc)) {
735                         logger.error("Failed to save PSML document for [" + profile.getPath());
736                     } else {
737                         String msg = "Profile [" + profile.getPath() + "] has been saved to disk in [" + copyToFile.toString() + "]<br>";
738                         logger.info(msg);
739                         rundata.addMessage(msg);
740                     }
741                 }
742             }
743 
744         }
745         catch (Exception e)
746         {
747             // log the error msg
748             logger.error("Exception", e);
749 
750             //
751             // dup key found - display error message - bring back to same screen
752             //
753             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
754             DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
755                                   .addPathInfo(SecurityConstants.PARAM_MODE,
756                                                "export_all")
757                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
758                                                SecurityConstants.MID_UPDATE_FAILED);
759             JetspeedLinkFactory.putInstance(link);
760             rundata.setRedirectURI(duri.toString());
761         }
762         // save values that user just entered so they don't have to re-enter
763         if (copyTo != null) {
764             rundata.getUser().setTemp(COPY_TO, copyTo);
765         }
766 
767         logger.info("PsmlUpdateAction: Ending export all operation");
768     }
769 
770     /*** Save the PSML document on disk to the specififed fileOrUrl
771      *
772      * @param fileOrUrl a String representing either an absolute URL
773      * or an absolute filepath
774      * @param doc the document to save
775      */
776     private boolean saveDocument(String fileOrUrl, PSMLDocument doc)
777     {
778         boolean success = false;
779 
780         if (doc == null) return false;
781         File f = new File(fileOrUrl);
782         File d = new File(f.getParent());
783         d.mkdirs();
784 
785         FileWriter writer = null;
786 
787         try
788         {
789             writer = new FileWriter(f);
790             // create the serializer output format
791             OutputFormat format = new OutputFormat();
792             format.setIndenting(true);
793             format.setIndent(4);
794             Serializer serializer = new XMLSerializer(writer,format);
795             Marshaller marshaller = new Marshaller(serializer.asDocumentHandler());
796             marshaller.setMapping(this.loadMapping());
797             marshaller.marshal(doc.getPortlets());
798 
799             success = true;
800         }
801         catch (MarshalException e)
802         {
803             logger.error("PSMLUpdateAction: Could not marshal the file " + f.getAbsolutePath(), e);
804         }
805         catch (MappingException e)
806         {
807             logger.error("PSMLUpdateAction: Could not marshal the file " + f.getAbsolutePath(), e);
808         }
809         catch (ValidationException e)
810         {
811             logger.error("PSMLUpdateAction: document "+f.getAbsolutePath() + " is not valid", e);
812         }
813         catch (IOException e)
814         {
815             logger.error("PSMLUpdateAction: Could not save the file " + f.getAbsolutePath(), e);
816         }
817         catch (Exception e)
818         {
819             logger.error("PSMLUpdateAction: Error while saving  " + f.getAbsolutePath(), e);
820         }
821         finally
822         {
823             try
824             {
825                 writer.close();
826             }
827             catch (IOException e)
828             {
829             }
830         }
831 
832         return success;
833     }
834 
835     /***
836      * Loads psml mapping file
837      *
838      * @exception Exception
839      */
840     private Mapping loadMapping()
841         throws Exception
842     {
843         // get configuration parameters from Jetspeed Resources
844         ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
845                                                      .getResources(PsmlManagerService.SERVICE_NAME);
846 
847         // test the mapping file and create the mapping object
848         Mapping mapping = null;
849         String mapFile = serviceConf.getString("mapping","${webappRoot}/WEB-INF/conf/psml-mapping.xml");
850         mapFile = TurbineServlet.getRealPath( mapFile );
851         if (mapFile != null)
852         {
853             File map = new File(mapFile);
854             if ( logger.isDebugEnabled() )
855             {
856                 logger.debug( "Loading psml mapping file " + mapFile );
857             }
858             if (map.exists() && map.isFile() && map.canRead())
859             {
860                 try
861                 {
862                     mapping = new Mapping();
863                     InputSource is = new InputSource( new FileReader(map) );
864                     is.setSystemId( mapFile );
865                     mapping.loadMapping( is );
866                 }
867                 catch (Exception e)
868                 {
869                     logger.error("Error in psml mapping creation", e);
870                     throw new Exception("Error in mapping");
871                 }
872             }
873             else
874             {
875                 throw new Exception("PSML Mapping not found or not a file or unreadable: " + mapFile);
876             }
877         }
878 
879         return mapping;
880     }
881 
882     /***
883      * File Import Action for Psml.
884      *
885      * TODO: Implement file upload.
886      *
887      * @param rundata The turbine rundata context for this request.
888      * @param context The velocity context for this request.
889      */
890     public void doImport(RunData rundata, Context context)
891         throws Exception
892     {
893         Profile profile = null;
894         ProfileLocator locator = null;
895         String categoryName = null;
896         String categoryValue = null;
897         String copyFrom = null;
898         String name = null;
899 
900         try
901         {
902             categoryName = rundata.getParameters().getString("CategoryName");
903             categoryValue = rundata.getParameters().getString("CategoryValue");
904             copyFrom = rundata.getParameters().getString("CopyFrom");
905             name = rundata.getParameters().getString("name");
906             //
907             //create a new locator and set its values according to users input
908             //
909             locator = Profiler.createLocator();
910             if (categoryName.equalsIgnoreCase(Profiler.PARAM_GROUP))
911             {
912                 locator.setGroupByName(categoryValue);
913             }
914             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_ROLE))
915             {
916                 locator.setRoleByName(categoryValue);
917             }
918             else if (categoryName.equalsIgnoreCase(Profiler.PARAM_USER))
919             {
920                 locator.setUser(JetspeedSecurity.getUser(categoryValue));
921             }
922             else
923             {
924                 locator.setAnonymous(true);
925             }
926 
927             String tempVar = rundata.getParameters().getString("psml_mediatype");
928             if (tempVar != null && tempVar.trim().length() > 0)
929             {
930                 locator.setMediaType(tempVar);
931             }
932 
933             tempVar = rundata.getParameters().getString("psml_language");
934             if (tempVar != null && tempVar.trim().length() > 0)
935             {
936                 locator.setLanguage(tempVar);
937             }
938 
939             tempVar = rundata.getParameters().getString("psml_country");
940             if (tempVar != null && tempVar.trim().length() > 0)
941             {
942                 locator.setCountry(tempVar);
943             }
944 
945             locator.setName(name);
946 
947             //
948             // validate that its not an 'blank' profile -- not allowed
949             //
950             if (name == null || name.trim().length() == 0)
951             {
952                 JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
953                 DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
954                                       .addPathInfo(SecurityConstants.PARAM_MODE,
955                                                    "import")
956                                       .addPathInfo(SecurityConstants.PARAM_MSGID,
957                                                    SecurityConstants.MID_INVALID_ENTITY_NAME);
958                 JetspeedLinkFactory.putInstance(link);
959                 rundata.setRedirectURI(duri.toString());
960 
961                 //save user entered values
962                 if (locator != null)
963                 {
964                     rundata.getUser().setTemp(TEMP_LOCATOR, locator);
965                 }
966                 if (categoryName != null)
967                 {
968                     rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
969                 }
970                 if (categoryValue != null)
971                 {
972                     rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
973                 }
974                 if (copyFrom != null)
975                 {
976                     rundata.getUser().setTemp(COPY_FROM, copyFrom);
977                 }
978                 return;
979             }
980 
981             //
982             // Retrieve the document to import
983             //
984             PSMLDocument doc = this.loadDocument(copyFrom);
985 
986             //
987             // create a new profile
988             //
989             if(doc != null)
990             {
991                 Portlets portlets = doc.getPortlets();
992                 //
993                 // Profiler does not provide update capability - must remove before replacing
994                 //
995                 if (PsmlManager.getDocument(locator) != null)
996                 {
997                     Profiler.removeProfile(locator);
998                 }
999                 
1000                 Portlets clonedPortlets = (Portlets) SerializationUtils.clone(portlets);
1001                 org.apache.jetspeed.util.PortletUtils.regenerateIds(clonedPortlets);
1002                 
1003                 profile = Profiler.createProfile(locator, clonedPortlets);
1004             }
1005             else
1006             {
1007                 throw new Exception("Failed to load PSML document from disk");
1008             }
1009             rundata.addMessage("Profile for [" + locator.getPath() + "] has been imported from file [" + copyFrom + "]<br>");
1010             setRefreshPsmlFlag(rundata, TRUE);
1011 
1012         }
1013         catch (Exception e)
1014         {
1015             // log the error msg
1016             logger.error("Exception", e);
1017 
1018             //
1019             // dup key found - display error message - bring back to same screen
1020             //
1021             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1022             DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
1023                                   .addPathInfo(SecurityConstants.PARAM_MODE,
1024                                                "import")
1025                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
1026                                                SecurityConstants.MID_UPDATE_FAILED);
1027             JetspeedLinkFactory.putInstance(link);
1028             rundata.setRedirectURI(duri.toString());
1029         }
1030         // save values that user just entered so they don't have to re-enter
1031         if (locator != null)
1032         {
1033            rundata.getUser().setTemp(TEMP_LOCATOR, locator);
1034         }
1035         if (categoryName != null)
1036         {
1037             rundata.getUser().setTemp(CATEGORY_NAME, categoryName);
1038         }
1039         if (categoryValue != null)
1040         {
1041             rundata.getUser().setTemp(CATEGORY_VALUE, categoryValue);
1042         }
1043         if (copyFrom != null)
1044         {
1045             rundata.getUser().setTemp(COPY_FROM, copyFrom);
1046         }
1047 
1048     }
1049 
1050     /***
1051      * File Import All Action for Psml.
1052      *
1053      *
1054      * @param rundata The turbine rundata context for this request.
1055      * @param context The velocity context for this request.
1056      */
1057     public void doImportall(RunData rundata, Context context)
1058         throws Exception
1059     {
1060         String copyFrom = null;
1061 
1062         try
1063         {
1064             copyFrom = rundata.getParameters().getString("CopyFrom");
1065 
1066             //
1067             // Collect all .psml files from the root specified
1068             //
1069             Vector files = new Vector();
1070             this.collectPsml(files, copyFrom);
1071 
1072             //
1073             // Process each file
1074             //
1075             for (Iterator it = files.iterator(); it.hasNext(); )
1076             {
1077                 // If error occurs processing one entry, continue on with the others
1078                 String path = null;
1079                 try
1080                 {
1081                     String psml = ((File) it.next()).getPath();
1082                     path = psml.substring(copyFrom.length() + 1);
1083                     ProfileLocator locator = this.mapFileToLocator(path);
1084 
1085                     PSMLDocument doc = this.loadDocument(psml);
1086 
1087                     //
1088                     // create a new profile
1089                     //
1090                     if(doc != null)
1091                     {
1092                         Portlets portlets = doc.getPortlets();
1093                         //
1094                         // Profiler does not provide update capability - must remove before replacing
1095                         //
1096                         if (PsmlManager.getDocument(locator) != null)
1097                         {
1098                             Profiler.removeProfile(locator);
1099                         }
1100                         Profiler.createProfile(locator, portlets);
1101                     }
1102                     else
1103                     {
1104                         throw new Exception("Failed to load PSML document [" + psml + "] from disk");
1105                     }
1106                     rundata.addMessage("Profile for [" + locator.getPath() + "] has been imported from file [" + psml + "]<br>");
1107                     setRefreshPsmlFlag(rundata, TRUE);
1108                 }
1109                 catch (Exception ouch)
1110                 {
1111                     logger.error("Exception", ouch);
1112                     rundata.addMessage("ERROR importing file [" + path + "]: " + ouch.toString() + "<br>");
1113                 }
1114             }
1115 
1116         }
1117         catch (Exception e)
1118         {
1119             // log the error msg
1120             logger.error("Exception", e);
1121 
1122             //
1123             // dup key found - display error message - bring back to same screen
1124             //
1125             JetspeedLink link = JetspeedLinkFactory.getInstance(rundata);
1126             DynamicURI duri = link.getPaneByName(PSML_UPDATE_PANE)
1127                                   .addPathInfo(SecurityConstants.PARAM_MODE,
1128                                                "import_all")
1129                                   .addPathInfo(SecurityConstants.PARAM_MSGID,
1130                                                SecurityConstants.MID_UPDATE_FAILED);
1131             JetspeedLinkFactory.putInstance(link);
1132             rundata.setRedirectURI(duri.toString());
1133         }
1134         // save values that user just entered so they don't have to re-enter
1135         if (copyFrom != null)
1136         {
1137             rundata.getUser().setTemp(COPY_FROM, copyFrom);
1138         }
1139 
1140     }
1141 
1142     /***
1143      * This method recursively collect all .psml documents starting at the given root
1144      *
1145      * @param v      Vector to put the file into
1146      * @param root   Root directory for import
1147      */
1148     private void collectPsml(Vector v, String root)
1149     {
1150 
1151         File dir = new File(root);
1152         File[] files = dir.listFiles();
1153         for (int i = 0; i < files.length; i++)
1154         {
1155             if (files[i].isDirectory())
1156             {
1157                 collectPsml(v, files[i].getPath());
1158             }
1159             else if (files[i].isFile() && files[i].getPath().endsWith(".psml"))
1160             {
1161                 v.add(files[i]);
1162             }
1163         }
1164 
1165     }
1166 
1167     /***
1168      * Creates profile locator from a given path in the format:
1169      *
1170      *   user/<name>/<mediaType>/<language>/<country>/<page>/
1171      *
1172      *   group/ ""
1173      *   role/  ""
1174      *
1175      * @param path The formatted profiler path string.
1176      * @param path   fully qualified .psml file name
1177      * @return profile locator
1178      */
1179     private ProfileLocator mapFileToLocator(String path)
1180     throws Exception
1181     {
1182         if (logger.isDebugEnabled())
1183         {
1184             logger.debug("PsmlUpdateAction.createFromPath: processing path = " + path);
1185         }
1186         ProfileLocator result = Profiler.createLocator();
1187 
1188         // Tokenize the file path into elements
1189         StringTokenizer tok = new StringTokenizer(path, File.separator);
1190 
1191         // Load path elements into a vector for random access
1192         Vector tokens = new Vector();
1193         while (tok.hasMoreTokens())
1194         {
1195             tokens.add(tok.nextToken());
1196         }
1197 
1198         // Assume that 1st element is the profile type (user|role|group) and 2nd is the name
1199         if (tokens.size() > 1)
1200         {
1201             String type = (String) tokens.elementAt(0);
1202             String name = (String) tokens.elementAt(1);
1203             if (type.equals(Profiler.PARAM_USER))
1204             {
1205                 result.setUser(JetspeedSecurity.getUser(name));
1206             }
1207             else if (type.equals(Profiler.PARAM_GROUP))
1208             {
1209                 result.setGroup(JetspeedSecurity.getGroup(name));
1210             }
1211             else if (type.equals(Profiler.PARAM_ROLE))
1212             {
1213                 result.setRole(JetspeedSecurity.getRole(name));
1214             }
1215         }
1216 
1217         // Assume that the last element is the page name
1218         if (tokens.size() > 0)
1219         {
1220             result.setName((String) tokens.lastElement());
1221         }
1222 
1223         // Based on the number of path elements set the other profile attributes
1224         switch (tokens.size())
1225         {
1226         case 3: // user|role|group/name/page.psml
1227             break;
1228         case 4: // user|role|group/name/media-type/page.psml
1229             result.setMediaType((String) tokens.elementAt(2));
1230             break;
1231         case 5: // user|role|group/name/media-type/language/page.psml
1232             result.setMediaType((String) tokens.elementAt(2));
1233             result.setLanguage((String) tokens.elementAt(3));
1234             break;
1235         case 6: // user|role|group/name/media-type/language/country/page.psml
1236             result.setMediaType((String) tokens.elementAt(2));
1237             result.setLanguage((String) tokens.elementAt(3));
1238             result.setCountry((String) tokens.elementAt(4));
1239             break;
1240         default:
1241             throw new Exception("Path must contain 3 to 6 elements: [" + path + "], and the size was: " + tokens.size());
1242         }
1243 
1244         return result;
1245     }
1246 
1247     /***
1248      * Maps a ProfileLocator to a file.
1249      *
1250      * @param locator The profile locator describing the PSML resource to be found.
1251      * @return the String path of the file.
1252      */
1253     private String mapLocatorToFile(ProfileLocator locator)
1254     {
1255         StringBuffer path = new StringBuffer();
1256 
1257         // move the base dir is either user or role is specified
1258         Role role = locator.getRole();
1259         Group group = locator.getGroup();
1260         JetspeedUser user = locator.getUser();
1261 
1262         if (user != null)
1263         {
1264             path.append(Profiler.PARAM_USER);
1265             String name = user.getUserName();
1266             if (null != name && name.length() > 0)
1267             {
1268                 path.append(File.separator)
1269                     .append(name);
1270             }
1271         }
1272         else if (group != null)
1273         {
1274             path.append(Profiler.PARAM_GROUP);
1275             String name = group.getName();
1276             if (null != name && name.length() > 0)
1277             {
1278                 path.append(File.separator)
1279                     .append(name);
1280             }
1281         }
1282         else if (null != role)
1283         {
1284             path.append(Profiler.PARAM_ROLE);
1285             String name = role.getName();
1286             if (null != name && name.length() > 0)
1287             {
1288                 path.append(File.separator)
1289                     .append(name);
1290             }
1291         }
1292 
1293         // Media
1294         if (null != locator.getMediaType())
1295         {
1296             path.append(File.separator)
1297                 .append(locator.getMediaType());
1298         }
1299         // Language
1300         if (null != locator.getLanguage())
1301         {
1302             path.append(File.separator)
1303                 .append(locator.getLanguage());
1304         }
1305         // Country
1306         if (null != locator.getCountry())
1307         {
1308             path.append(File.separator)
1309                 .append(locator.getCountry());
1310         }
1311         // Resource Name
1312         if (null != locator.getName())
1313         {
1314             if (!(locator.getName().endsWith(Profiler.DEFAULT_EXTENSION)))
1315             {
1316                 path.append(File.separator)
1317                     .append(locator.getName()).append(Profiler.DEFAULT_EXTENSION);
1318             }
1319             else
1320             {
1321                 path.append(File.separator)
1322                     .append(locator.getName());
1323             }
1324         }
1325         else
1326         {
1327             path.append(File.separator)
1328                 .append(Profiler.FULL_DEFAULT_PROFILE);
1329         }
1330 
1331         return  path.toString();
1332     }
1333 
1334     /***
1335      * Load a PSMLDOcument from disk
1336      *
1337      * @param fileOrUrl a String representing either an absolute URL or an
1338      * absolute filepath
1339      */
1340     private PSMLDocument loadDocument(String fileOrUrl)
1341     {
1342         PSMLDocument doc = null;
1343 
1344         if (fileOrUrl != null)
1345         {
1346 
1347             // we'll assume the name is the the location of the file
1348             File f = null;
1349 
1350             f = new File(fileOrUrl);
1351 
1352             if (!f.exists())
1353             {
1354                 return null;
1355             }
1356 
1357             doc = new BasePSMLDocument();
1358             doc.setName(fileOrUrl);
1359 
1360             // now that we have a file reference, try to load the serialized PSML
1361             Portlets portlets = null;
1362             FileReader reader = null;
1363             try
1364             {
1365                 reader = new FileReader(f);
1366 
1367                 Unmarshaller unmarshaller = new Unmarshaller(this.loadMapping());
1368                 portlets = (Portlets) unmarshaller.unmarshal(reader);
1369 
1370                 doc.setPortlets(portlets);
1371 
1372             }
1373             catch (IOException e)
1374             {
1375                 logger.error("PSMLUpdateAction: Could not load the file " + f.getAbsolutePath(), e);
1376             }
1377             catch (MarshalException e)
1378             {
1379                 logger.error("PSMLUpdateAction: Could not unmarshal the file " + f.getAbsolutePath(), e);
1380             }
1381             catch (MappingException e)
1382             {
1383                 logger.error("PSMLUpdateAction: Could not unmarshal the file " + f.getAbsolutePath(), e);
1384             }
1385             catch (ValidationException e)
1386             {
1387                 logger.error("PSMLUpdateAction: document " + f.getAbsolutePath() + " is not valid", e);
1388             }
1389             catch (Exception e)
1390             {
1391                 logger.error("PSMLUpdateAction: Error while loading  " + f.getAbsolutePath(), e);
1392             }
1393             finally
1394             {
1395                 try
1396                 {
1397                     reader.close();
1398                 }
1399                 catch (IOException e)
1400                 {
1401                 }
1402             }
1403         }
1404 
1405         return doc;
1406     }
1407 
1408 }
1409 
1410