001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.ui; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.text.SimpleDateFormat; 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.Date; 028import java.util.Enumeration; 029import java.util.HashMap; 030import java.util.LinkedHashMap; 031import java.util.List; 032import java.util.Locale; 033import java.util.Map; 034import java.util.Properties; 035import java.util.ResourceBundle; 036import java.util.Set; 037import java.util.TimeZone; 038import java.util.TreeSet; 039import java.util.Vector; 040 041import javax.servlet.ServletContext; 042import javax.servlet.http.HttpServletRequest; 043import javax.servlet.jsp.PageContext; 044import javax.servlet.jsp.jstl.fmt.LocaleSupport; 045 046import org.apache.commons.lang.StringUtils; 047import org.apache.log4j.Logger; 048import org.apache.wiki.InternalWikiException; 049import org.apache.wiki.WikiContext; 050import org.apache.wiki.WikiEngine; 051import org.apache.wiki.i18n.InternationalizationManager; 052import org.apache.wiki.modules.ModuleManager; 053import org.apache.wiki.modules.WikiModuleInfo; 054import org.apache.wiki.preferences.Preferences; 055import org.apache.wiki.preferences.Preferences.TimeFormat; 056import org.apache.wiki.util.ClassUtil; 057 058 059/** 060 * This class takes care of managing JSPWiki templates. This class also provides 061 * the ResourceRequest mechanism. 062 * 063 * @since 2.1.62 064 */ 065public class TemplateManager extends ModuleManager { 066 067 private static final String SKIN_DIRECTORY = "skins"; 068 069 /** 070 * Requests a JavaScript function to be called during window.onload. Value is {@value}. 071 */ 072 public static final String RESOURCE_JSFUNCTION = "jsfunction"; 073 074 /** 075 * Requests a JavaScript associative array with all localized strings. 076 */ 077 public static final String RESOURCE_JSLOCALIZEDSTRINGS = "jslocalizedstrings"; 078 079 /** 080 * Requests a stylesheet to be inserted. Value is {@value}. 081 */ 082 public static final String RESOURCE_STYLESHEET = "stylesheet"; 083 084 /** 085 * Requests a script to be loaded. Value is {@value}. 086 */ 087 public static final String RESOURCE_SCRIPT = "script"; 088 089 /** 090 * Requests inlined CSS. Value is {@value}. 091 */ 092 public static final String RESOURCE_INLINECSS = "inlinecss"; 093 094 /** The default directory for the properties. Value is {@value}. */ 095 public static final String DIRECTORY = "templates"; 096 097 /** The name of the default template. Value is {@value}. */ 098 public static final String DEFAULT_TEMPLATE = "default"; 099 100 /** Name of the file that contains the properties. */ 101 102 public static final String PROPERTYFILE = "template.properties"; 103 104 /** Location of I18N Resource bundles, and path prefix and suffixes */ 105 106 public static final String I18NRESOURCE_PREFIX = "templates/default_"; 107 108 public static final String I18NRESOURCE_SUFFIX = ".properties"; 109 110 /** The default (en) RESOURCE name and id. */ 111 112 public static final String I18NRESOURCE_EN = "templates/default.properties"; 113 public static final String I18NRESOURCE_EN_ID = "en"; 114 115 /** I18N string to mark the default locale */ 116 117 public static final String I18NDEFAULT_LOCALE = "prefs.user.language.default"; 118 119 /** I18N string to mark the server timezone */ 120 121 public static final String I18NSERVER_TIMEZONE = "prefs.user.timezone.server"; 122 123 /** Prefix of the default timeformat properties. */ 124 125 public static final String TIMEFORMATPROPERTIES = "jspwiki.defaultprefs.timeformat."; 126 127 /** 128 * The name under which the resource includes map is stored in the 129 * WikiContext. 130 */ 131 public static final String RESOURCE_INCLUDES = "jspwiki.resourceincludes"; 132 133 // private Cache m_propertyCache; 134 135 protected static final Logger log = Logger.getLogger(TemplateManager.class); 136 137 /** Requests a HTTP header. Value is {@value}. */ 138 public static final String RESOURCE_HTTPHEADER = "httpheader"; 139 140 /** 141 * Creates a new TemplateManager. There is typically one manager per engine. 142 * 143 * @param engine The owning engine. 144 * @param properties The property list used to initialize this. 145 */ 146 public TemplateManager( WikiEngine engine, Properties properties ) 147 { 148 super(engine); 149 150 // 151 // Uses the unlimited cache. 152 // 153 // m_propertyCache = new Cache( true, false ); 154 } 155 156 /** 157 * Check the existence of a template. 158 */ 159 // FIXME: Does not work yet 160 public boolean templateExists( String templateName ) 161 { 162 ServletContext context = m_engine.getServletContext(); 163 164 InputStream in = context.getResourceAsStream( getPath(templateName)+"ViewTemplate.jsp"); 165 166 if( in != null ) 167 { 168 try 169 { 170 in.close(); 171 } 172 catch (IOException e) 173 { 174 } 175 176 return true; 177 } 178 179 return false; 180 } 181 182 /** 183 * Tries to locate a given resource from the template directory. If the 184 * given resource is not found under the current name, returns the 185 * path to the corresponding one in the default template. 186 * 187 * @param sContext The servlet context 188 * @param name The name of the resource 189 * @return The name of the resource which was found. 190 */ 191 private static String findResource( ServletContext sContext, String name ) 192 { 193 InputStream is = sContext.getResourceAsStream( name ); 194 195 if( is == null ) 196 { 197 String defname = makeFullJSPName( DEFAULT_TEMPLATE, 198 removeTemplatePart(name) ); 199 is = sContext.getResourceAsStream( defname ); 200 201 if( is != null ) 202 name = defname; 203 else 204 name = null; 205 } 206 207 if( is != null ) 208 { 209 try 210 { 211 is.close(); 212 } 213 catch( IOException e ) 214 {} 215 } 216 217 return name; 218 } 219 220 /** 221 * Attempts to find a resource from the given template, and if it's not found 222 * attempts to locate it from the default template. 223 * @param sContext 224 * @param template 225 * @param name 226 * @return the Resource for the given template and name. 227 */ 228 private static String findResource( ServletContext sContext, String template, String name ) 229 { 230 if( name.charAt(0) == '/' ) 231 { 232 // This is already a full path 233 return findResource( sContext, name ); 234 } 235 236 String fullname = makeFullJSPName( template, name ); 237 238 return findResource( sContext, fullname ); 239 } 240 241 /** 242 * An utility method for finding a JSP page. It searches only under 243 * either current context or by the absolute name. 244 * 245 * @param pageContext the JSP PageContext 246 * @param name The name of the JSP page to look for (e.g "Wiki.jsp") 247 * @return The context path to the resource 248 */ 249 public String findJSP( PageContext pageContext, String name ) 250 { 251 ServletContext sContext = pageContext.getServletContext(); 252 253 return findResource( sContext, name ); 254 } 255 256 /** 257 * Removes the template part of a name. 258 */ 259 private static String removeTemplatePart( String name ) 260 { 261 int idx = 0; 262 if( name.startsWith( "/" ) ) idx = 1; 263 264 idx = name.indexOf('/', idx); 265 if( idx != -1 ) 266 { 267 idx = name.indexOf('/', idx+1); // Find second "/" 268 269 if( idx != -1 ) 270 { 271 name = name.substring( idx+1 ); 272 } 273 } 274 275 if( log.isDebugEnabled() ) log.debug( "Final name = "+name ); 276 return name; 277 } 278 279 /** 280 * Returns the full name (/templates/foo/bar) for name=bar, template=foo. 281 * 282 * @param template The name of the template. 283 * @param name The name of the resource. 284 * @return The full name for a template. 285 */ 286 private static String makeFullJSPName( String template, String name ) 287 { 288 return "/"+DIRECTORY+"/"+template+"/"+name; 289 } 290 291 /** 292 * Attempts to locate a resource under the given template. If that template 293 * does not exist, or the page does not exist under that template, will 294 * attempt to locate a similarly named file under the default template. 295 * <p> 296 * Even though the name suggests only JSP files can be located, but in fact 297 * this method can find also other resources than JSP files. 298 * 299 * @param pageContext The JSP PageContext 300 * @param template From which template we should seek initially? 301 * @param name Which resource are we looking for (e.g. "ViewTemplate.jsp") 302 * @return path to the JSP page; null, if it was not found. 303 */ 304 public String findJSP( PageContext pageContext, String template, String name ) 305 { 306 if( name == null || template == null ) 307 { 308 log.fatal("findJSP() was asked to find a null template or name ("+template+","+name+")."+ 309 " JSP page '"+ 310 ((HttpServletRequest)pageContext.getRequest()).getRequestURI()+"'"); 311 throw new InternalWikiException("Illegal arguments to findJSP(); please check logs."); 312 } 313 314 return findResource( pageContext.getServletContext(), template, name ); 315 } 316 317 /** 318 * Attempts to locate a resource under the given template. This matches the 319 * functionality findJSP(), but uses the WikiContext as the argument. If there 320 * is no servlet context (i.e. this is embedded), will just simply return 321 * a best-guess. 322 * <p> 323 * This method is typically used to locate any resource, including JSP pages, images, 324 * scripts, etc. 325 * 326 * @since 2.6 327 * @param ctx the wiki context 328 * @param template the name of the template to use 329 * @param name the name of the resource to fine 330 * @return the path to the resource 331 */ 332 public String findResource( WikiContext ctx, String template, String name ) 333 { 334 if( m_engine.getServletContext() != null ) 335 { 336 return findResource( m_engine.getServletContext(), template, name ); 337 } 338 339 return getPath(template)+"/"+name; 340 } 341 342 /** 343 * Returns a property, as defined in the template. The evaluation 344 * is lazy, i.e. the properties are not loaded until the template is 345 * actually used for the first time. 346 */ 347 /* 348 public String getTemplateProperty( WikiContext context, String key ) 349 { 350 String template = context.getTemplate(); 351 352 try 353 { 354 Properties props = (Properties)m_propertyCache.getFromCache( template, -1 ); 355 356 if( props == null ) 357 { 358 try 359 { 360 props = getTemplateProperties( template ); 361 362 m_propertyCache.putInCache( template, props ); 363 } 364 catch( IOException e ) 365 { 366 log.warn("IO Exception while reading template properties",e); 367 368 return null; 369 } 370 } 371 372 return props.getProperty( key ); 373 } 374 catch( NeedsRefreshException ex ) 375 { 376 // FIXME 377 return null; 378 } 379 } 380*/ 381 /** 382 * Returns an absolute path to a given template. 383 */ 384 private static String getPath( String template ) 385 { 386 return "/"+DIRECTORY+"/"+template+"/"; 387 } 388 389 /** 390 * Lists the skins available under this template. Returns an 391 * empty Set, if there are no extra skins available. Note that 392 * this method does not check whether there is anything actually 393 * in the directories, it just lists them. This may change 394 * in the future. 395 * 396 * @param pageContext the JSP PageContext 397 * @param template The template to search 398 * @return Set of Strings with the skin names. 399 * @since 2.3.26 400 */ 401 @SuppressWarnings("unchecked") 402 public Set listSkins( PageContext pageContext, String template ) 403 { 404 String place = makeFullJSPName( template, SKIN_DIRECTORY ); 405 406 ServletContext sContext = pageContext.getServletContext(); 407 408 Set<String> skinSet = sContext.getResourcePaths( place ); 409 TreeSet<String> resultSet = new TreeSet<String>(); 410 411 if( log.isDebugEnabled() ) log.debug( "Listings skins from "+place ); 412 413 if( skinSet != null ) 414 { 415 String[] skins = {}; 416 417 skins = skinSet.toArray(skins); 418 419 for (int i = 0; i < skins.length; i++) 420 { 421 String[] s = StringUtils.split(skins[i], "/"); 422 423 if (s.length > 2 && skins[i].endsWith("/")) 424 { 425 String skinName = s[s.length - 1]; 426 resultSet.add(skinName); 427 if (log.isDebugEnabled()) 428 log.debug("...adding skin '" + skinName + "'"); 429 } 430 } 431 } 432 433 return resultSet; 434 } 435 436 /** 437 * List all installed i18n language properties by classpath searching for files like : 438 * templates/default_*.properties 439 * templates/default.properties 440 * 441 * @param pageContext 442 * @return map of installed Languages 443 * @since 2.7.x 444 */ 445 public Map listLanguages(PageContext pageContext) 446 { 447 Map< String, String > resultMap = new LinkedHashMap< String, String >(); 448 String clientLanguage = ((HttpServletRequest) pageContext.getRequest()).getLocale().toString(); 449 450 List< String > entries = ClassUtil.classpathEntriesUnder( DIRECTORY ); 451 for( String name : entries ) { 452 if ( name.equals( I18NRESOURCE_EN ) || 453 (name.startsWith( I18NRESOURCE_PREFIX ) && name.endsWith( I18NRESOURCE_SUFFIX ) ) ) 454 { 455 if (name.equals( I18NRESOURCE_EN )) { 456 name = I18NRESOURCE_EN_ID; 457 } else { 458 name = name.substring(I18NRESOURCE_PREFIX.length(), name.lastIndexOf(I18NRESOURCE_SUFFIX)); 459 } 460 Locale locale = new Locale(name.substring(0, 2), ((name.indexOf("_") == -1) ? "" : name.substring(3, 5))); 461 String defaultLanguage = ""; 462 if (clientLanguage.startsWith(name)) 463 { 464 defaultLanguage = LocaleSupport.getLocalizedMessage(pageContext, I18NDEFAULT_LOCALE); 465 } 466 resultMap.put(name, locale.getDisplayName(locale) + " " + defaultLanguage); 467 } 468 } 469 470 return resultMap; 471 } 472 473 474 /** 475 * List all available timeformats, read from the jspwiki.properties 476 * 477 * @param pageContext 478 * @return map of TimeFormats 479 * @since 2.7.x 480 */ 481 public Map listTimeFormats(PageContext pageContext) 482 { 483 WikiContext context = WikiContext.findContext( pageContext ); 484 Properties props = m_engine.getWikiProperties(); 485 ArrayList<String> tfArr = new ArrayList<String>(40); 486 LinkedHashMap<String,String> resultMap = new LinkedHashMap<String,String>(); 487 488 /* filter timeformat properties */ 489 for (Enumeration e = props.propertyNames(); e.hasMoreElements();) 490 { 491 String name = (String) e.nextElement(); 492 493 if (name.startsWith(TIMEFORMATPROPERTIES)) 494 { 495 tfArr.add(name); 496 } 497 } 498 499 /* fetch actual formats */ 500 if (tfArr.size() == 0) /* 501 * no props found - make sure some default 502 * formats are avail 503 */ 504 { 505 tfArr.add("dd-MMM-yy"); 506 tfArr.add("d-MMM-yyyy"); 507 tfArr.add("EEE, dd-MMM-yyyy, zzzz"); 508 } 509 else 510 { 511 Collections.sort(tfArr); 512 513 for (int i = 0; i < tfArr.size(); i++) 514 { 515 tfArr.set(i, props.getProperty(tfArr.get(i))); 516 } 517 } 518 519 String prefTimeZone = Preferences.getPreference( context, "TimeZone" ); 520 //TimeZone tz = TimeZone.getDefault(); 521 TimeZone tz = TimeZone.getTimeZone(prefTimeZone); 522 /*try 523 { 524 tz.setRawOffset(Integer.parseInt(prefTimeZone)); 525 } 526 catch (Exception e) 527 { 528 }*/ 529 530 Date d = new Date(); // current date 531 try 532 { 533 // dummy format pattern 534 SimpleDateFormat fmt = Preferences.getDateFormat( context, TimeFormat.DATETIME ); 535 fmt.setTimeZone(tz); 536 537 for (int i = 0; i < tfArr.size(); i++) 538 { 539 try 540 { 541 String f = tfArr.get(i); 542 fmt.applyPattern(f); 543 544 resultMap.put(f, fmt.format(d)); 545 } 546 catch (IllegalArgumentException e) 547 { 548 } // skip parameter 549 } 550 } 551 catch (IllegalArgumentException e) 552 { 553 } // skip parameter 554 555 return resultMap; 556 } 557 558 /** 559 * List all timezones, with special marker for server timezone 560 * 561 * @param pageContext 562 * @return map of TimeZones 563 * @since 2.7.x 564 */ 565 public Map listTimeZones(PageContext pageContext) 566 { 567 LinkedHashMap<String,String> resultMap = new LinkedHashMap<String,String>(); 568 569 String[][] tzs = { { "GMT-12", "Enitwetok, Kwajalien" }, 570 { "GMT-11", "Nome, Midway Island, Samoa" }, 571 { "GMT-10", "Hawaii" }, 572 { "GMT-9", "Alaska" }, 573 { "GMT-8", "Pacific Time" }, 574 { "GMT-7", "Mountain Time" }, 575 { "GMT-6", "Central Time, Mexico City" }, 576 { "GMT-5", "Eastern Time, Bogota, Lima, Quito" }, 577 { "GMT-4", "Atlantic Time, Caracas, La Paz" }, 578 { "GMT-3:30", "Newfoundland" }, 579 { "GMT-3", "Brazil, Buenos Aires, Georgetown, Falkland Is." }, 580 { "GMT-2", "Mid-Atlantic, Ascention Is., St Helena" }, 581 { "GMT-1", "Azores, Cape Verde Islands" }, 582 { "GMT", "Casablanca, Dublin, Edinburgh, London, Lisbon, Monrovia" }, 583 { "GMT+1", "Berlin, Brussels, Copenhagen, Madrid, Paris, Rome" }, 584 { "GMT+2", "Helsinki, Athens, Kaliningrad, South Africa, Warsaw" }, 585 { "GMT+3", "Baghdad, Riyadh, Moscow, Nairobi" }, 586 { "GMT+3:30", "Tehran" }, 587 { "GMT+4", "Adu Dhabi, Baku, Muscat, Tbilisi" }, 588 { "GMT+4:30", "Kabul" }, 589 { "GMT+5", "Islamabad, Karachi, Tashkent" }, 590 { "GMT+5:30", "Bombay, Calcutta, Madras, New Delhi" }, 591 { "GMT+6", "Almaty, Colomba, Dhakra" }, 592 { "GMT+7", "Bangkok, Hanoi, Jakarta" }, 593 { "GMT+8", "Beijing, Hong Kong, Perth, Singapore, Taipei" }, 594 { "GMT+9", "Osaka, Sapporo, Seoul, Tokyo, Yakutsk" }, 595 { "GMT+9:30", "Adelaide, Darwin" }, 596 { "GMT+10", "Melbourne, Papua New Guinea, Sydney, Vladivostok" }, 597 { "GMT+11", "Magadan, New Caledonia, Solomon Islands" }, 598 { "GMT+12", "Auckland, Wellington, Fiji, Marshall Island" } }; 599 600 java.util.TimeZone servertz = java.util.TimeZone.getDefault(); 601 602 for( int i = 0; i < tzs.length; i++ ) 603 { 604 String tzID = tzs[i][0]; 605 java.util.TimeZone tz = java.util.TimeZone.getTimeZone(tzID); 606 607 String serverTimeZone = ""; 608 609 if( servertz.getRawOffset() == tz.getRawOffset() ) 610 { 611 serverTimeZone = LocaleSupport.getLocalizedMessage(pageContext, I18NSERVER_TIMEZONE); 612 tzID = servertz.getID(); 613 } 614 615 resultMap.put(tzID, "(" + tzs[i][0] + ") "+tzs[i][1] + " " + serverTimeZone); 616 } 617 618 return resultMap; 619 } 620 621 /** 622 * Always returns a valid property map. 623 */ 624 /* 625 private Properties getTemplateProperties( String templateName ) 626 throws IOException 627 { 628 Properties p = new Properties(); 629 630 ServletContext context = m_engine.getServletContext(); 631 632 InputStream propertyStream = context.getResourceAsStream(getPath(templateName)+PROPERTYFILE); 633 634 if( propertyStream != null ) 635 { 636 p.load( propertyStream ); 637 638 propertyStream.close(); 639 } 640 else 641 { 642 log.debug("Template '"+templateName+"' does not have a propertyfile '"+PROPERTYFILE+"'."); 643 } 644 645 return p; 646 } 647*/ 648 /** 649 * Returns the include resources marker for a given type. This is in a 650 * HTML or Javascript comment format. 651 * 652 * @param context the wiki context 653 * @param type the marker 654 * @return the generated marker comment 655 */ 656 public static String getMarker(WikiContext context, String type ) 657 { 658 if( type.equals(RESOURCE_JSLOCALIZEDSTRINGS) ) 659 { 660 return getJSLocalizedStrings( context ); 661 } 662 else if( type.equals(RESOURCE_JSFUNCTION) ) 663 { 664 return "/* INCLUDERESOURCES ("+type+") */"; 665 } 666 return "<!-- INCLUDERESOURCES ("+type+") -->"; 667 } 668 669 /** 670 * Extract all i18n strings in the javascript domain. (javascript.*) 671 * Returns a javascript snippet which defines the LocalizedStings array. 672 * 673 * @param context the {@link WikiContext} 674 * @return Javascript snippet which defines the LocalizedStrings array 675 * @since 2.5.108 676 */ 677 private static String getJSLocalizedStrings( WikiContext context ) 678 { 679 StringBuilder sb = new StringBuilder(); 680 681 sb.append( "var LocalizedStrings = {\n"); 682 683 ResourceBundle rb = Preferences.getBundle( context, InternationalizationManager.DEF_TEMPLATE ); 684 685 boolean first = true; 686 687 for( Enumeration< String > en = rb.getKeys(); en.hasMoreElements(); ) 688 { 689 String key = en.nextElement(); 690 691 if( key.startsWith("javascript") ) 692 { 693 if( first ) 694 { 695 first = false; 696 } 697 else 698 { 699 sb.append( ",\n" ); 700 } 701 sb.append( "\""+key+"\":\""+rb.getString(key)+"\"" ); 702 } 703 } 704 sb.append("\n};\n"); 705 706 return( sb.toString() ); 707 } 708 709 /** 710 * Adds a resource request to the current request context. 711 * The content will be added at the resource-type marker 712 * (see IncludeResourcesTag) in WikiJSPFilter. 713 * <p> 714 * The resources can be of different types. For RESOURCE_SCRIPT and RESOURCE_STYLESHEET 715 * this is an URI path to the resource (a script file or an external stylesheet) 716 * that needs to be included. For RESOURCE_INLINECSS 717 * the resource should be something that can be added between <style></style> in the 718 * header file (commonheader.jsp). For RESOURCE_JSFUNCTION it is the name of the Javascript 719 * function that should be run at page load. 720 * <p> 721 * The IncludeResourceTag inserts code in the template files, which is then filled 722 * by the WikiFilter after the request has been rendered but not yet sent to the recipient. 723 * <p> 724 * Note that ALL resource requests get rendered, so this method does not check if 725 * the request already exists in the resources. Therefore, if you have a plugin which 726 * makes a new resource request every time, you'll end up with multiple resource requests 727 * rendered. It's thus a good idea to make this request only once during the page 728 * life cycle. 729 * 730 * @param ctx The current wiki context 731 * @param type What kind of a request should be added? 732 * @param resource The resource to add. 733 */ 734 @SuppressWarnings("unchecked") 735 public static void addResourceRequest( WikiContext ctx, String type, String resource ) 736 { 737 HashMap<String,Vector<String>> resourcemap = (HashMap<String,Vector<String>>) ctx.getVariable( RESOURCE_INCLUDES ); 738 739 if( resourcemap == null ) 740 { 741 resourcemap = new HashMap<String,Vector<String>>(); 742 } 743 744 Vector<String> resources = resourcemap.get( type ); 745 746 if( resources == null ) 747 { 748 resources = new Vector<String>(); 749 } 750 751 String resourceString = null; 752 753 if( type.equals(RESOURCE_SCRIPT) ) 754 { 755 resourceString = "<script type='text/javascript' src='"+resource+"'></script>"; 756 } 757 else if( type.equals(RESOURCE_STYLESHEET) ) 758 { 759 resourceString = "<link rel='stylesheet' type='text/css' href='"+resource+"' />"; 760 } 761 else if( type.equals(RESOURCE_INLINECSS) ) 762 { 763 resourceString = "<style type='text/css'>\n"+resource+"\n</style>\n"; 764 } 765 else if( type.equals(RESOURCE_JSFUNCTION) ) 766 { 767 resourceString = resource; 768 } 769 else if( type.equals(RESOURCE_HTTPHEADER) ) 770 { 771 resourceString = resource; 772 } 773 774 if( resourceString != null ) 775 { 776 resources.add( resourceString ); 777 } 778 779 log.debug("Request to add a resource: "+resourceString); 780 781 resourcemap.put( type, resources ); 782 ctx.setVariable( RESOURCE_INCLUDES, resourcemap ); 783 } 784 785 /** 786 * Returns resource requests for a particular type. If there are no resources, 787 * returns an empty array. 788 * 789 * @param ctx WikiContext 790 * @param type The resource request type 791 * @return a String array for the resource requests 792 */ 793 794 @SuppressWarnings("unchecked") 795 public static String[] getResourceRequests( WikiContext ctx, String type ) 796 { 797 HashMap<String,Vector<String>> hm = (HashMap<String,Vector<String>>) ctx.getVariable( RESOURCE_INCLUDES ); 798 799 if( hm == null ) return new String[0]; 800 801 Vector<String> resources = hm.get( type ); 802 803 if( resources == null ) return new String[0]; 804 805 String[] res = new String[resources.size()]; 806 807 return resources.toArray( res ); 808 } 809 810 /** 811 * Returns all those types that have been requested so far. 812 * 813 * @param ctx the wiki context 814 * @return the array of types requested 815 */ 816 @SuppressWarnings("unchecked") 817 public static String[] getResourceTypes( WikiContext ctx ) 818 { 819 String[] res = new String[0]; 820 821 if( ctx != null ) 822 { 823 HashMap<String,String> hm = (HashMap<String,String>) ctx.getVariable( RESOURCE_INCLUDES ); 824 825 if( hm != null ) 826 { 827 Set<String> keys = hm.keySet(); 828 829 res = keys.toArray( res ); 830 } 831 } 832 833 return res; 834 } 835 836 /** 837 * Returns an empty collection, since at the moment the TemplateManager 838 * does not manage any modules. 839 * 840 * @return {@inheritDoc} 841 */ 842 @Override 843 public Collection modules() 844 { 845 return new ArrayList(); 846 } 847 848 /** 849 * Returns null! 850 * {@inheritDoc} 851 */ 852 @Override 853 public WikiModuleInfo getModuleInfo(String moduleName) { 854 return null; 855 } 856}