1 package org.springframework.richclient.jnlp; 2 3 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 4 5 import javax.jnlp.BasicService; 6 import javax.jnlp.ServiceManager; 7 import javax.jnlp.UnavailableServiceException; 8 import java.util.Properties; 9 10 /** 11 * Subclass of PropertyPlaceholderConfigurer that resolves the following properties as placeholders: 12 * <ul> 13 * <li><code>jnlp.webAppContextUrl</code> the webAppContextUrl, for example 14 * http://domain.com/petclinic/</li> 15 * </ul> 16 * <p/> 17 * <p>Can be combined with "locations" and/or "properties" values. 18 * <p/> 19 * <p>If a placeholder could not be resolved against the provided local 20 * properties within the application, this configurer will fall back to 21 * the JNLP properties. Can also be configured to let jnlp properties 22 * override local properties (contextOverride=true). 23 * <p/> 24 * <p>If not running within a JNLP context (or any other context that 25 * is able to satisfy the BasicService.lookup call), this class will 26 * use the fallBackWebAppContextUrl. This allows for keeping 27 * JnlpPropertyPlaceholderConfigurer definitions in test suites. 28 * <p/> 29 * <p> A typical usage would be: 30 * <pre> 31 * <bean id="jnlpPropertyPlaceholderConfigurer" 32 * class="be.kahosl.thot.swingui.util.JnlpPropertyPlaceholderConfigurer"> 33 * <property name="fallBackWebAppContextUrl" value="http://localhost:8080/mywebapp/"/> 34 * <property name="jnlpRelativeDirectoryPathFromWebAppContext" value="/jnlp/"/> 35 * </bean> 36 * </pre> 37 * <p/> 38 * Use this in combination with Sun's JnlpDownloadServlet to not have to hardcode your server URL: 39 * http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/downloadservletguide.html 40 * 41 * @author Geoffrey De Smet 42 * @see #setLocations 43 * @see #setProperties 44 * @see #setSystemPropertiesModeName 45 * @see #setContextOverride 46 * @see javax.jnlp.BasicService#getCodeBase() 47 */ 48 public class JnlpPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { 49 50 /** 51 * The placeholder for getWebAppContextUrl() 52 */ 53 public static final String WEB_APP_CONTEXT_URL_PLACEHOLDER = "jnlp.webAppContextUrl"; 54 55 private boolean contextOverride = false; 56 private String fallBackWebAppContextUrl = "http://localhost:8080/"; 57 private String jnlpRelativeDirectoryPathFromWebAppContext = "/"; 58 59 /** 60 * Set whether the JNLP properties should override local properties within the application. 61 * Default is "false": JNLP properties settings serve as fallback. 62 * <p>Note that system properties will still override JNLP properties, 63 * if the system properties mode is set to "SYSTEM_PROPERTIES_MODE_OVERRIDE". 64 * 65 * @see #setSystemPropertiesModeName 66 * @see #SYSTEM_PROPERTIES_MODE_OVERRIDE 67 */ 68 public void setContextOverride(boolean contextOverride) { 69 this.contextOverride = contextOverride; 70 } 71 72 /** 73 * Set the webAppContextUrl to use when no javax.jnlp.BasicService is available. 74 * This is usefull for testing outside JNLP (Java webstart). 75 * This defaults to <code>http://localhost:8080/</code>. 76 * Ussually you 'll want to set this to <code>http://localhost:8080/mywebapp/</code>. 77 * 78 * @param fallBackWebAppContextUrl the webAppContextUrl to fall back on ending with a slash 79 */ 80 public void setFallBackWebAppContextUrl(String fallBackWebAppContextUrl) { 81 this.fallBackWebAppContextUrl = fallBackWebAppContextUrl; 82 } 83 84 /** 85 * Sets the relative directory path of the JNLP file relative to the WebAppContext. 86 * Default this is <code>/</code>, which means that the JNLP file is in the root of your webapp. 87 * If your JNLP file isn't in the root of you webapp, change it. 88 * For example for <code>http://localhost:8080/mywebapp/dist/jnlp/myswingapp.jnlp</code> 89 * you would set this to <code>/dist/jnlp/</code>. 90 * 91 * @param jnlpRelativeDirectoryPathFromWebAppContext 92 * the relative directory path starting and ending with a slash 93 */ 94 public void setJnlpRelativeDirectoryPathFromWebAppContext(String jnlpRelativeDirectoryPathFromWebAppContext) { 95 this.jnlpRelativeDirectoryPathFromWebAppContext = jnlpRelativeDirectoryPathFromWebAppContext; 96 } 97 98 protected String resolvePlaceholder(String placeholder, Properties props) { 99 String value = null; 100 if (this.contextOverride) { 101 value = resolvePlaceholder(placeholder); 102 } 103 if (value == null) { 104 value = super.resolvePlaceholder(placeholder, props); 105 } 106 if (value == null) { 107 value = resolvePlaceholder(placeholder); 108 } 109 return value; 110 } 111 112 /** 113 * Resolves the given placeholder using the jnlp properties. 114 * 115 * @param placeholder the placeholder to resolve 116 * @return the resolved value, of null if none 117 */ 118 protected String resolvePlaceholder(String placeholder) { 119 String value = null; 120 if (placeholder.equals(WEB_APP_CONTEXT_URL_PLACEHOLDER)) { 121 value = getWebAppContextUrl(); 122 } 123 return value; 124 } 125 126 /** 127 * Uses the jnlp API to determine the webapp context. 128 * If used outside of webstart, <code>fallBackWebAppContextUrl</code> is returned. 129 * For example this could return <code>http://localhost:8080/mywebapp/</code>. 130 * 131 * @return the url to the webapp ending with a slash 132 */ 133 public String getWebAppContextUrl() { 134 String webAppContextUrl; 135 try { 136 BasicService basicService = (BasicService) ServiceManager.lookup("javax.jnlp.BasicService"); 137 String codeBase = basicService.getCodeBase().toExternalForm(); 138 if (!codeBase.endsWith("/")) { 139 codeBase += "/"; 140 } 141 int webAppContextUrlLength = codeBase.lastIndexOf(jnlpRelativeDirectoryPathFromWebAppContext); 142 webAppContextUrl = codeBase.substring(0, webAppContextUrlLength + 1); 143 } catch (UnavailableServiceException e) { 144 // TODO logging 145 webAppContextUrl = fallBackWebAppContextUrl; 146 } 147 return webAppContextUrl; 148 } 149 150 }