This closes #102
diff --git a/LICENSE b/LICENSE
index ba06157..f01776f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -387,6 +387,12 @@
   Used under the following license: Apache License, version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
   Copyright (c) SmartBear Software (2011-2015)
 
+This project includes the software: Tango Project Icons
+  Available at: https://commons.wikimedia.org/wiki/File:Network-server.svg
+  Inclusive of: tango-project-icons
+  Used under the following license: Public Domain (https://en.wikipedia.org/wiki/en:public_domain)
+  Released into the public domain by the people from the Tango! project (The Tango! Desktop Project), via Wikimedia Commons
+
 This project includes the software: typeahead.js
   Available at: https://github.com/twitter/typeahead.js
   Developed by: Twitter, Inc (http://twitter.com)
diff --git a/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java b/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java
index 6fae614..94665bd 100644
--- a/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java
+++ b/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java
@@ -44,6 +44,7 @@
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.BrooklynMavenArtifacts;
 import org.apache.brooklyn.util.maven.MavenRetriever;
+import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
@@ -124,7 +125,7 @@
     public void testObtain() {
         String localUrl = MavenRetriever.localUrl(BrooklynMavenArtifacts.artifact("", "brooklyn-dist", "tar.gz", "dist"));
         String userName = "admin";
-        String userPassword = Strings.makeRandomId(6);
+        String userPassword = Identifiers.makeRandomPassword(6);
         String remoteConfig = Joiner.on('\n').join(MutableList.of(
                 "brooklyn.webconsole.security.users=" + userName,
                 "brooklyn.webconsole.security.user.admin.password=" + userPassword)
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
index 3c9e383..d23b636 100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
@@ -456,7 +456,7 @@
     }
     
     protected String getUserPassword() {
-        return getConfigOrDefault(PostgreSqlNode.PASSWORD, Strings.makeRandomId(8));
+        return getConfigOrDefault(PostgreSqlNode.PASSWORD, Identifiers.makeRandomPassword(8));
     }
 
     protected void executeDatabaseCreationScript() {
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java
index cf22177..747517b 100644
--- a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java
@@ -44,7 +44,9 @@
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.net.Networking;
 import org.apache.brooklyn.util.net.Urls;
+import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
 
 /**
  * TODO javadoc
@@ -138,16 +140,10 @@
     public void launch() {
         newScript(MutableMap.of("usePidFile", false), LAUNCHING)
             .body.append(
-                "rm console-out.log || true",
+                "mv console-out.log console-out-$(date +\"%Y%m%d.%H%M.%S\").log || true",
                 "nohup ./sbin/rabbitmq-server > console-out.log 2> console-err.log &",
                 "./sbin/rabbitmqctl wait ${RABBITMQ_PID_FILE}",
-                "for i in {1..60}\n" +
-                    "do\n" +
-                     "    grep 'Starting broker... completed' console-out.log && exit\n" +
-                     "    sleep 1\n" +
-                     "done",
-                "echo \"Couldn't determine if rabbitmq-server is running\"",
-                "exit 1"
+                BashCommands.waitForFileContents("console-out.log", "Starting broker... completed", Duration.ONE_MINUTE, true)
             ).execute();
     }
 
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
index 854c0a3..c98fd43 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
@@ -22,6 +22,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.brooklyn.util.text.Identifiers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,7 +69,7 @@
             if (LOG.isInfoEnabled()) {
                 LOG.info(this + " cluster password not provided for " + CLUSTER_PASSWORD.getName() + " : generating random password");
             }
-            config().set(CLUSTER_PASSWORD, Strings.makeRandomId(12));
+            config().set(CLUSTER_PASSWORD, Identifiers.makeRandomPassword(12));
         }
         
         policies().add(PolicySpec.create(MemberTrackingPolicy.class)
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java
index 41808ae..0a3580a 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.entity.nosql.mongodb;
 
+import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.text.Strings;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
@@ -46,7 +47,7 @@
         String password = entity.config().get(MongoDBAuthenticationMixins.ROOT_PASSWORD);
         if (Strings.isEmpty(password)) {
             LOG.debug(entity + " has no password specified for " + MongoDBAuthenticationMixins.ROOT_PASSWORD.getName() + "; using a random string");
-            password = Strings.makeRandomId(16);
+            password = Identifiers.makeRandomPassword(16);
             entity.sensors().set(MongoDBAuthenticationMixins.ROOT_PASSWORD, password);
             entity.config().set(MongoDBAuthenticationMixins.ROOT_PASSWORD, password);
         }
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6SshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6SshDriver.java
index 70d6a14..1ed0e64 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6SshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6SshDriver.java
@@ -37,6 +37,7 @@
 import org.apache.brooklyn.util.net.Networking;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.ssh.BashCommands;
+import org.apache.brooklyn.util.time.Duration;
 
 public class JBoss6SshDriver extends JavaWebAppSshDriver implements JBoss6Driver {
 
@@ -90,6 +91,14 @@
     }
 
     @Override
+    public boolean installJava() {
+        /*
+         * JBoss only works on Java 7 or lower, see here: https://developer.jboss.org/message/808212
+         */
+        return checkForAndInstallJava("1.7");
+    }
+
+    @Override
     public void install() {
         List<String> urls = resolver.getTargets();
         String saveAs = resolver.getFilename();
@@ -144,17 +153,13 @@
                 .body.append(
                         format("export JBOSS_CLASSPATH=%s/lib/jboss-logmanager.jar",getExpandedInstallDir()),
                         format("export JBOSS_PIDFILE=%s/%s", getRunDir(), PID_FILENAME),
+                        "mv "+getRunDir()+"/console "+getRunDir()+"/console-$(date +\"%Y%m%d.%H%M.%S\") || true",
                         format("%s/bin/run.sh -Djboss.service.binding.set=%s -Djboss.server.base.dir=$RUN_DIR/server ",getExpandedInstallDir(),PORT_GROUP_NAME) +
                                 format("-Djboss.server.base.url=file://$RUN_DIR/server -Djboss.messaging.ServerPeerID=%s ",entity.getId())+
-                                format("-Djboss.boot.server.log.dir=%s/server/%s/log ",getRunDir(),SERVER_TYPE) +
-                                format("-b %s %s -c %s ", getBindAddress(), clusterArg,SERVER_TYPE) +
+                                format("-Djboss.boot.server.log.dir=%s/server/%s/log ", getRunDir(), SERVER_TYPE) +
+                                format("-b %s %s -c %s ", getBindAddress(), clusterArg, SERVER_TYPE) +
                                 ">>$RUN_DIR/console 2>&1 </dev/null &",
-                        "for i in {1..10}\n" +
-                                "do\n" +
-                                "    grep -i 'starting' "+getRunDir()+"/console && exit\n" +
-                                "    sleep 1\n" +
-                                "done\n" +
-                                "echo \"Couldn't determine if process is running (console output does not contain 'starting'); continuing but may subsequently fail\""
+                        BashCommands.waitForFileContents(getRunDir()+"/console", "Starting", Duration.TEN_SECONDS, false)
                     )
                 .execute();
     }
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7SshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7SshDriver.java
index 5fc1e86..081cd11 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7SshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7SshDriver.java
@@ -28,6 +28,7 @@
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSshDriver;
+import org.apache.brooklyn.util.text.Identifiers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
@@ -37,6 +38,7 @@
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Preconditions;
@@ -109,6 +111,14 @@
     }
 
     @Override
+    public boolean installJava() {
+        /*
+         * JBoss only works on Java 7 or lower, see here: https://developer.jboss.org/message/808212
+         */
+        return checkForAndInstallJava("1.7");
+    }
+
+    @Override
     public void install() {
         List<String> urls = resolver.getTargets();
         String saveAs = resolver.getFilename();
@@ -145,7 +155,7 @@
         String managementPassword = getManagementPassword();
         if (Strings.isBlank(managementPassword)) {
             LOG.debug(this+" has no password specified for "+JBoss7Server.MANAGEMENT_PASSWORD.getName()+"; using a random string");
-            entity.config().set(JBoss7Server.MANAGEMENT_PASSWORD, Strings.makeRandomId(8));
+            entity.config().set(JBoss7Server.MANAGEMENT_PASSWORD, Identifiers.makeRandomPassword(8));
         }
         String hashedPassword = hashPassword(getManagementUsername(), getManagementPassword(), MANAGEMENT_REALM);
 
@@ -206,6 +216,7 @@
                         "export LAUNCH_JBOSS_IN_BACKGROUND=true",
                         format("export JBOSS_HOME=%s", getExpandedInstallDir()),
                         format("export JBOSS_PIDFILE=%s/%s", getRunDir(), PID_FILENAME),
+                        "mv "+getRunDir()+"/console "+getRunDir()+"/console-$(date +\"%Y%m%d.%H%M.%S\") || true",
                         format("%s/bin/%s.sh ", getExpandedInstallDir(), SERVER_TYPE) +
                                 format("--server-config %s ", CONFIG_FILE) +
                                 format("-Djboss.server.base.dir=%s/%s ", getRunDir(), SERVER_TYPE) +
@@ -213,12 +224,7 @@
                                 "-Djava.net.preferIPv4Stack=true " +
                                 "-Djava.net.preferIPv6Addresses=false " +
                                 format(" >> %s/console 2>&1 </dev/null &", getRunDir()),
-                        "for i in {1..10}\n" +
-                                "do\n" +
-                                "    grep -i 'starting' "+getRunDir()+"/console && exit\n" +
-                                "    sleep 1\n" +
-                                "done\n" +
-                                "echo \"Couldn't determine if process is running (console output does not contain 'starting'); continuing but may subsequently fail\""
+                        BashCommands.waitForFileContents("console", "starting", Duration.TEN_SECONDS, false)
                     )
                 .execute();
     }
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6SshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6SshDriver.java
index e856e56..cd1c6e0 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6SshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/jetty/Jetty6SshDriver.java
@@ -32,6 +32,7 @@
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
 
 public class Jetty6SshDriver extends JavaWebAppSshDriver implements Jetty6Driver {
 
@@ -98,19 +99,18 @@
 
     @Override
     public void launch() {
-        Map ports = MutableMap.of("httpPort", getHttpPort(), "jmxPort", getJmxPort(), "rmiRegistryPort", getRmiRegistryPort());
+        MutableMap<String, Integer> ports = MutableMap.of("httpPort", getHttpPort(), "jmxPort", getJmxPort(), "rmiRegistryPort", getRmiRegistryPort());
         Networking.checkPortsValid(ports);
 
         newScript(MutableMap.of(USE_PID_FILE, false), LAUNCHING)
                 .body.append(
+                        "mv "+getLogFileLocation()+" "+getLogFileLocation()+"-$(date +\"%Y%m%d.%H%M.%S\") || true",
                         "./bin/jetty.sh start jetty-brooklyn.xml jetty.xml jetty-logging.xml jetty-stats.xml " +
                                 (Strings.isEmpty(getConfigXmlTemplateUrl()) ? "" : "jetty-custom.xml ") +
                                 ">> $RUN_DIR/console 2>&1 < /dev/null",
-                        "for i in {1..10} ; do\n" +
-                        "    if [ -s "+getLogFileLocation()+" ]; then exit; fi\n" +
-                        "    sleep 1\n" +
-                        "done",
-                        "echo \"Couldn't determine if jetty-server is running (log file is still empty); continuing but may subsequently fail\""
+                        BashCommands.waitForFileExists(getLogFileLocation(), Duration.TEN_SECONDS, false),
+                        "sleep 5",
+                        "cat $RUN_DIR/console"
                     )
                 .execute();
         log.debug("launched jetty");
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
index 4963038..20c79ae 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
@@ -103,7 +103,7 @@
                 .add(BashCommands.ifExecutableElse0("apt-get", BashCommands.chain(
                         BashCommands.installPackage("software-properties-common python-software-properties python g++ make"),
                         BashCommands.sudo("add-apt-repository ppa:chris-lea/node.js"))))
-                .add(BashCommands.installPackage(MutableMap.of("yum", "git nodejs npm", "apt", "git-core nodejs"), null))
+                .add(BashCommands.installPackage(MutableMap.of("yum", "git nodejs npm", "apt", "git-core nodejs npm"), null))
                 .add("mkdir -p \"$HOME/.npm\"")
                 .add(BashCommands.sudo("npm install -g n"))
                 .add(BashCommands.sudo("n " + getVersion()))
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatSshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatSshDriver.java
index 5214b28..eeb88a2 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatSshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatSshDriver.java
@@ -35,6 +35,7 @@
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.ssh.BashCommands;
 import org.apache.brooklyn.util.text.StringEscapes.BashStringEscapes;
+import org.apache.brooklyn.util.time.Duration;
 
 public class TomcatSshDriver extends JavaWebAppSshDriver implements TomcatDriver {
 
@@ -91,13 +92,9 @@
         // so the process failed to start.
         newScript(MutableMap.of(USE_PID_FILE, false), LAUNCHING)
                 .body.append(
+                        "mv "+getLogFileLocation()+" "+getLogFileLocation()+"-$(date +\"%Y%m%d.%H%M.%S\").log || true",
                         format("%s/bin/startup.sh >>$RUN/console 2>&1 </dev/null",getExpandedInstallDir()),
-                        "for i in {1..10}\n" +
-                        "do\n" +
-                        "    if [ -s "+getLogFileLocation()+" ]; then exit; fi\n" +
-                        "    sleep 1\n" +
-                        "done\n" +
-                        "echo \"Couldn't determine if tomcat-server is running (logs/catalina.out is still empty); continuing but may subsequently fail\""
+                        BashCommands.waitForFileExists(getLogFileLocation(), Duration.TEN_SECONDS, false)
                     )
                 .execute();
     }