001 package org.springframework.richclient.jnlp; 002 003 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 004 005 import javax.jnlp.BasicService; 006 import javax.jnlp.ServiceManager; 007 import javax.jnlp.UnavailableServiceException; 008 import java.util.Properties; 009 010 /** 011 * Subclass of PropertyPlaceholderConfigurer that resolves the following properties as placeholders: 012 * <ul> 013 * <li><code>jnlp.webAppContextUrl</code> the webAppContextUrl, for example 014 * http://domain.com/petclinic/</li> 015 * </ul> 016 * <p/> 017 * <p>Can be combined with "locations" and/or "properties" values. 018 * <p/> 019 * <p>If a placeholder could not be resolved against the provided local 020 * properties within the application, this configurer will fall back to 021 * the JNLP properties. Can also be configured to let jnlp properties 022 * override local properties (contextOverride=true). 023 * <p/> 024 * <p>If not running within a JNLP context (or any other context that 025 * is able to satisfy the BasicService.lookup call), this class will 026 * use the fallBackWebAppContextUrl. This allows for keeping 027 * JnlpPropertyPlaceholderConfigurer definitions in test suites. 028 * <p/> 029 * <p> A typical usage would be: 030 * <pre> 031 * <bean id="jnlpPropertyPlaceholderConfigurer" 032 * class="be.kahosl.thot.swingui.util.JnlpPropertyPlaceholderConfigurer"> 033 * <property name="fallBackWebAppContextUrl" value="http://localhost:8080/mywebapp/"/> 034 * <property name="jnlpRelativeDirectoryPathFromWebAppContext" value="/jnlp/"/> 035 * </bean> 036 * </pre> 037 * <p/> 038 * Use this in combination with Sun's JnlpDownloadServlet to not have to hardcode your server URL: 039 * http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/downloadservletguide.html 040 * 041 * @author Geoffrey De Smet 042 * @see #setLocations 043 * @see #setProperties 044 * @see #setSystemPropertiesModeName 045 * @see #setContextOverride 046 * @see javax.jnlp.BasicService#getCodeBase() 047 */ 048 public class JnlpPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { 049 050 /** 051 * The placeholder for getWebAppContextUrl() 052 */ 053 public static final String WEB_APP_CONTEXT_URL_PLACEHOLDER = "jnlp.webAppContextUrl"; 054 055 private boolean contextOverride = false; 056 private String fallBackWebAppContextUrl = "http://localhost:8080/"; 057 private String jnlpRelativeDirectoryPathFromWebAppContext = "/"; 058 059 /** 060 * Set whether the JNLP properties should override local properties within the application. 061 * Default is "false": JNLP properties settings serve as fallback. 062 * <p>Note that system properties will still override JNLP properties, 063 * if the system properties mode is set to "SYSTEM_PROPERTIES_MODE_OVERRIDE". 064 * 065 * @see #setSystemPropertiesModeName 066 * @see #SYSTEM_PROPERTIES_MODE_OVERRIDE 067 */ 068 public void setContextOverride(boolean contextOverride) { 069 this.contextOverride = contextOverride; 070 } 071 072 /** 073 * Set the webAppContextUrl to use when no javax.jnlp.BasicService is available. 074 * This is usefull for testing outside JNLP (Java webstart). 075 * This defaults to <code>http://localhost:8080/</code>. 076 * Ussually you 'll want to set this to <code>http://localhost:8080/mywebapp/</code>. 077 * 078 * @param fallBackWebAppContextUrl the webAppContextUrl to fall back on ending with a slash 079 */ 080 public void setFallBackWebAppContextUrl(String fallBackWebAppContextUrl) { 081 this.fallBackWebAppContextUrl = fallBackWebAppContextUrl; 082 } 083 084 /** 085 * Sets the relative directory path of the JNLP file relative to the WebAppContext. 086 * Default this is <code>/</code>, which means that the JNLP file is in the root of your webapp. 087 * If your JNLP file isn't in the root of you webapp, change it. 088 * For example for <code>http://localhost:8080/mywebapp/dist/jnlp/myswingapp.jnlp</code> 089 * you would set this to <code>/dist/jnlp/</code>. 090 * 091 * @param jnlpRelativeDirectoryPathFromWebAppContext 092 * the relative directory path starting and ending with a slash 093 */ 094 public void setJnlpRelativeDirectoryPathFromWebAppContext(String jnlpRelativeDirectoryPathFromWebAppContext) { 095 this.jnlpRelativeDirectoryPathFromWebAppContext = jnlpRelativeDirectoryPathFromWebAppContext; 096 } 097 098 protected String resolvePlaceholder(String placeholder, Properties props) { 099 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 }