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 }