You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/01 18:48:44 UTC

[14/50] brooklyn-server git commit: better parsing of comma-separated things, including from CLI Main; and use a builder for quoted string tokenizer

better parsing of comma-separated things, including from CLI Main; and use a builder for quoted string tokenizer


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/5d025ace
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/5d025ace
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/5d025ace

Branch: refs/heads/0.4.0
Commit: 5d025ace2f7cde127f0ea6ce34661b3a7d9249d1
Parents: 1607a94
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Sep 27 11:44:58 2012 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 28 00:21:23 2012 -0400

----------------------------------------------------------------------
 .../location/basic/LocationRegistry.java        |  19 ++-
 .../util/text/QuotedStringTokenizer.java        |  46 +++++--
 .../location/basic/LocationResolverTest.groovy  |  19 ++-
 .../util/text/QuotedStringTokenizerTest.java    | 125 +++++++++++--------
 usage/cli/src/main/java/brooklyn/cli/Main.java  |  19 ++-
 5 files changed, 145 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5d025ace/core/src/main/java/brooklyn/location/basic/LocationRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/LocationRegistry.java b/core/src/main/java/brooklyn/location/basic/LocationRegistry.java
index 4d3ad70..8fe9393 100644
--- a/core/src/main/java/brooklyn/location/basic/LocationRegistry.java
+++ b/core/src/main/java/brooklyn/location/basic/LocationRegistry.java
@@ -14,6 +14,9 @@ import brooklyn.config.BrooklynProperties;
 import brooklyn.location.Location;
 import brooklyn.location.LocationResolver;
 import brooklyn.util.MutableMap;
+import brooklyn.util.text.QuotedStringTokenizer;
+import brooklyn.util.text.WildcardGlobs;
+import brooklyn.util.text.WildcardGlobs.PhraseTreatment;
 
 public class LocationRegistry {
 
@@ -63,6 +66,8 @@ public class LocationRegistry {
     
     /**
      * Expects a collection of strings being the spec for locations, returns a list of locations.
+     * Also allows single elements which are comma-separated lists of locations.
+     * <p>
      * For legacy compatibility this also accepts nested lists, but that is deprecated
      * (and triggers a warning).
      */
@@ -70,9 +75,15 @@ public class LocationRegistry {
         List<Location> result = new ArrayList<Location>();
         for (Object id : ids) {
             if (id instanceof String) {
-                result.add(resolve((String) id));
+                // if it as comma-separated list -- TODO with no comma in the brackets
+                List<String> l = expandCommaSeparateLocationList((String)id);
+                if (l.size()>1) id = l;
             } else if (id instanceof Iterable) {
                 log.warn("LocationRegistry got list of list of location strings, "+ids+"; flattening");
+            }
+            if (id instanceof String) {
+                result.add(resolve((String) id));
+            } else if (id instanceof Iterable) {
                 result.addAll(getLocationsById((Iterable<?>) id));
             } else if (id instanceof Location) {
                 result.add((Location) id);
@@ -84,6 +95,12 @@ public class LocationRegistry {
         return result;
     }
 
+    private List<String> expandCommaSeparateLocationList(String id) {
+        return WildcardGlobs.getGlobsAfterBraceExpansion("{"+id+"}", false, PhraseTreatment.INTERIOR_NOT_EXPANDABLE, PhraseTreatment.INTERIOR_NOT_EXPANDABLE);
+        // don't do this, it tries to expand commas inside parentheses which is not good!
+//        QuotedStringTokenizer.builder().addDelimiterChars(",").tokenizeAll((String)id);
+    }
+    
     public Map getProperties() {
         return properties;
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5d025ace/core/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java b/core/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java
index 036aa31..52b1f45 100644
--- a/core/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java
+++ b/core/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java
@@ -48,6 +48,30 @@ public class QuotedStringTokenizer {
 		this.includeDelimiters = includeDelimiters;
 		updateNextToken();
 	}
+	
+	public static class Builder {
+	    private String quoteChars = DEFAULT_QUOTE_CHARS;
+	    private boolean includeQuotes=true;
+	    private String delimiterChars=DEFAULT_DELIMITERS;
+	    private boolean includeDelimiters=false;
+
+	    public QuotedStringTokenizer build(String stringToTokenize) {
+	        return new QuotedStringTokenizer(stringToTokenize, quoteChars, includeQuotes, delimiterChars, includeDelimiters);
+	    }
+        public List<String> tokenizeAll(String stringToTokenize) {
+            return new QuotedStringTokenizer(stringToTokenize, quoteChars, includeQuotes, delimiterChars, includeDelimiters).remainderAsList();
+        }
+        
+        public Builder quoteChars(String quoteChars) { this.quoteChars = quoteChars; return this; }
+        public Builder addQuoteChars(String quoteChars) { this.quoteChars = this.quoteChars + quoteChars; return this; }
+        public Builder includeQuotes(boolean includeQuotes) { this.includeQuotes = includeQuotes; return this; } 
+        public Builder delimiterChars(String delimiterChars) { this.delimiterChars = delimiterChars; return this; }
+        public Builder addDelimiterChars(String delimiterChars) { this.delimiterChars = this.delimiterChars + delimiterChars; return this; }
+        public Builder includeDelimiters(boolean includeDelimiters) { this.includeDelimiters = includeDelimiters; return this; } 
+	}
+    public static Builder builder() {
+        return new Builder();
+    }
 
 	String peekedNextToken = null;
 	
@@ -105,23 +129,19 @@ public class QuotedStringTokenizer {
 			//skip delimeters
 		} while (!includeDelimiters && token.matches("["+delimiters+"]+"));
 		
-		if (token.indexOf('"')<0 && token.indexOf('\'')<0) {
-			//no quote
-			peekedNextToken = token;
-			return;
-		}
-		
 		StringBuffer nextToken = new StringBuffer(token);
-		
-		while (hasOpenQuote(nextToken.toString(), quoteChars) && delegate.hasMoreTokens()) {
-			//keep appending until the quote is ended or there are no more quotes
-			nextToken.append(delegate.nextToken());
-		}
-		
+		pullUntilValid(nextToken);
 		peekedNextToken = nextToken.toString();
 	}
 
-	public static boolean hasOpenQuote(String stringToCheck) {
+	private void pullUntilValid(StringBuffer nextToken) {
+        while (hasOpenQuote(nextToken.toString(), quoteChars) && delegate.hasMoreTokens()) {
+            //keep appending until the quote is ended or there are no more quotes
+            nextToken.append(delegate.nextToken());
+        }
+    }
+
+    public static boolean hasOpenQuote(String stringToCheck) {
 		return hasOpenQuote(stringToCheck, DEFAULT_QUOTE_CHARS);
 	}
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5d025ace/core/src/test/java/brooklyn/location/basic/LocationResolverTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/location/basic/LocationResolverTest.groovy b/core/src/test/java/brooklyn/location/basic/LocationResolverTest.groovy
index eb33539..bcb053b 100644
--- a/core/src/test/java/brooklyn/location/basic/LocationResolverTest.groovy
+++ b/core/src/test/java/brooklyn/location/basic/LocationResolverTest.groovy
@@ -67,10 +67,21 @@ public class LocationResolverTest {
     public void testAcceptsList() {
         new LocationRegistry().getLocationsById(["localhost"]);
     }
-    
+
+    @Test
+    public void testRegistryCommaResolution() {
+        List<Location> l;
+        l = new LocationRegistry().getLocationsById(["byon:(hosts=\"192.168.1.{1,2}\")"]);
+        Assert.assertEquals(1, l.size());
+        l = new LocationRegistry().getLocationsById(["aws-ec2:us-west,byon:(hosts=\"192.168.1.{1,2}\"),aws-ec2:us-east"]);
+        Assert.assertEquals(3, l.size());
+        l = new LocationRegistry().getLocationsById(["aws-ec2:us-west,byon:(hosts=\"192.168.1.{1,2}\",user=bob),aws-ec2:us-east"]);
+        Assert.assertEquals(3, l.size());
+    }
+
     @Test
     public void testAcceptsListOLists() {
-        //accidental, but if inner list has a single item it automatically gets coerced correctly to string
+        //if inner list has a single item it automatically gets coerced correctly to string
         //preserve for compatibility with older CommandLineLocations (since 0.4.0) [but log warning]
         new LocationRegistry().getLocationsById([["localhost"]]);
     }
@@ -82,9 +93,9 @@ public class LocationResolverTest {
     
     @Test
     public void testLegacyCommandLineAcceptsListOLists() {
-        //accidental, but if inner list has a single item it automatically gets coerced correctly to string
+        //if inner list has a single item it automatically gets coerced correctly to string
         //preserve for compatibility (since 0.4.0)
         CommandLineLocations.getLocationsById([["localhost"]]);
     }
-
+    
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5d025ace/core/src/test/java/brooklyn/util/text/QuotedStringTokenizerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/text/QuotedStringTokenizerTest.java b/core/src/test/java/brooklyn/util/text/QuotedStringTokenizerTest.java
index e3ba325..bccfe2d 100644
--- a/core/src/test/java/brooklyn/util/text/QuotedStringTokenizerTest.java
+++ b/core/src/test/java/brooklyn/util/text/QuotedStringTokenizerTest.java
@@ -11,67 +11,86 @@ import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
+import junit.framework.Assert;
+
 import org.testng.annotations.Test;
 
-/**
- * The ConfigParserTest
- *
- * @author aled
- **/
 public class QuotedStringTokenizerTest {
-	
-	// have to initialise to use the methods (instance as it can take custom tokens)
-	private QuotedStringTokenizer defaultTokenizer= new QuotedStringTokenizer("", true); 
-	
-	@Test
-	public void testQuoting() throws Exception {
-		assertQuoteUnquoteFor("a=b");
-		assertQuoteUnquoteFor("a=\"things\",b=c");
-		assertQuoteUnquoteFor("thing=\"\"");
-		assertQuoteUnquoteFor("\"thing\"=\"\"");
-		assertQuoteUnquoteFor("");
+
+    // have to initialise to use the methods (instance as it can take custom tokens)
+    private QuotedStringTokenizer defaultTokenizer= new QuotedStringTokenizer("", true); 
+
+    @Test
+    public void testQuoting() throws Exception {
+        assertQuoteUnquoteFor("a=b");
+        assertQuoteUnquoteFor("a=\"things\",b=c");
+        assertQuoteUnquoteFor("thing=\"\"");
+        assertQuoteUnquoteFor("\"thing\"=\"\"");
+        assertQuoteUnquoteFor("");
         assertQuoteUnquoteFor("\"");
         assertQuoteUnquoteFor("\"\"");
-        
+
         assertUnquoteFor("", "''");
         assertUnquoteFor("thing=", "\"thing\"=\"\"");
         assertUnquoteFor("a=", "a=\"\"");
-	}
-	
-	@Test
-	public void testTokenizing() throws Exception {
-		testResultingTokens("foo,bar,baz", "\"", false, ",", false, "foo", "bar", "baz");
-		testResultingTokens("\"foo,bar\",baz", "\"", false, ",", false, "foo,bar", "baz");
-		testResultingTokens("\"foo,,bar\",baz", "\"", false, ",", false, "foo,,bar", "baz");
-		
-		// Have seen "the operator ""foo"" is not recognised" entries in BAML CSV files.
-		testResultingTokens("foo \"\"bar\"\" baz", "\"", false, ",", false, "foo bar baz");
-		testResultingTokens("\"foo \"\"bar\"\" baz\"", "\"", false, ",", false, "foo bar baz");
-
-		// FIXME: would like to return empty tokens when we encounter adjacent delimiters, but need
-		// to work around brain-dead java.util.StringTokenizer to do this.
-		// testResultingTokens("foo,,baz", "\"", false, ",", false, "foo", "", "baz");
-	}
-
-	private void testResultingTokens(String input, String quoteChars, boolean includeQuotes, String delimiterChars, boolean includeDelimiters, String... expectedTokens) {
-		QuotedStringTokenizer tok = new QuotedStringTokenizer(input, quoteChars, includeQuotes, delimiterChars, includeDelimiters);
-		testResultingTokens(input, tok, expectedTokens);
-	}
-	
-	private void testResultingTokens(String input, QuotedStringTokenizer tok, String... expectedTokens) {
-		List<String> actual = new LinkedList<String>();
-		while (tok.hasMoreTokens()) actual.add(tok.nextToken());
-		assertEquals(actual, Arrays.asList(expectedTokens), "Wrong tokens returned.");
-	}
-	
-	private void assertQuoteUnquoteFor(String unquoted) {
-		String quoted = defaultTokenizer.quoteToken(unquoted);
-		String reunquoted = defaultTokenizer.unquoteToken(quoted);
-		//System.out.println("orig="+unquoted+"  quoted="+quoted+"   reunquoted="+reunquoted);
-		assertEquals(reunquoted, unquoted);
-	}
-
-	private void assertUnquoteFor(String expected, String quoted) {
+    }
+
+    @Test
+    public void testTokenizing() throws Exception {
+        testResultingTokens("foo,bar,baz", "\"", false, ",", false, "foo", "bar", "baz");
+        testResultingTokens("\"foo,bar\",baz", "\"", false, ",", false, "foo,bar", "baz");
+        testResultingTokens("\"foo,,bar\",baz", "\"", false, ",", false, "foo,,bar", "baz");
+
+        // Have seen "the operator ""foo"" is not recognised" entries in BAML CSV files.
+        testResultingTokens("foo \"\"bar\"\" baz", "\"", false, ",", false, "foo bar baz");
+        testResultingTokens("\"foo \"\"bar\"\" baz\"", "\"", false, ",", false, "foo bar baz");
+
+        // FIXME: would like to return empty tokens when we encounter adjacent delimiters, but need
+        // to work around brain-dead java.util.StringTokenizer to do this.
+        // testResultingTokens("foo,,baz", "\"", false, ",", false, "foo", "", "baz");
+    }
+
+    @Test
+    public void testTokenizingBuilder() throws Exception {
+        Assert.assertEquals(Arrays.asList("foo", "bar"), QuotedStringTokenizer.builder().tokenizeAll("foo bar"));
+        Assert.assertEquals(Arrays.asList("foo,bar"), QuotedStringTokenizer.builder().tokenizeAll("foo,bar"));
+        Assert.assertEquals(Arrays.asList("foo", "bar"), QuotedStringTokenizer.builder().delimiterChars(",").tokenizeAll("foo,bar"));
+        Assert.assertEquals(Arrays.asList("foo", " bar"), QuotedStringTokenizer.builder().delimiterChars(",").tokenizeAll("foo, bar"));
+        Assert.assertEquals(Arrays.asList("foo", "bar"), QuotedStringTokenizer.builder().addDelimiterChars(",").tokenizeAll("foo, bar"));
+    }
+
+    @Test
+    public void testCommaInQuotes() throws Exception {
+        List<String> l = QuotedStringTokenizer.builder().addDelimiterChars(",").tokenizeAll("location1,byon:(hosts=\"loc2,loc3\"),location4");
+        Assert.assertEquals(Arrays.asList("location1", "byon:(hosts=\"loc2,loc3\")", "location4"), l);
+    }
+
+    /** not implemented yet */
+    @Test(enabled=false)
+    public void testCommaInParentheses() throws Exception {
+        List<String> l = QuotedStringTokenizer.builder().addDelimiterChars(",").tokenizeAll("location1, byon:(hosts=\"loc2,loc3\",user=foo),location4");
+        Assert.assertEquals(Arrays.asList("location1", "byon:(hosts=\"loc2,loc3\",user=foo)", "location4"), l);
+    }
+
+    private void testResultingTokens(String input, String quoteChars, boolean includeQuotes, String delimiterChars, boolean includeDelimiters, String... expectedTokens) {
+        QuotedStringTokenizer tok = new QuotedStringTokenizer(input, quoteChars, includeQuotes, delimiterChars, includeDelimiters);
+        testResultingTokens(input, tok, expectedTokens);
+    }
+
+    private void testResultingTokens(String input, QuotedStringTokenizer tok, String... expectedTokens) {
+        List<String> actual = new LinkedList<String>();
+        while (tok.hasMoreTokens()) actual.add(tok.nextToken());
+        assertEquals(actual, Arrays.asList(expectedTokens), "Wrong tokens returned.");
+    }
+
+    private void assertQuoteUnquoteFor(String unquoted) {
+        String quoted = defaultTokenizer.quoteToken(unquoted);
+        String reunquoted = defaultTokenizer.unquoteToken(quoted);
+        //System.out.println("orig="+unquoted+"  quoted="+quoted+"   reunquoted="+reunquoted);
+        assertEquals(reunquoted, unquoted);
+    }
+
+    private void assertUnquoteFor(String expected, String quoted) {
         String unquoted = defaultTokenizer.unquoteToken(quoted);
         //System.out.println("expected="+expected+"  quoted="+quoted+"   unquoted="+unquoted);
         assertEquals(unquoted, expected);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5d025ace/usage/cli/src/main/java/brooklyn/cli/Main.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/brooklyn/cli/Main.java b/usage/cli/src/main/java/brooklyn/cli/Main.java
index 21b6673..1b8c3db 100644
--- a/usage/cli/src/main/java/brooklyn/cli/Main.java
+++ b/usage/cli/src/main/java/brooklyn/cli/Main.java
@@ -37,7 +37,6 @@ import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 
 public class Main {
 
@@ -153,10 +152,6 @@ public class Main {
             if (verbose) {
                 System.out.println("Launching brooklyn app: "+app+" in "+locations);
             }
-            if (locations==null) {
-                log.warn("Locations parameter not supplied. Assuming empty list.");
-                locations = "";
-            }
             BrooklynLauncher launcher = BrooklynLauncher.newLauncher();
             
             ResourceUtils utils = new ResourceUtils(this);
@@ -174,6 +169,13 @@ public class Main {
             launcher.webconsolePort(port);
             launcher.webconsole(!noConsole);
             
+            if (locations==null || locations.isEmpty()) {
+                log.warn("Locations parameter not supplied: assuming localhost");
+                locations = "localhost";
+            }
+            // lean on getLocationsById to do parsing
+            List<Location> brooklynLocations = new LocationRegistry().getLocationsById(Arrays.asList(locations));
+            
             // Create the instance of the brooklyn app
             AbstractApplication application = null;
             if (app!=null) {
@@ -182,13 +184,6 @@ public class Main {
                 launcher.managing(application);
             }
             
-            // Figure out the brooklyn location(s) where to launch the application
-            Iterable<String> parsedLocations = new QuotedStringTokenizer(locations).remainderAsList();
-            log.info("Parsed user provided location(s): {}",Lists.newArrayList(parsedLocations));
-            List<Location> brooklynLocations = new LocationRegistry().getLocationsById(
-                    (parsedLocations==null || Iterables.isEmpty(parsedLocations)) ?
-                            ImmutableSet.of(CommandLineLocations.LOCALHOST) : parsedLocations);
-            
             // Launch server
             log.info("Launching Brooklyn web console management");
             launcher.launch();