From ff286264e4472a62188ac3b0c4a1fb60c7faae44 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 23 Nov 2014 14:01:05 -0800 Subject: [PATCH] GUAC-340: Add Environment and LocalEnvironment, collectively replacing GuacamoleHome and GuacamoleProperties. Mark GuacamoleHome and GuacamoleProperties as deprecated. Remove use of deprecated classes within guacamole-ext. --- .../guacamole/environment/Environment.java | 134 ++++++++++++++ .../environment/LocalEnvironment.java | 164 ++++++++++++++++++ .../net/auth/simple/SimpleConnection.java | 11 +- .../guacamole/properties/GuacamoleHome.java | 13 ++ .../properties/GuacamoleProperties.java | 13 ++ 5 files changed, 331 insertions(+), 4 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/Environment.java create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/LocalEnvironment.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/Environment.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/Environment.java new file mode 100644 index 000000000..8805c5173 --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/Environment.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.environment; + +import java.io.File; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.properties.BooleanGuacamoleProperty; +import org.glyptodon.guacamole.properties.GuacamoleProperty; +import org.glyptodon.guacamole.properties.IntegerGuacamoleProperty; +import org.glyptodon.guacamole.properties.StringGuacamoleProperty; + +/** + * The environment of an arbitrary Guacamole instance, describing available + * protocols, configuration parameters, and the GUACAMOLE_HOME directory. + * + * @author Michael Jumper + */ +public interface Environment { + + /** + * The hostname of the server where guacd (the Guacamole proxy server) is + * running. + */ + public static final StringGuacamoleProperty GUACD_HOSTNAME = new StringGuacamoleProperty() { + + @Override + public String getName() { return "guacd-hostname"; } + + }; + + /** + * The port that guacd (the Guacamole proxy server) is listening on. + */ + public static final IntegerGuacamoleProperty GUACD_PORT = new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "guacd-port"; } + + }; + + /** + * Whether guacd requires SSL/TLS on connections. + */ + public static final BooleanGuacamoleProperty GUACD_SSL = new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "guacd-ssl"; } + + }; + + /** + * Returns the Guacamole home directory as determined when this Environment + * object was created. The Guacamole home directory is found by checking, in + * order: the guacamole.home system property, the GUACAMOLE_HOME environment + * variable, and finally the .guacamole directory in the home directory of + * the user running the servlet container. + * + * @return The File representing the Guacamole home directory, which may + * or may not exist, and may turn out to not be a directory. + */ + public File getGuacamoleHome(); + + /** + * Given a GuacamoleProperty, parses and returns the value set for that + * property in guacamole.properties, if any. + * + * @param The type that the given property is parsed into. + * @param property The property to read from guacamole.properties. + * @return The parsed value of the property as read from + * guacamole.properties. + * @throws GuacamoleException If an error occurs while parsing the value + * for the given property in + * guacamole.properties. + */ + public Type getProperty(GuacamoleProperty property) + throws GuacamoleException; + + /** + * Given a GuacamoleProperty, parses and returns the value set for that + * property in guacamole.properties, if any. If no value is found, the + * provided default value is returned. + * + * @param The type that the given property is parsed into. + * @param property The property to read from guacamole.properties. + * @param defaultValue The value to return if no value was given in + * guacamole.properties. + * @return The parsed value of the property as read from + * guacamole.properties, or the provided default value if no value + * was found. + * @throws GuacamoleException If an error occurs while parsing the value + * for the given property in + * guacamole.properties. + */ + public Type getProperty(GuacamoleProperty property, + Type defaultValue) throws GuacamoleException; + + /** + * Given a GuacamoleProperty, parses and returns the value set for that + * property in guacamole.properties. An exception is thrown if the value + * is not provided. + * + * @param The type that the given property is parsed into. + * @param property The property to read from guacamole.properties. + * @return The parsed value of the property as read from + * guacamole.properties. + * @throws GuacamoleException If an error occurs while parsing the value + * for the given property in + * guacamole.properties, or if the property is + * not specified. + */ + public Type getRequiredProperty(GuacamoleProperty property) + throws GuacamoleException; + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/LocalEnvironment.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/LocalEnvironment.java new file mode 100644 index 000000000..0fe2880dc --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/environment/LocalEnvironment.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.environment; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleServerException; +import org.glyptodon.guacamole.properties.GuacamoleProperty; + +/** + * The environment of the locally-running Guacamole instance, describing + * available protocols, configuration parameters, and the GUACAMOLE_HOME + * directory. + * + * @author Michael Jumper + */ +public class LocalEnvironment implements Environment { + + /** + * All properties read from guacamole.properties. + */ + private final Properties properties; + + /** + * The location of GUACAMOLE_HOME, which may not truly exist. + */ + private final File guacHome; + + /** + * Creates a new Environment, initializing that environment based on the + * location of GUACAMOLE_HOME and the contents of guacamole.properties. + * + * @throws GuacamoleException If an error occurs while determining the + * environment of this Guacamole instance. + */ + public LocalEnvironment() throws GuacamoleException { + + properties = new Properties(); + guacHome = findGuacamoleHome(); + + try { + + InputStream stream; + + // If not a directory, load from classpath + if (!guacHome.isDirectory()) { + + // Read from classpath + stream = LocalEnvironment.class.getResourceAsStream("/guacamole.properties"); + if (stream == null) + throw new GuacamoleServerException( + "guacamole.properties not loaded from " + guacHome + + " (not a directory), and guacamole.properties could" + + " not be found as a resource in the classpath."); + + } + + // Otherwise, try to load from file + else + stream = new FileInputStream(new File(guacHome, "guacamole.properties")); + + // Load properties, always close stream + try { properties.load(stream); } + finally { stream.close(); } + + } + catch (IOException e) { + throw new GuacamoleServerException("Error reading guacamole.properties", e); + } + + } + + /** + * Locates the Guacamole home directory by checking, in order: + * the guacamole.home system property, the GUACAMOLE_HOME environment + * variable, and finally the .guacamole directory in the home directory of + * the user running the servlet container. + * + * @return The File representing the Guacamole home directory, which may + * or may not exist, and may turn out to not be a directory. + */ + private static File findGuacamoleHome() { + + // Attempt to find Guacamole home + File guacHome; + + // Use system property by default + String desiredDir = System.getProperty("guacamole.home"); + + // Failing that, try the GUACAMOLE_HOME environment variable + if (desiredDir == null) desiredDir = System.getenv("GUACAMOLE_HOME"); + + // If successful, use explicitly specified directory + if (desiredDir != null) + guacHome = new File(desiredDir); + + // If not explicitly specified, use ~/.guacamole + else + guacHome = new File(System.getProperty("user.home"), ".guacamole"); + + // Return discovered directory + return guacHome; + + } + + @Override + public File getGuacamoleHome() { + return guacHome; + } + + @Override + public Type getProperty(GuacamoleProperty property) throws GuacamoleException { + return property.parseValue(properties.getProperty(property.getName())); + } + + @Override + public Type getProperty(GuacamoleProperty property, + Type defaultValue) throws GuacamoleException { + + Type value = getProperty(property); + if (value == null) + return defaultValue; + + return value; + + } + + @Override + public Type getRequiredProperty(GuacamoleProperty property) + throws GuacamoleException { + + Type value = getProperty(property); + if (value == null) + throw new GuacamoleServerException("Property " + property.getName() + " is required."); + + return value; + + } + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java index b8f1fd327..5065ef5d7 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java @@ -25,12 +25,13 @@ package org.glyptodon.guacamole.net.auth.simple; import java.util.Collections; import java.util.List; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.environment.Environment; +import org.glyptodon.guacamole.environment.LocalEnvironment; import org.glyptodon.guacamole.net.GuacamoleSocket; import org.glyptodon.guacamole.net.InetGuacamoleSocket; import org.glyptodon.guacamole.net.SSLGuacamoleSocket; import org.glyptodon.guacamole.net.auth.AbstractConnection; import org.glyptodon.guacamole.net.auth.ConnectionRecord; -import org.glyptodon.guacamole.properties.GuacamoleProperties; import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; @@ -81,12 +82,14 @@ public class SimpleConnection extends AbstractConnection { public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { + Environment env = new LocalEnvironment(); + // Get guacd connection parameters - String hostname = GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_HOSTNAME); - int port = GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_PORT); + String hostname = env.getProperty(Environment.GUACD_HOSTNAME); + int port = env.getProperty(Environment.GUACD_PORT); // If guacd requires SSL, use it - if (GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_SSL, false)) + if (env.getProperty(Environment.GUACD_SSL, false)) return new ConfiguredGuacamoleSocket( new SSLGuacamoleSocket(hostname, port), config, info diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleHome.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleHome.java index a9a5165a4..b629183cd 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleHome.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleHome.java @@ -23,14 +23,27 @@ package org.glyptodon.guacamole.properties; import java.io.File; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Abstract representation of the Guacamole configuration directory. * + * @deprecated * @author Michael Jumper */ public class GuacamoleHome { + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(GuacamoleHome.class); + + static { + // Warn about deprecation + logger.warn("GuacamoleHome is deprecated. Please use Environment instead."); + } + /** * GuacamoleHome is a utility class and cannot be instantiated. */ diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleProperties.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleProperties.java index 88925bd66..891667e05 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleProperties.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/properties/GuacamoleProperties.java @@ -29,6 +29,8 @@ import java.io.InputStream; import java.util.Properties; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleServerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Simple utility class for reading properties from the guacamole.properties @@ -39,10 +41,21 @@ import org.glyptodon.guacamole.GuacamoleServerException; * If none of those locations are possible, guacamole.properties will also * be read from the root of the classpath. * + * @deprecated * @author Michael Jumper */ public class GuacamoleProperties { + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(GuacamoleProperties.class); + + static { + // Warn about deprecation + logger.warn("GuacamoleProperties is deprecated. Please use Environment instead."); + } + /** * GuacamoleProperties is a utility class and cannot be instantiated. */