| 1 16 17 package org.apache.jetspeed.services.psmlmanager; 18 19 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 import org.apache.jetspeed.om.profile.Portlets; 32 import org.apache.jetspeed.om.profile.*; 33 34 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 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 import org.apache.xml.serialize.Serializer; 63 import org.apache.xml.serialize.XMLSerializer; 64 import org.apache.xml.serialize.OutputFormat; 65 66 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 95 public class CastorPsmlManagerService extends TurbineBaseService 96 implements FileCacheEventListener, 97 PsmlManagerService 98 { 99 102 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(CastorPsmlManagerService.class.getName()); 103 104 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 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 public final static String DEFAULT_ROOT = "/WEB-INF/psml"; 117 public final static String DEFAULT_EXT = ".psml"; 118 119 public final static String DEFAULT_RESOURCE = "default.psml"; 121 122 protected String root; 124 protected File rootDir = null; 126 protected String ext; 128 129 130 protected FileCache documents = null; 131 132 133 protected OutputFormat format = null; 134 135 136 protected long scanRate = 1000 * 60; 138 139 protected int cacheSize = 100; 140 141 142 protected PsmlManagerService consumer = null; 143 protected boolean importFlag = false; 144 145 public static final String DEFAULT_MAPPING = "${webappRoot}/WEB-INF/conf/psml-mapping.xml"; 147 protected String mapFile = null; 148 149 150 protected Mapping mapping = null; 151 152 153 protected String defaultEncoding = JetspeedResources.getString(JetspeedResources.CONTENT_ENCODING_KEY, "utf-8"); 154 155 159 public void init( ServletConfig conf ) throws InitializationException 160 { 161 if (getInit()) 162 { 163 return; 164 } 165 166 TurbineServices.getInstance().initService(ServletService.SERVICE_NAME, conf); 168 169 ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance()) 171 .getResources(PsmlManagerService.SERVICE_NAME); 172 this.root = serviceConf.getString( CONFIG_ROOT, DEFAULT_ROOT ); 174 this.rootDir = new File (root); 175 176 if ( !rootDir.exists() ) 178 { 179 try 180 { 181 this.rootDir = new File (conf.getServletContext().getRealPath(root)); 182 } 183 catch (Exception e) 184 { 185 } 187 } 188 if (!rootDir.exists()) 190 { 191 try 192 { 193 rootDir.mkdirs(); 194 } 195 catch (Exception e) 196 { 197 } 198 } 199 200 this.ext = serviceConf.getString( CONFIG_EXT, DEFAULT_EXT ); 202 203 this.format = new OutputFormat(); 205 format.setIndenting(true); 206 format.setIndent(4); 207 format.setLineWidth(0); 208 209 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 setInit(true); 224 225 228 } 229 230 231 232 public void init() throws InitializationException 233 { 234 while( !getInit() ) 235 { 236 try 238 { 239 Thread.sleep( 500 ); 240 } 241 catch (InterruptedException ie ) 242 { 243 logger.error("Exception", ie); 244 } 245 } 246 } 247 248 249 253 public void shutdown() 254 { 255 documents.stopFileScanner(); 256 } 257 258 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 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 311 public PSMLDocument getDocument( ProfileLocator locator) 312 { 313 return getDocument(locator, true); 314 } 315 316 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 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 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 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 428 File f = getFile(fileOrUrl); 429 if (null == f) 430 return null; 431 432 doc = new BasePSMLDocument(); 433 doc.setName(fileOrUrl); 434 435 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 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 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 531 public boolean saveDocument(PSMLDocument doc) 532 { 533 return saveDocument(doc.getName(), doc); 534 } 535 536 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 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 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 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 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 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 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 766 public void removeDocument( ProfileLocator locator ) 767 { 768 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 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; 813 String path = buffer.toString(); 814 File base = this.rootDir; 815 File |