1 package org.apache.velocity.tools.view; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.util.Locale; 23 import java.util.Map; 24 import javax.servlet.ServletContext; 25 import org.apache.velocity.app.VelocityEngine; 26 import org.apache.velocity.exception.ResourceNotFoundException; 27 import org.apache.velocity.tools.Scope; 28 import org.apache.velocity.tools.config.DefaultKey; 29 import org.apache.velocity.tools.config.InvalidScope; 30 import org.apache.velocity.tools.view.ViewToolContext; 31 32 /** 33 * Allows for transparent content negotiation in a manner mimicking 34 * Apache httpd's <a 35 * href="http://httpd.apache.org/docs-2.0/content-negotiation.html">MultiViews</a>. 36 * 37 * <p>Reads the default language out of the ViewToolContext as 38 * <code>org.apache.velocity.tools.view.i18n.defaultLanguage</code>. 39 * See {@link #find(String, String)}, {@link 40 * #find(String, Locale)} and {@link #exists(String)} for usage.</p> 41 * 42 * <p>This is the successor to the MultiViewsTool in VelocityTools 1.x. 43 * Please note that it does NOT do the actual #include or #parse for 44 * you, but is merely to aid in include content negotiation.</p> 45 * 46 * @version $Id: IncludeTool.java 730292 2008-12-31 01:31:09Z nbubna $ 47 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> 48 * @author Nathan Bubna 49 * @since VelocityTools 2.0 50 */ 51 @DefaultKey("include") 52 @InvalidScope(Scope.APPLICATION) 53 public class IncludeTool 54 { 55 /** 56 * The key used to search initialization, context, and JVM 57 * parameters for the default language to use. 58 */ 59 protected static final String DEFAULT_LANGUAGE_KEY = 60 "org.apache.velocity.tools.view.i18n.defaultLanguage"; 61 62 /** 63 * The two character abbreviation for the request's default 64 * language. 65 */ 66 protected String defaultLanguage; 67 protected VelocityEngine engine; 68 69 /** 70 * Extracts the default language from the specified 71 * <code>ViewContext</code>, looking first at the Velocity 72 * context, then the servlet context, then lastly at the JVM 73 * default. This "narrow scope to wide scope" pattern makes it 74 * easy to setup language overrides at different levels within 75 * your application. 76 * 77 * @param params the {@link Map} of configuration parameters 78 * @throws IllegalArgumentException if the param is not a ViewContext 79 */ 80 public void configure(Map params) 81 { 82 configure((ViewToolContext)params.get(ViewToolContext.CONTEXT_KEY)); 83 } 84 85 protected void configure(ViewToolContext ctx) 86 { 87 defaultLanguage = (String) ctx.get(DEFAULT_LANGUAGE_KEY); 88 if (defaultLanguage == null || defaultLanguage.trim().equals("")) 89 { 90 ServletContext sc = ctx.getServletContext(); 91 defaultLanguage = (String) sc.getAttribute(DEFAULT_LANGUAGE_KEY); 92 if (defaultLanguage == null || defaultLanguage.trim().equals("")) 93 { 94 // Use JVM default. 95 defaultLanguage = Locale.getDefault().getLanguage(); 96 } 97 } 98 99 this.engine = ctx.getVelocityEngine(); 100 } 101 102 /** 103 * Calls {@link #find(String, String)} using the 104 * language extracted from <code>locale</code>. 105 * 106 * @see #find(String, String) 107 */ 108 public String find(String name, Locale locale) 109 { 110 if (locale == null) 111 { 112 return null; 113 } 114 return find(name, locale.getLanguage()); 115 } 116 117 /** 118 * Calls {@link #find(String, String)} using the 119 * default language. 120 * 121 * @see #find(String, String) 122 */ 123 public String find(String name) 124 { 125 return find(name, defaultLanguage); 126 } 127 128 /** 129 * <p>Finds the a localized version of the requested Velocity 130 * resource (such as a file or template) which is most appropriate 131 * for the locale of the current request. Use in conjuction with 132 * Apache httpd's <code>MultiViews</code>, or by itself.</p> 133 * 134 * <p>Usage from a template would be something like the following: 135 * <blockquote><code><pre> 136 * #parse( $include.find('header.vm', 'en') ) 137 * #include( $include.find('my_page.html', 'en') ) 138 * #parse( $include.find('footer.vm', 'en') ) 139 * </pre></code></blockquote> 140 * 141 * You might also wrap this method using another pull/view tool 142 * which does internationalization/localization/content negation 143 * for a single point of access.</p> 144 * 145 * @param name The unlocalized name of the file to find. 146 * @param language The language to find localized context for. 147 * @return The localized file name, or <code>name</code> if it is 148 * not localizable. 149 */ 150 public String find(String name, String language) 151 { 152 String localizedName = name + '.' + language; 153 if (!exists(localizedName)) 154 { 155 // Fall back to the default lanaguage. 156 String defaultLangSuffix = '.' + defaultLanguage; 157 if (localizedName.endsWith(defaultLangSuffix)) 158 { 159 // Assume no localized version of the resource. 160 localizedName = name; 161 } 162 else 163 { 164 localizedName = name + defaultLangSuffix; 165 if (!exists(localizedName)) 166 { 167 localizedName = name; 168 } 169 } 170 } 171 return localizedName; 172 } 173 174 /** 175 * <p>Checks to see whether a #parse-able template or 176 * #include-able resource exists under the specified name/path.</p> 177 * 178 * <p>Usage from a template would be something like the following: 179 * <blockquote><code><pre> 180 * #if( $include.exists('header.vm') ) 181 * #parse( 'header.vm' ) 182 * #end 183 * </pre></code></blockquote> 184 * 185 * @see VelocityEngine#resourceExists 186 */ 187 public boolean exists(String name) 188 { 189 try 190 { 191 // checks for both templates and static content 192 return engine.resourceExists(name); 193 } 194 // make sure about this... 195 catch (ResourceNotFoundException rnfe) 196 { 197 return false; 198 } 199 } 200 201 /** 202 * Checks to see whether a localized version of the 203 * named template exists for the specified language. 204 * 205 * @see #exists(String) 206 */ 207 public boolean exists(String name, String language) 208 { 209 String localizedName = name + '.' + language; 210 return exists(localizedName); 211 } 212 213 }