1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.services.psmlmanager;
18
19
20 import org.apache.jetspeed.om.profile.ProfileLocator;
21 import org.apache.jetspeed.om.profile.QueryLocator;
22 import org.apache.jetspeed.util.FileCopy;
23 import org.apache.jetspeed.util.DirectoryUtils;
24 import org.apache.jetspeed.services.Profiler;
25 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
26 import org.apache.jetspeed.services.logging.JetspeedLogger;
27 import org.apache.jetspeed.services.JetspeedSecurity;
28 import org.apache.jetspeed.services.resources.JetspeedResources;
29
30
31 import org.apache.jetspeed.om.profile.Portlets;
32 import org.apache.jetspeed.om.profile.*;
33
34
35 import org.apache.turbine.services.TurbineBaseService;
36 import org.apache.turbine.services.InitializationException;
37 import org.apache.turbine.services.TurbineServices;
38 import org.apache.turbine.services.servlet.TurbineServlet;
39 import org.apache.turbine.services.resources.ResourceService;
40 import org.apache.turbine.services.servlet.ServletService;
41
42 import org.apache.jetspeed.om.security.JetspeedUser;
43 import org.apache.jetspeed.om.security.Role;
44 import org.apache.jetspeed.om.security.JetspeedRoleFactory;
45 import org.apache.jetspeed.om.security.Group;
46 import org.apache.jetspeed.om.security.JetspeedGroupFactory;
47 import org.apache.jetspeed.om.security.JetspeedUserFactory;
48
49
50 import org.exolab.castor.xml.MarshalException;
51 import org.exolab.castor.xml.Unmarshaller;
52 import org.exolab.castor.xml.Marshaller;
53 import org.exolab.castor.xml.ValidationException;
54 import org.exolab.castor.mapping.Mapping;
55 import org.exolab.castor.mapping.MappingException;
56 import org.xml.sax.InputSource;
57 import org.xml.sax.SAXException;
58 import org.w3c.dom.Document;
59 import org.w3c.dom.Node;
60
61
62 import org.apache.xml.serialize.Serializer;
63 import org.apache.xml.serialize.XMLSerializer;
64 import org.apache.xml.serialize.OutputFormat;
65
66
67 import java.io.File;
68 import java.io.Reader;
69 import java.io.FileReader;
70 import java.io.Writer;
71 import java.io.FileOutputStream;
72 import java.io.OutputStreamWriter;
73 import java.io.IOException;
74 import java.util.Iterator;
75 import java.util.List;
76 import java.util.LinkedList;
77 import javax.servlet.ServletConfig;
78 import javax.xml.parsers.DocumentBuilder;
79 import javax.xml.parsers.DocumentBuilderFactory;
80 import javax.xml.parsers.ParserConfigurationException;
81
82 import org.apache.jetspeed.cache.FileCache;
83 import org.apache.jetspeed.cache.FileCacheEventListener;
84 import org.apache.jetspeed.cache.FileCacheEntry;
85
86
87 /***
88 * This service is responsible for loading and saving PSML documents.
89 *
90 * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
91 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
92 * @author <a href="mailto:sgala@apache.org">Santiago Gala</a>
93 * @version $Id: CastorPsmlManagerService.java,v 1.44 2004/03/31 00:23:02 jford Exp $
94 */
95 public class CastorPsmlManagerService extends TurbineBaseService
96 implements FileCacheEventListener,
97 PsmlManagerService
98 {
99 /***
100 * Static initialization of the logger for this class
101 */
102 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(CastorPsmlManagerService.class.getName());
103
104
105 protected static final String PATH_GROUP = "group";
106 protected static final String PATH_ROLE = "role";
107 protected static final String PATH_USER = "user";
108
109
110 protected final static String CONFIG_ROOT = "root";
111 protected final static String CONFIG_EXT = "ext";
112 protected final static String CONFIG_SCAN_RATE = "scanRate";
113 protected final static String CONFIG_CACHE_SIZE = "cacheSize";
114
115
116 public final static String DEFAULT_ROOT = "/WEB-INF/psml";
117 public final static String DEFAULT_EXT = ".psml";
118
119
120 public final static String DEFAULT_RESOURCE = "default.psml";
121
122
123 protected String root;
124
125 protected File rootDir = null;
126
127 protected String ext;
128
129 /*** The documents loaded by this manager */
130 protected FileCache documents = null;
131
132 /*** the output format for pretty printing when saving registries */
133 protected OutputFormat format = null;
134
135 /*** the base refresh rate for documents */
136 protected long scanRate = 1000 * 60;
137
138 /*** the default cache size */
139 protected int cacheSize = 100;
140
141 /*** the import/export consumer service **/
142 protected PsmlManagerService consumer = null;
143 protected boolean importFlag = false;
144
145
146 public static final String DEFAULT_MAPPING = "${webappRoot}/WEB-INF/conf/psml-mapping.xml";
147 protected String mapFile = null;
148
149 /*** the Castor mapping file name */
150 protected Mapping mapping = null;
151
152 /*** The default encoding used to serialize PSML files to disk */
153 protected String defaultEncoding = JetspeedResources.getString(JetspeedResources.CONTENT_ENCODING_KEY, "utf-8");
154
155 /***
156 * This is the early initialization method called by the
157 * Turbine <code>Service</code> framework
158 */
159 public void init( ServletConfig conf ) throws InitializationException
160 {
161 if (getInit())
162 {
163 return;
164 }
165
166
167 TurbineServices.getInstance().initService(ServletService.SERVICE_NAME, conf);
168
169
170 ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
171 .getResources(PsmlManagerService.SERVICE_NAME);
172
173 this.root = serviceConf.getString( CONFIG_ROOT, DEFAULT_ROOT );
174 this.rootDir = new File(root);
175
176
177 if ( !rootDir.exists() )
178 {
179 try
180 {
181 this.rootDir = new File(conf.getServletContext().getRealPath(root));
182 }
183 catch (Exception e)
184 {
185
186 }
187 }
188
189 if (!rootDir.exists())
190 {
191 try
192 {
193 rootDir.mkdirs();
194 }
195 catch (Exception e)
196 {
197 }
198 }
199
200
201 this.ext = serviceConf.getString( CONFIG_EXT, DEFAULT_EXT );
202
203
204 this.format = new OutputFormat();
205 format.setIndenting(true);
206 format.setIndent(4);
207 format.setLineWidth(0);
208
209
210 mapFile = serviceConf.getString("mapping",DEFAULT_MAPPING);
211 mapFile = TurbineServlet.getRealPath( mapFile );
212 loadMapping();
213
214 this.scanRate = serviceConf.getLong(CONFIG_SCAN_RATE, this.scanRate);
215 this.cacheSize= serviceConf.getInt(CONFIG_CACHE_SIZE, this.cacheSize);
216
217 documents = new FileCache(this.scanRate, this.cacheSize);
218 documents.addListener(this);
219 documents.startFileScanner();
220
221
222
223 setInit(true);
224
225
226
227
228 }
229
230
231 /*** Late init method from Turbine Service model */
232 public void init() throws InitializationException
233 {
234 while( !getInit() )
235 {
236
237 try
238 {
239 Thread.sleep( 500 );
240 }
241 catch (InterruptedException ie )
242 {
243 logger.error("Exception", ie);
244 }
245 }
246 }
247
248
249 /***
250 * This is the shutdown method called by the
251 * Turbine <code>Service</code> framework
252 */
253 public void shutdown()
254 {
255 documents.stopFileScanner();
256 }
257
258 /***
259 * Returns a PSML document of the given name.
260 * For this implementation, the name must be the document
261 * URL or absolute filepath
262 *
263 * @deprecated
264 * @param name the name of the document to retrieve
265 */
266 public PSMLDocument getDocument( String name )
267 {
268 if (name == null)
269 {
270 String message = "PSMLManager: Must specify a name";
271 logger.error( message );
272 throw new IllegalArgumentException( message );
273 }
274
275 if (logger.isDebugEnabled())
276 {
277 logger.debug( "PSMLManager: asked for " + name );
278 }
279
280 PSMLDocument doc = null;
281
282 doc = (PSMLDocument)documents.getDocument(name);
283
284 if (doc == null)
285 {
286 doc = loadDocument(name);
287
288 synchronized (documents)
289 {
290
291 try
292 {
293 documents.put(name, doc);
294 }
295 catch (java.io.IOException e)
296 {
297 logger.error("Error putting document", e);
298 }
299 }
300 }
301
302 return doc;
303 }
304
305 /***
306 * Returns a cached PSML document for the given locator
307 *
308 * @param locator The locator descriptor of the document to be retrieved.
309 * @return PSML document from cache (or disk if not yet cached)
310 */
311 public PSMLDocument getDocument( ProfileLocator locator)
312 {
313 return getDocument(locator, true);
314 }
315
316 /***
317 * Returns a PSML document for the given locator
318 *
319 * @param locator The locator descriptor of the document to be retrieved.
320 * @param getCached Look in the cache (true) or umarshall a fresh copy from disk (false)
321 * @return
322 */
323 protected PSMLDocument getDocument( ProfileLocator locator, boolean getCached )
324 {
325 if (locator == null)
326 {
327 String message = "PSMLManager: Must specify a name";
328 logger.error( message );
329 throw new IllegalArgumentException( message );
330 }
331 File base = this.rootDir;
332 String path = mapLocatorToFile(locator);
333 File file = new File(base, path);
334 String name = null;
335
336 try
337 {
338 name = file.getCanonicalPath();
339 }
340 catch (IOException e)
341 {
342 logger.error("PSMLManager: unable to resolve file path for "+ file);
343 }
344
345 if (logger.isDebugEnabled())
346 {
347 logger.debug("PSMLManager: calculated resource:" + path + ". Base: " + base + " File: " + name);
348 }
349
350 PSMLDocument doc = null;
351 Profile profile = null;
352
353 if (getCached == true)
354 {
355 profile = (Profile)documents.getDocument(name);
356 }
357
358 if (profile == null)
359 {
360 doc = loadDocument(name);
361 if (null == doc)
362 {
363 if (logger.isWarnEnabled())
364 {
365 logger.warn( "PSMLManager: " + name + " not found, returning null document" );
366 }
367 return null;
368 }
369
370 synchronized (documents)
371 {
372
373 Profile newProfile = createProfile(locator);
374 newProfile.setDocument(doc);
375 try
376 {
377 documents.put(name, newProfile);
378 }
379 catch (IOException e)
380 {
381 logger.error("Error putting document", e);
382 }
383 }
384 }
385 else
386 {
387 doc = profile.getDocument();
388 }
389
390 return doc;
391 }
392
393 /***
394 * Loads a PSML document from disk bypassing the cache
395 *
396 * @param locator
397 * @return PSML document from disk
398 */
399 public PSMLDocument refresh(ProfileLocator locator)
400 {
401 if (logger.isDebugEnabled())
402 {
403 logger.debug("CastorPsmlManagerService: psml document refreshed from disk: " + locator.getPath());
404 }
405 return getDocument(locator, false);
406 }
407
408 /***
409 * Load a PSMLDOcument from disk
410 *
411 * @param fileOrUrl a String representing either an absolute URL or an
412 * absolute filepath
413 */
414 protected PSMLDocument loadDocument(String fileOrUrl)
415 {
416 PSMLDocument doc = null;
417
418 if (fileOrUrl!=null)
419 {
420 if (!fileOrUrl.endsWith(DEFAULT_EXT))
421 {
422 fileOrUrl = fileOrUrl.concat(DEFAULT_EXT);
423 }
424
425
426
427
428 File f = getFile(fileOrUrl);
429 if (null == f)
430 return null;
431
432 doc = new BasePSMLDocument();
433 doc.setName(fileOrUrl);
434
435
436 Portlets portlets = null;
437 try
438 {
439 DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
440 DocumentBuilder builder = dbfactory.newDocumentBuilder();
441
442 Document d = builder.parse(f);
443
444 Unmarshaller unmarshaller = new Unmarshaller(this.mapping);
445 portlets = (Portlets)unmarshaller.unmarshal((Node) d);
446
447 doc.setPortlets(portlets);
448
449 }
450 catch (IOException e)
451 {
452 logger.error("PSMLManager: Could not load the file "+f.getAbsolutePath(), e);
453 doc = null;
454 }
455 catch (MarshalException e)
456 {
457 logger.error("PSMLManager: Could not unmarshal the file "+f.getAbsolutePath(), e);
458 doc = null;
459 }
460 catch (MappingException e)
461 {
462 logger.error("PSMLManager: Could not unmarshal the file "+f.getAbsolutePath(), e);
463 doc = null;
464 }
465 catch (ValidationException e)
466 {
467 logger.error("PSMLManager: document "+f.getAbsolutePath()+" is not valid", e);
468 doc = null;
469 }
470 catch (ParserConfigurationException e)
471 {
472 logger.error("PSMLManager: Could not load the file "+f.getAbsolutePath(), e);
473 doc = null;
474 }
475 catch (SAXException e)
476 {
477 logger.error("PSMLManager: Could not load the file "+f.getAbsolutePath(), e);
478 doc = null;
479 }
480 }
481
482 return doc;
483 }
484
485 /*** Store the PSML document on disk, using its locator
486 *
487 * @param profile the profile locator description.
488 * @return true if the operation succeeded
489 */
490 public boolean store(Profile profile)
491 {
492 PSMLDocument doc = profile.getDocument();
493
494 File base = this.rootDir;
495 String path = mapLocatorToFile(profile);
496
497 File file = new File(base, path);
498 String fullpath = null;
499
500 try
501 {
502 fullpath = file.getCanonicalPath();
503 }
504 catch (IOException e)
505 {
506 logger.error("PSMLManager: unable to resolve file path for "+ file);
507 }
508
509 boolean ok = saveDocument(fullpath, doc);
510
511
512 synchronized (documents)
513 {
514 try
515 {
516 documents.put(fullpath, profile);
517 }
518 catch (IOException e)
519 {
520 logger.error("Error storing document", e);
521 }
522 }
523
524 return ok;
525 }
526
527 /*** Save the PSML document on disk, using its name as filepath
528 * @deprecated
529 * @param doc the document to save
530 */
531 public boolean saveDocument(PSMLDocument doc)
532 {
533 return saveDocument(doc.getName(), doc);
534 }
535
536 /*** Save the PSML document on disk to the specififed fileOrUrl
537 *
538 * @param fileOrUrl a String representing either an absolute URL
539 * or an absolute filepath
540 * @param doc the document to save
541 */
542 public boolean saveDocument(String fileOrUrl, PSMLDocument doc)
543 {
544 boolean success = false;
545
546 if (doc == null) return false;
547 File f = getFile(fileOrUrl);
548 if (f == null)
549 {
550 f = new File(fileOrUrl);
551 }
552
553 OutputStreamWriter writer = null;
554 FileOutputStream fos = null;
555 try
556 {
557 String encoding = this.defaultEncoding;
558 fos = new FileOutputStream(f);
559 writer = new OutputStreamWriter(fos, encoding);
560
561 save(writer, doc.getPortlets());
562 success = true;
563 }
564 catch (MarshalException e)
565 {
566 logger.error("PSMLManager: Could not marshal the file "+f.getAbsolutePath(), e);
567 }
568 catch (MappingException e)
569 {
570 logger.error("PSMLManager: Could not marshal the file "+f.getAbsolutePath(), e);
571 }
572 catch (ValidationException e)
573 {
574 logger.error("PSMLManager: document "+f.getAbsolutePath()+" is not valid", e);
575 }
576 catch (IOException e)
577 {
578 logger.error("PSMLManager: Could not save the file "+f.getAbsolutePath(), e);
579 }
580 catch (Exception e)
581 {
582 logger.error("PSMLManager: Error while saving "+f.getAbsolutePath(), e);
583 }
584 finally
585 {
586 try { writer.close(); } catch (IOException e) {}
587 try { if(fos != null) { fos.close(); } } catch (IOException e) {}
588 }
589
590 return success;
591 }
592
593 /*** Deserializes a PSML structure read from the reader using Castor
594 * XML unmarshaller
595 *
596 * @param reader the reader to load the PSML from
597 * @param the loaded portlets structure or null
598 */
599 protected Portlets load(Reader reader)
600 throws IOException, MarshalException, ValidationException, MappingException
601 {
602 Unmarshaller unmarshaller = new Unmarshaller(this.mapping);
603 Portlets portlets = (Portlets)unmarshaller.unmarshal(reader);
604 return portlets;
605 }
606
607 protected void loadMapping()
608 throws InitializationException
609 {
610
611
612 if (mapFile != null)
613 {
614 File map = new File(mapFile);
615 if (logger.isDebugEnabled())
616 {
617 logger.debug("PSMLManager: Loading psml mapping file "+mapFile);
618 }
619 if (map.exists() && map.isFile() && map.canRead())
620 {
621 try
622 {
623 mapping = new Mapping();
624 InputSource is = new InputSource( new FileReader(map) );
625 is.setSystemId( mapFile );
626 mapping.loadMapping( is );
627 }
628 catch (Exception e)
629 {
630 logger.error("PSMLManager: Error in psml mapping creation", e);
631 throw new InitializationException("Error in mapping",e);
632 }
633 }
634 else
635 {
636 throw new InitializationException("PSML Mapping not found or not a file or unreadable: "+mapFile);
637 }
638 }
639 }
640
641 /*** Serializes a PSML structure using the specified writer with Castor
642 * XML marshaller and a Xerces serializer for pretty printing
643 *
644 * @param writer the writer to use for serialization
645 * @param portlets the structure to save
646 */
647 protected void save(Writer writer, Portlets portlets)
648 throws IOException, MarshalException, ValidationException, MappingException
649 {
650 String encoding = this.defaultEncoding;
651
652 if (portlets != null)
653 {
654 format.setEncoding(encoding);
655 Serializer serializer = new XMLSerializer(writer, format);
656 Marshaller marshaller = new Marshaller(serializer.asDocumentHandler());
657 marshaller.setMapping(this.mapping);
658 marshaller.marshal(portlets);
659 }
660 }
661
662 /*** Tests wether the passed argument is an URL string or a file name
663 * and returns the corresponding file object, using diskcache for
664 * remote URLs
665 *
666 * @param fileOrUrl the URL string or file path
667 * @return a File object. This file may not exist on disk.
668 */
669 protected File getFile(String fileOrUrl)
670 {
671 File f = null;
672
673 f = new File(fileOrUrl);
674
675 if (f.exists())
676 {
677 return f;
678 }
679
680 return null;
681 }
682
683 /*** Create a new document.
684 *
685 * @param profile The description and default value for the new document.
686 * @return The newly created document;
687 */
688 public PSMLDocument createDocument( Profile profile )
689 {
690 File base = this.rootDir;
691 String path = mapLocatorToFile((ProfileLocator)profile);
692
693 if (logger.isDebugEnabled())
694 {
695 logger.debug("PSMLManager: Create document for profile " + profile +", calculated path: " + path);
696 }
697
698 File file = new File(base, path);
699 String name = null;
700
701 try
702 {
703 name = file.getCanonicalPath();
704 }
705 catch (IOException e)
706 {
707 logger.error("PSMLManager: unable to resolve file path for "+ file);
708 }
709
710 PSMLDocument template = profile.getDocument();
711 PSMLDocument doc = new BasePSMLDocument( name, template.getPortlets() );
712 try
713 {
714 String parent = file.getParent();
715 File filePath = new File(parent);
716 filePath.mkdirs();
717 if (template.getName() != null)
718 {
719 try
720 {
721 File source = new File(template.getName());
722 if (source.exists())
723 {
724 FileCopy.copy( template.getName(), name );
725 }
726 }
727 catch (Exception e)
728 {}
729 }
730 else
731 {
732 doc.setName(name);
733 }
734 saveDocument(doc);
735 }
736 catch (Exception e)
737 {
738 logger.error("PSMLManager: Failed to save document: " , e);
739 }
740 return doc;
741 }
742
743 /*** Given a ordered list of locators, find the first document matching
744 * a profile locator, starting from the beginning of the list and working
745 * to the end.
746 *
747 * @param locator The ordered list of profile locators.
748 */
749 public PSMLDocument getDocument( List locators )
750 {
751 PSMLDocument doc=null;
752
753 Iterator i = locators.iterator();
754 while ((doc==null)&&(i.hasNext()))
755 {
756 doc=getDocument((ProfileLocator)i.next());
757 }
758
759 return doc;
760 }
761
762 /*** Removes a document.
763 *
764 * @param locator The description of the profile resource to be removed.
765 */
766 public void removeDocument( ProfileLocator locator )
767 {
768
769 String fileName = mapLocatorToFile(locator);
770
771 File base = this.rootDir;
772 File file = new File(base, fileName);
773 String name = null;
774
775 try
776 {
777 name = file.getCanonicalPath();
778 }
779 catch (IOException e)
780 {
781 logger.error("PSMLManager: unable to resolve file path for "+ file);
782 }
783
784
785 synchronized (documents)
786 {
787 documents.remove(name);
788 }
789
790 file.delete();
791
792 }
793
794 /*** Removes all documents for a given user.
795 *
796 * @param user The user object.
797 */
798 public void removeUserDocuments( JetspeedUser user )
799 {
800 ProfileLocator locator = Profiler.createLocator();
801 locator.setUser(user);
802 StringBuffer buffer = new StringBuffer();
803 buffer.append(PATH_USER);
804 String name = user.getUserName();
805 if (null != name && name.length() > 0)
806 {
807 buffer.append(File.separator)
808 .append(name);
809 }
810 else
811 return;
812
813 String path = buffer.toString();
814 File base = this.rootDir;
815 File file = new File(base, path);
816
817 try
818 {
819 name = file.getCanonicalPath();
820 }
821 catch (IOException e)
822 {
823 logger.error("PSMLManager: unable to resolve file path for "+ file);
824 }
825
826
827 synchronized (documents)
828 {
829 DirectoryUtils.rmdir(name);
830 Iterator it = documents.getIterator();
831 while (it.hasNext())
832 {
833 FileCacheEntry entry = (FileCacheEntry)it.next();
834 if (null == entry)
835 {
836 continue;
837 }
838 Profile profile = (Profile)entry.getDocument();
839 if (null == profile)
840 {
841 continue;
842 }
843 JetspeedUser pUser = profile.getUser();
844 if (null != pUser && pUser.getUserName().equals(user.getUserName()))
845 {
846 documents.remove(profile.getDocument().getName());
847 }
848 }
849 }
850
851 }
852
853 /*** Removes all documents for a given role.
854 *
855 * @param role The role object.
856 */
857 public void removeRoleDocuments( Role role )
858 {
859 ProfileLocator locator = Profiler.createLocator();
860 locator.setRole(role);
861 StringBuffer buffer = new StringBuffer();
862 buffer.append(PATH_ROLE);
863 String name = role.getName();
864 if (null != name && name.length() > 0)
865 {
866 buffer.append(File.separator)
867 .append(name);
868 }
869 else
870 return;
871
872 String path = buffer.toString();
873 File base = this.rootDir;
874 File file = new File(base, path);
875
876 try
877 {
878 name = file.getCanonicalPath();
879 }
880 catch (IOException e)
881 {
882 logger.error("PSMLManager: unable to resolve file path for "+ file);
883 }
884
885
886 synchronized (documents)
887 {
888 DirectoryUtils.rmdir(name);
889 Iterator it = documents.getIterator();
890 while (it.hasNext())
891 {
892 FileCacheEntry entry = (FileCacheEntry)it.next();
893 if (null == entry)
894 {
895 continue;
896 }
897 Profile profile = (Profile)entry.getDocument();
898 if (null == profile)
899 {
900 continue;
901 }
902 Role pRole = profile.getRole();
903 if (null != pRole && pRole.getName().equals(role.getName()))
904 {
905 documents.remove(profile.getDocument().getName());
906 }
907 }
908 }
909 }
910
911 /*** Removes all documents for a given group.
912 *
913 * @param group The group object.
914 */
915 public void removeGroupDocuments( Group group )
916 {
917 ProfileLocator locator = Profiler.createLocator();
918 locator.setGroup(group);
919 StringBuffer buffer = new StringBuffer();
920 buffer.append(PATH_GROUP);
921 String name = group.getName();
922 if (null != name && name.length() > 0)
923 {
924 buffer.append(File.separator)
925 .append(name);
926 }
927 else
928 return;
929
930 String path = buffer.toString();
931 File base = this.rootDir;
932 File file = new File(base, path);
933
934 try
935 {
936 name = file.getCanonicalPath();
937 }
938 catch (IOException e)
939 {
940 logger.error("PSMLManager: unable to resolve file path for "+ file);
941 }
942
943
944 synchronized (documents)
945 {
946 DirectoryUtils.rmdir(name);
947 Iterator it = documents.getIterator();
948 while (it.hasNext())
949 {
950 FileCacheEntry entry = (FileCacheEntry)it.next();
951 if (null == entry)
952 {
953 continue;
954 }
955 Profile profile = (Profile)entry.getDocument();
956 if (null == profile)
957 {
958 continue;
959 }
960 Group pGroup = profile.getGroup();
961 if (null != pGroup && pGroup.getName().equals(group.getName()))
962 {
963 documents.remove(profile.getDocument().getName());
964 }
965 }
966 }
967
968 }
969
970
971 /***
972 * Maps a ProfileLocator to a file.
973 *
974 * @param locator The profile locator describing the PSML resource to be found.
975 * @return the String path of the file.
976 */
977 protected String mapLocatorToFile(ProfileLocator locator)
978 {
979 StringBuffer path = new StringBuffer();
980
981
982 Role role = locator.getRole();
983 Group group = locator.getGroup();
984 JetspeedUser user = locator.getUser();
985
986 if (user != null)
987 {
988 path.append(PATH_USER);
989 String name = user.getUserName();
990 if (null != name && name.length() > 0)
991 {
992 path.append(File.separator)
993 .append(name);
994 }
995 }
996 else if (group != null)
997 {
998 path.append(PATH_GROUP);
999 String name = group.getName();
1000 if (null != name && name.length() > 0)
1001 {
1002 path.append(File.separator)
1003 .append(name);
1004 }
1005 }
1006 else if (null != role)
1007 {
1008 path.append(PATH_ROLE);
1009 String name = role.getName();
1010 if (null != name && name.length() > 0)
1011 {
1012 path.append(File.separator)
1013 .append(name);
1014 }
1015 }
1016
1017
1018 if (null != locator.getMediaType())
1019 {
1020 path.append(File.separator)
1021 .append(locator.getMediaType());
1022 }
1023
1024 if (null != locator.getLanguage() && (! locator.getLanguage().equals("-1")))
1025 {
1026 path.append(File.separator)
1027 .append(locator.getLanguage());
1028 }
1029
1030 if (null != locator.getCountry() && (! locator.getCountry().equals("-1")))
1031 {
1032 path.append(File.separator)
1033 .append(locator.getCountry());
1034 }
1035
1036 if (null != locator.getName())
1037 {
1038 if (!(locator.getName().endsWith(CastorPsmlManagerService.DEFAULT_EXT)))
1039 {
1040 path.append(File.separator)
1041 .append(locator.getName()).append(CastorPsmlManagerService.DEFAULT_EXT);
1042 }
1043 else
1044 {
1045 path.append(File.separator)
1046 .append(locator.getName());
1047 }
1048 }
1049 else
1050 {
1051 path.append(File.separator)
1052 .append(DEFAULT_RESOURCE);
1053 }
1054
1055 return path.toString();
1056 }
1057
1058 protected static int STATE_INIT = 0;
1059 protected static int STATE_BASE = 1;
1060 protected static int STATE_NAME = 2;
1061 protected static int STATE_MEDIA = 3;
1062 protected static int STATE_LANGUAGE = 4;
1063 protected static int STATE_COUNTRY = 5;
1064
1065 /*** Query for a collection of profiles given a profile locator criteria.
1066 *
1067 * @param locator The profile locator criteria.
1068 */
1069 public Iterator query( QueryLocator locator )
1070 {
1071 List list = new LinkedList();
1072
1073 Role role = locator.getRole();
1074 Group group = locator.getGroup();
1075 JetspeedUser user = locator.getUser();
1076
1077
1078 int qm = locator.getQueryMode();
1079 if ((qm & QueryLocator.QUERY_USER) == QueryLocator.QUERY_USER)
1080 {
1081 Profile profile = createProfile();
1082 StringBuffer path = new StringBuffer();
1083 path.append(PATH_USER);
1084 String name = null;
1085 int state = STATE_INIT;
1086 if (null != user)
1087 {
1088 name = user.getUserName();
1089 profile.setUser( user );
1090 if (null != name)
1091 {
1092 path.append(File.separator).append(name);
1093 state = STATE_BASE;
1094 }
1095 }
1096 File base = this.rootDir;
1097 File file = new File(base, path.toString());
1098 String absPath = file.getAbsolutePath();
1099 QueryState qs = new QueryState( QUERY_BY_USER,
1100 profile,
1101 locator,
1102 list,
1103 name,
1104 state);
1105 subQuery(qs, absPath);
1106 }
1107 if ((qm & QueryLocator.QUERY_ROLE) == QueryLocator.QUERY_ROLE)
1108 {
1109 Profile profile = createProfile();
1110 StringBuffer path = new StringBuffer();
1111 path.append(PATH_ROLE);
1112 String name = null;
1113 int state = STATE_INIT;
1114 if (null != role)
1115 {
1116 name = role.getName();
1117 profile.setRole( role );
1118 if (null != name)
1119 {
1120 path.append(File.separator).append(name);
1121 state = STATE_BASE;
1122 }
1123 }
1124 File base = this.rootDir;
1125 File file = new File(base, path.toString());
1126 String absPath = null;
1127
1128 try
1129 {
1130 absPath = file.getCanonicalPath();
1131 }
1132 catch (IOException e)
1133 {
1134 logger.error("PSMLManager: unable to resolve file path for "+ file);
1135 }
1136
1137 QueryState qs = new QueryState( QUERY_BY_ROLE,
1138 profile,
1139 locator,
1140 list,
1141 name,
1142 state);
1143 subQuery(qs, absPath);
1144 }
1145 if ((qm & QueryLocator.QUERY_GROUP) == QueryLocator.QUERY_GROUP)
1146 {
1147 Profile profile = createProfile();
1148 StringBuffer path = new StringBuffer();
1149 path.append(PATH_GROUP);
1150 String name = null;
1151 int state = STATE_INIT;
1152 if (null != group)
1153 {
1154 name = group.getName();
1155 profile.setGroup( group );
1156 if (null != name)
1157 {
1158 path.append(File.separator).append(name);
1159 state = STATE_BASE;
1160 }
1161 }
1162 File base = this.rootDir;
1163 File file = new File(base, path.toString());
1164 String absPath = null;
1165
1166 try
1167 {
1168 absPath = file.getCanonicalPath();
1169 }
1170 catch (IOException e)
1171 {
1172 logger.error("PSMLManager: unable to resolve file path for "+ file);
1173 }
1174
1175 QueryState qs = new QueryState( QUERY_BY_GROUP,
1176 profile,
1177 locator,
1178 list,
1179 name,
1180 state);
1181 subQuery(qs, absPath);
1182 }
1183
1184 return list.iterator();
1185 }
1186
1187 /*** Create a profile based on import flag.
1188 *
1189 */
1190 protected Profile createProfile()
1191 {
1192 if (importFlag)
1193 return new ImportProfile(this, this.consumer);
1194 else
1195 return Profiler.createProfile();
1196 }
1197
1198 protected Profile createProfile(ProfileLocator locator)
1199 {
1200 if (importFlag)
1201 return new ImportProfile(this, this.consumer, locator);
1202 else
1203 return Profiler.createProfile(locator);
1204 }
1205
1206 /*** Query for a collection of profiles given a profile locator criteria.
1207 * This method should be used when importing or exporting profiles between services.
1208 *
1209 * @param locator The profile locator criteria.
1210 * @return The count of profiles exported.
1211 */
1212 public int export(PsmlManagerService consumer, QueryLocator locator)
1213 {
1214 importFlag = true;
1215 Iterator profiles = null;
1216 int count = 0;
1217 try
1218 {
1219 this.consumer = consumer;
1220 profiles = query(locator);
1221
1222 while (profiles.hasNext() )
1223 {
1224 Profile profile = (Profile)profiles.next();
1225
1226 try
1227 {
1228 consumer.createDocument(profile);
1229 count++;
1230 }
1231 catch (Exception ex)
1232 {
1233 try
1234 {
1235 consumer.store(profile);
1236 count++;
1237 }
1238 catch (Exception e)
1239 {
1240 logger.error("PSMLManager: Failed to export profiles to DB: " + profile, ex );
1241 }
1242 }
1243 }
1244 }
1245 catch(Exception e)
1246 {
1247 e.printStackTrace();
1248 logger.error("PSMLManager: Failed to export profiles to DB: " , e );
1249
1250 }
1251 finally
1252 {
1253 importFlag = false;
1254 }
1255 return count;
1256 }
1257
1258
1259 /*** Query for a collection of profiles given a profile locator criteria.
1260 * To specify 'all' - use '*' in the criteria
1261 *
1262 * @param locator The profile locator criteria.
1263 */
1264 protected void subQuery(QueryState qs, String path)
1265 {
1266 File file = new File(path);
1267 if (file.isFile())
1268 {
1269 try
1270 {
1271 String filename = file.getName();
1272 if (!filename.endsWith(this.ext))
1273 return;
1274
1275 Profile clone = (Profile)qs.profile.clone();
1276 clone.setName(filename);
1277 qs.list.add( clone );
1278 }
1279 catch (Exception e)
1280 {
1281 logger.error("PSMLManager: Failed to clone profile: " + path + " : " + e, e);
1282 }
1283 }
1284 else if (file.isDirectory())
1285 {
1286 String dirName = file.getName();
1287 qs.state++;
1288
1289
1290 if (qs.state == STATE_NAME)
1291 {
1292 if (null != qs.name)
1293 {
1294 if (!dirName.equals(qs.name))
1295 return;
1296 }
1297 try
1298 {
1299 if (QUERY_BY_USER == qs.queryBy)
1300 {
1301 JetspeedUser user = (JetspeedUser)qs.profile.getUser();
1302 if (null == user)
1303 {
1304 user = JetspeedUserFactory.getInstance();
1305 user.setUserName(file.getName());
1306 qs.profile.setUser(user);
1307 qs.clearName = true;
1308 }
1309 }
1310 else if (QUERY_BY_ROLE == qs.queryBy)
1311 {
1312 Role role = qs.profile.getRole();
1313 if (null == role)
1314 {
1315 role = JetspeedRoleFactory.getInstance();
1316 role.setName(file.getName());
1317 qs.profile.setRole(role);
1318 qs.clearName = true;
1319 }
1320 }
1321 else if (QUERY_BY_GROUP == qs.queryBy)
1322 {
1323 Group group = qs.profile.getGroup();
1324 if (null == group)
1325 {
1326 group = JetspeedGroupFactory.getInstance();
1327 group.setName(file.getName());
1328 qs.profile.setGroup(group);
1329 qs.clearName = true;
1330 }
1331 }
1332 }
1333 catch (Exception e)
1334 {}
1335
1336
1337 }
1338 else if (qs.state == STATE_MEDIA)
1339 {
1340 String media = qs.locator.getMediaType();
1341 if (null != media)
1342 {
1343 if (!dirName.equals(media))
1344 return;
1345 }
1346 else
1347 {
1348 qs.profile.setMediaType(dirName);
1349 qs.clearMedia = true;
1350 }
1351 }
1352 else if (qs.state == STATE_LANGUAGE)
1353 {
1354 String language = qs.locator.getLanguage();
1355 if (null != language)
1356 {
1357 if (!dirName.equals(language))
1358 return;
1359 }
1360 else
1361 {
1362 qs.profile.setLanguage(dirName);
1363 qs.clearLanguage = true;
1364 }
1365 }
1366 else if (qs.state == STATE_COUNTRY)
1367 {
1368 String country = qs.locator.getCountry();
1369 if (null != country)
1370 {
1371 if (!dirName.equals(country))
1372 return;
1373 }
1374 else
1375 {
1376 qs.profile.setCountry(dirName);
1377 qs.clearCountry = true;
1378 }
1379 }
1380
1381 if (!path.endsWith(File.separator))
1382 path += File.separator;
1383
1384 String files[] = file.list();
1385
1386
1387
1388 for(int ix = 0; files != null && ix < files.length; ix++)
1389 {
1390 subQuery(qs, path + files[ix]);
1391 }
1392
1393
1394 if (qs.state == STATE_NAME && true == qs.clearName)
1395 {
1396 if (QUERY_BY_USER == qs.queryBy)
1397 qs.profile.setUser(null);
1398 else if (QUERY_BY_ROLE == qs.queryBy)
1399 qs.profile.setRole(null);
1400 else if (QUERY_BY_GROUP == qs.queryBy)
1401 qs.profile.setGroup(null);
1402 qs.clearName = false;
1403 }
1404 else if (qs.state == STATE_MEDIA && true == qs.clearMedia)
1405 {
1406 qs.profile.setMediaType(null);
1407 qs.clearMedia = false;
1408 }
1409 else if (qs.state == STATE_LANGUAGE && true == qs.clearLanguage)
1410 {
1411 qs.profile.setLanguage(null);
1412 qs.clearLanguage = false;
1413 }
1414 else if (qs.state == STATE_COUNTRY && true == qs.clearCountry)
1415 {
1416 qs.profile.setCountry(null);
1417 qs.clearCountry = false;
1418 }
1419
1420 qs.state--;
1421
1422 }
1423
1424 }
1425
1426 static int QUERY_BY_USER = 0;
1427 static int QUERY_BY_ROLE = 1;
1428 static int QUERY_BY_GROUP = 2;
1429
1430 protected class QueryState
1431 {
1432
1433 QueryState( int queryBy,
1434 Profile profile,
1435 ProfileLocator locator,
1436 List list,
1437 String name,
1438 int state)
1439 {
1440 this.queryBy = queryBy;
1441 this.profile = profile;
1442 this.locator = locator;
1443 this.list = list;
1444 this.name = name;
1445 this.state = state;
1446 }
1447
1448 protected int queryBy;
1449 protected Profile profile;
1450 protected ProfileLocator locator;
1451 protected List list;
1452 protected String name;
1453 protected int state;
1454
1455 protected boolean clearName = false;
1456 protected boolean clearMedia = false;
1457 protected boolean clearLanguage = false;
1458 protected boolean clearCountry = false;
1459
1460 }
1461
1462 protected void testCases()
1463 {
1464 try
1465 {
1466 QueryLocator locator = new QueryLocator( QueryLocator.QUERY_USER );
1467 Iterator x1 = query( locator );
1468 dump( x1 );
1469
1470 QueryLocator locator2 = new QueryLocator( QueryLocator.QUERY_USER );
1471 locator2.setUser( JetspeedSecurity.getUser("turbine") );
1472 Iterator x2 = query( locator2 );
1473 dump( x2 );
1474
1475
1476 QueryLocator locator4 = new QueryLocator( QueryLocator.QUERY_GROUP );
1477
1478 Iterator x4 = query( locator4 );
1479 dump( x4 );
1480 }
1481 catch (Exception e)
1482 {
1483 System.out.println( "Exception in Debug:" + e);
1484 }
1485 }
1486
1487 protected void dump( Iterator it )
1488 {
1489 System.out.println("===============================================");
1490 while (it.hasNext() )
1491 {
1492 Profile profile = (Profile)it.next();
1493 dumpProfile(profile);
1494 }
1495 System.out.println("===============================================");
1496 }
1497
1498 protected void dumpProfile(Profile profile)
1499 {
1500 JetspeedUser user = profile.getUser();
1501 Group group = profile.getGroup();
1502 Role role = profile.getRole();
1503 if (profile.getAnonymous() == true)
1504 System.out.println("ANON USER");
1505 System.out.println("RESOURCE = " + profile.getName());
1506 if (null != user)
1507 System.out.println("USER = " + user.getUserName() );
1508 if (null != group)
1509 System.out.println("GROUP = " + group.getName() );
1510 if (null != role)
1511 System.out.println("ROLE = " + role.getName() );
1512 System.out.println("MEDIA TYPE = " + profile.getMediaType());
1513 System.out.println("LANGUAGE = " + profile.getLanguage());
1514 System.out.println("COUNTRY = " + profile.getCountry());
1515 PSMLDocument doc = profile.getDocument();
1516 if (null == doc)
1517 System.out.println("Document is null");
1518 else
1519 {
1520 if (null == profile.getName())
1521 System.out.println("profile name is null");
1522 else
1523 System.out.println("Doc.name=" + profile.getName());
1524 }
1525
1526 System.out.println("----------------------");
1527 }
1528
1529 /***
1530 * Refresh event, called when the entry is being refreshed from file system.
1531 *
1532 * @param entry the entry being refreshed.
1533 */
1534 public void refresh(FileCacheEntry entry)
1535 {
1536 if (logger.isInfoEnabled())
1537 {
1538 logger.info("CastorPsmlManager: Entry is refreshing: " + entry.getFile().getPath());
1539 }
1540
1541 Profile profile = (Profile) entry.getDocument();
1542 String path = null;
1543
1544 if (profile != null)
1545 {
1546 try
1547 {
1548 path = entry.getFile().getCanonicalPath();
1549 profile.setDocument(loadDocument(path));
1550 }
1551 catch(java.io.IOException e)
1552 {
1553 logger.error("CastorPsmlManager: Failed to refresh document "+path);
1554 }
1555 }
1556 }
1557
1558 /***
1559 * Evict event, called when the entry is being evicted out of the cache
1560 *
1561 * @param entry the entry being refreshed.
1562 */
1563 public void evict(FileCacheEntry entry)
1564 {
1565 System.out.println("entry is evicting: " + entry.getFile().getName());
1566 }
1567
1568 }
1569