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