Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1FCDD12ECB for ; Sun, 11 May 2014 01:59:46 +0000 (UTC) Received: (qmail 40744 invoked by uid 500); 10 May 2014 23:29:14 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 25783 invoked by uid 500); 10 May 2014 23:21:20 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 92599 invoked by uid 99); 10 May 2014 23:03:00 -0000 Received: from Unknown (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 10 May 2014 23:03:00 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 07 May 2014 09:49:00 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 6C19E2388999; Wed, 7 May 2014 09:48:36 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1592953 - in /sling/trunk/contrib/crankstart: api/src/main/java/org/apache/sling/crankstart/api/ core/src/main/java/org/apache/sling/crankstart/core/ core/src/test/java/org/apache/sling/crankstart/ core/src/test/resources/ Date: Wed, 07 May 2014 09:48:36 -0000 To: commits@sling.apache.org From: bdelacretaz@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140507094836.6C19E2388999@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: bdelacretaz Date: Wed May 7 09:48:35 2014 New Revision: 1592953 URL: http://svn.apache.org/r1592953 Log: SLING-3528 - CrankstartParser added, with tests. See core/src/test/resources/parser-test.txt for syntax Added: sling/trunk/contrib/crankstart/api/src/main/java/org/apache/sling/crankstart/api/CrankstartParser.java sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartParserImpl.java sling/trunk/contrib/crankstart/core/src/test/java/org/apache/sling/crankstart/CrankstartParserImplTest.java sling/trunk/contrib/crankstart/core/src/test/resources/ sling/trunk/contrib/crankstart/core/src/test/resources/parser-test.txt Modified: sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartFileProcessor.java Added: sling/trunk/contrib/crankstart/api/src/main/java/org/apache/sling/crankstart/api/CrankstartParser.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/api/src/main/java/org/apache/sling/crankstart/api/CrankstartParser.java?rev=1592953&view=auto ============================================================================== --- sling/trunk/contrib/crankstart/api/src/main/java/org/apache/sling/crankstart/api/CrankstartParser.java (added) +++ sling/trunk/contrib/crankstart/api/src/main/java/org/apache/sling/crankstart/api/CrankstartParser.java Wed May 7 09:48:35 2014 @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.crankstart.api; + +import java.io.IOException; +import java.io.Reader; +import java.util.Iterator; + +/** Parses a Reader to generate CrankstartCommandLine objects. + * See test code for input syntax details. + */ +public interface CrankstartParser { + Iterator parse(Reader r) throws IOException; +} \ No newline at end of file Modified: sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartFileProcessor.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartFileProcessor.java?rev=1592953&r1=1592952&r2=1592953&view=diff ============================================================================== --- sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartFileProcessor.java (original) +++ sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartFileProcessor.java Wed May 7 09:48:35 2014 @@ -81,6 +81,7 @@ public class CrankstartFileProcessor imp qualifier.append(parts[i]); } + // TODO use CrankstartParserImpl final CrankstartCommandLine cc = new CrankstartCommandLine(verb, qualifier.toString(), null); if(c.appliesTo(cc)) { try { Added: sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartParserImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartParserImpl.java?rev=1592953&view=auto ============================================================================== --- sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartParserImpl.java (added) +++ sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/CrankstartParserImpl.java Wed May 7 09:48:35 2014 @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.crankstart.core; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Iterator; + +import org.apache.sling.crankstart.api.CrankstartCommandLine; +import org.apache.sling.crankstart.api.CrankstartParser; + +/** Default crankstart parser */ +public class CrankstartParserImpl implements CrankstartParser { + + @Override + public Iterator parse(Reader r) throws IOException { + return new CmdIterator(r); + } +} + +class ParserException extends RuntimeException { + private static final long serialVersionUID = 4156681962159138482L; + + ParserException(String reason) { + super(reason); + } + + ParserException(String reason, Throwable cause) { + super(reason, cause); + } +} + +class CmdIterator implements Iterator { + + String line; + BufferedReader input; + + + + CmdIterator(Reader r) throws IOException { + input = new BufferedReader(r); + takeLine(); + } + + private String takeLine() throws IOException { + final String result = line; + line = input.readLine(); + while(line != null && ignore(line)) { + line = input.readLine(); + } + return result; + } + + private boolean ignore(String line) { + if(line == null) { + return false; + } + line = line.trim(); + return empty(line) || line.startsWith(("#")); + } + + private boolean isVerb() { + return line != null && line.length() > 0 && !Character.isWhitespace(line.charAt(0)); + } + + @Override + public boolean hasNext() { + return line != null; + } + + @Override + public CrankstartCommandLine next() { + + // Command must start with a verb, optionally followed + // by properties + if(!isVerb()) { + throw new ParserException("Expecting verb, current line is " + line); + } + + CrankstartCommandLine result = null; + + try { + // Parse verb and qualifier from first line + final String [] firstLine= takeLine().split(" "); + final String verb = firstLine[0]; + final StringBuilder qualifier = new StringBuilder(); + for(int i=1; i < firstLine.length; i++) { + if(qualifier.length() > 0) { + qualifier.append(' '); + } + qualifier.append(firstLine[i]); + } + + // Parse properties from optional indented lines + // that follow verb line + Dictionary props = null; + while(line != null && !isVerb()) { + if(props == null) { + props = new Hashtable(); + } + addProperty(props, takeLine()); + } + result = new CrankstartCommandLine(verb, qualifier.toString(), props); + } catch(IOException ioe) { + line = null; + throw new ParserException("IOException in takeLine()", ioe); + } + return result; + } + + private static boolean empty(String str) { + return str == null || str.trim().length() == 0; + } + + private void addProperty(Dictionary props, String line) throws ParserException { + if(line == null) { + return; + } + final int equalsPos = line.indexOf('='); + final String key = line.substring(0, equalsPos).trim(); + final String value = line.substring(equalsPos + 1).trim(); + if(empty(key) || empty(value)) { + throw new ParserException("Invalid property line [" + line + "]"); + } + + // If we already have a value with the same name, make that an array + Object o = props.get(key); + if(o == null) { + props.put(key, value); + } else if(o instanceof String[]) { + String [] a = (String [])o; + a = Arrays.copyOf(a, a.length + 1); + a[a.length - 1] = value; + props.put(key, a); + } else { + String [] a = new String[2]; + a[0] = (String)o; + a[1] = value; + props.put(key, a); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} + + + \ No newline at end of file Added: sling/trunk/contrib/crankstart/core/src/test/java/org/apache/sling/crankstart/CrankstartParserImplTest.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/core/src/test/java/org/apache/sling/crankstart/CrankstartParserImplTest.java?rev=1592953&view=auto ============================================================================== --- sling/trunk/contrib/crankstart/core/src/test/java/org/apache/sling/crankstart/CrankstartParserImplTest.java (added) +++ sling/trunk/contrib/crankstart/core/src/test/java/org/apache/sling/crankstart/CrankstartParserImplTest.java Wed May 7 09:48:35 2014 @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.crankstart; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Dictionary; +import java.util.Iterator; + +import org.apache.sling.crankstart.api.CrankstartCommandLine; +import org.apache.sling.crankstart.api.CrankstartParser; +import org.apache.sling.crankstart.core.CrankstartParserImpl; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class CrankstartParserImplTest { + private CrankstartParser parser; + private Reader input; + public static final String TEST_PATH = "/parser-test.txt"; + + @Before + public void setup() throws IOException { + parser = new CrankstartParserImpl(); + final InputStream is = getClass().getResourceAsStream(TEST_PATH); + assertNotNull("Expecting test resource to be found:" + TEST_PATH, is); + input = new InputStreamReader(is); + } + + @After + public void cleanup() throws IOException { + if(input != null) { + input.close(); + input = null; + } + } + + private void assertCommand(String verb, String qualifier, CrankstartCommandLine cmd) { + assertEquals("Expecting the correct verb", verb, cmd.getVerb()); + assertEquals("Expecting the correct qualifier", qualifier, cmd.getQualifier()); + } + + @Test + public void parserTest() throws IOException { + final Iterator it = parser.parse(input); + + assertCommand("verb", "qualifier with several words", it.next()); + assertCommand("verb2", "single_qualifier", it.next()); + + final CrankstartCommandLine config = it.next(); + assertCommand("config", "the.pid.goes.here", config); + final Dictionary props = config.getProperties(); + assertEquals("Expecting 3 properties", 3, props.size()); + assertEquals("Expecting correct foo value", "bar", props.get("foo")); + final Object o = props.get("array"); + assertTrue("Expecting array property", o instanceof String[]); + final String [] a = (String[])o; + assertEquals("Expecting two entries in array", 2, a.length); + assertEquals("Expecting one for first array value", "one", a[0]); + assertEquals("Expecting two for second array value", "two", a[1]); + assertEquals("Expecting correct another value", "property with several words", props.get("another")); + + assertCommand("another", "command", it.next()); + assertCommand("last.command", "", it.next()); + + assertFalse("Expecting no more commands", it.hasNext()); + } +} Added: sling/trunk/contrib/crankstart/core/src/test/resources/parser-test.txt URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/core/src/test/resources/parser-test.txt?rev=1592953&view=auto ============================================================================== --- sling/trunk/contrib/crankstart/core/src/test/resources/parser-test.txt (added) +++ sling/trunk/contrib/crankstart/core/src/test/resources/parser-test.txt Wed May 7 09:48:35 2014 @@ -0,0 +1,15 @@ +# Test the CrankstartParserImpl +verb qualifier with several words +verb2 single_qualifier + +# more comments + +# command with properties +# repeating the same property name creates an array +config the.pid.goes.here + foo = bar + array = one + array = two + another=property with several words +another command +last.command \ No newline at end of file