You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2014/06/06 14:18:30 UTC

svn commit: r1600865 - in /sling/trunk/contrib/crankstart: core/ core/src/main/java/org/apache/sling/crankstart/core/commands/ launcher/ launcher/src/test/java/org/apache/sling/crankstart/launcher/ launcher/src/test/resources/

Author: bdelacretaz
Date: Fri Jun  6 12:18:30 2014
New Revision: 1600865

URL: http://svn.apache.org/r1600865
Log:
Add support for configurations in Felix .config format

Added:
    sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/PreemptiveAuthInterceptor.java
Modified:
    sling/trunk/contrib/crankstart/core/pom.xml
    sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/commands/Configure.java
    sling/trunk/contrib/crankstart/launcher/pom.xml
    sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/CrankstartBootstrapTest.java
    sling/trunk/contrib/crankstart/launcher/src/test/resources/launcher-test.crank.txt

Modified: sling/trunk/contrib/crankstart/core/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/core/pom.xml?rev=1600865&r1=1600864&r2=1600865&view=diff
==============================================================================
--- sling/trunk/contrib/crankstart/core/pom.xml (original)
+++ sling/trunk/contrib/crankstart/core/pom.xml Fri Jun  6 12:18:30 2014
@@ -36,6 +36,44 @@
                     <target>1.6</target>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.3</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <createDependencyReducedPom>false</createDependencyReducedPom>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.felix:org.apache.felix.configadmin</include>
+                                </includes>
+                                <excludes>
+                                    <exclude>org.osgi</exclude>
+                                </excludes>
+                            </artifactSet>
+                            <filters>
+                                <filter>
+                                    <artifact>org.apache.felix:org.apache.felix.configadmin</artifact>
+                                    <includes>
+                                        <include>org/apache/felix/cm/file/Config*</include>
+                                    </includes>
+                                </filter>
+                            </filters>
+                            <relocations>
+                                <relocation>
+                                    <pattern>org.apache.felix.cm.file</pattern>
+                                    <shadedPattern>org.apache.felix.SHADED.cm.file</shadedPattern>
+                                </relocation>
+                            </relocations>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
           </plugins>
     </build>   
 
@@ -58,6 +96,16 @@
             <version>0.0.1-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
+        <!-- 
+            We use a class from the config admin implementation to read config files,
+            and we process it using maven-shade-plugin to avoid conflicts 
+         -->
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configadmin</artifactId>
+            <version>1.2.8</version>
+            <scope>compile</scope>
+        </dependency>
          <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>

Modified: sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/commands/Configure.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/commands/Configure.java?rev=1600865&r1=1600864&r2=1600865&view=diff
==============================================================================
--- sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/commands/Configure.java (original)
+++ sling/trunk/contrib/crankstart/core/src/main/java/org/apache/sling/crankstart/core/commands/Configure.java Fri Jun  6 12:18:30 2014
@@ -16,8 +16,13 @@
  */
 package org.apache.sling.crankstart.core.commands;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.Dictionary;
+import java.util.Enumeration;
 
+import org.apache.felix.cm.file.ConfigurationHandler;
 import org.apache.sling.crankstart.api.CrankstartCommand;
 import org.apache.sling.crankstart.api.CrankstartCommandLine;
 import org.apache.sling.crankstart.api.CrankstartContext;
@@ -30,6 +35,7 @@ import org.slf4j.LoggerFactory;
 public class Configure implements CrankstartCommand {
     public static final String I_CONFIGURE = "config";
     public static final String FACTORY_SUFFIX = ".factory";
+    public static final String FELIX_FORMAT_SUFFIX = "FORMAT:felix.config";
     private final Logger log = LoggerFactory.getLogger(getClass());
     
     @Override
@@ -43,8 +49,21 @@ public class Configure implements Cranks
 
     @Override
     public void execute(CrankstartContext crankstartContext, CrankstartCommandLine commandLine) throws Exception {
-        final String pid = commandLine.getQualifier();
-        final Dictionary<String, Object> properties = commandLine.getProperties();
+        
+        // Configs can be in our plain format or in Felix .config format, which supports various data types 
+        String pid = null;
+        boolean felixFormat = false;
+        if(commandLine.getQualifier().endsWith(FELIX_FORMAT_SUFFIX)) {
+            felixFormat = true;
+            pid = commandLine.getQualifier().split(" ")[0].trim();
+        } else {
+            pid = commandLine.getQualifier();
+        }
+        
+        Dictionary<String, Object> properties = commandLine.getProperties();
+        if(felixFormat) {
+            properties = parseFelixConfig(properties);
+        }
         final BundleContext bundleContext = crankstartContext.getOsgiFramework().getBundleContext();
         
         // TODO: wait for configadmin service?
@@ -74,4 +93,23 @@ public class Configure implements Cranks
             .invoke(config, properties);
         log.info("Updated configuration {}: {}", pid, properties);
     }
+    
+    @SuppressWarnings("unchecked")
+    private Dictionary<String, Object> parseFelixConfig(Dictionary<String, Object> properties) throws IOException {
+        // Build a stream in Felix .config format and parse it
+        final StringBuilder sb = new StringBuilder();
+        final Enumeration<String> keys = properties.keys();
+        while(keys.hasMoreElements()) {
+            final String key = keys.nextElement();
+            final Object value = properties.get(key);
+            sb.append(key).append("=").append(value).append("\n");
+        }
+        
+        final InputStream is = new ByteArrayInputStream(sb.toString().getBytes("UTF-8")); 
+        try {
+            return ConfigurationHandler.read(is);
+        } finally {
+            is.close();
+        }
+    }
 }

Modified: sling/trunk/contrib/crankstart/launcher/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/launcher/pom.xml?rev=1600865&r1=1600864&r2=1600865&view=diff
==============================================================================
--- sling/trunk/contrib/crankstart/launcher/pom.xml (original)
+++ sling/trunk/contrib/crankstart/launcher/pom.xml Fri Jun  6 12:18:30 2014
@@ -157,5 +157,11 @@
             <version>4.1</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+            <scope>test</scope>
+        </dependency>
       </dependencies>
 </project>

Modified: sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/CrankstartBootstrapTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/CrankstartBootstrapTest.java?rev=1600865&r1=1600864&r2=1600865&view=diff
==============================================================================
--- sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/CrankstartBootstrapTest.java (original)
+++ sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/CrankstartBootstrapTest.java Fri Jun  6 12:18:30 2014
@@ -3,6 +3,7 @@ package org.apache.sling.crankstart.laun
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.File;
@@ -13,11 +14,18 @@ import java.io.Reader;
 import java.net.ServerSocket;
 import java.util.Random;
 
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
 import org.apache.sling.commons.testing.junit.Retry;
 import org.apache.sling.commons.testing.junit.RetryRule;
 import org.junit.AfterClass;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
@@ -28,7 +36,7 @@ import org.junit.Test;
 public class CrankstartBootstrapTest {
     
     private static final int port = getAvailablePort();
-    private static final HttpClient client = new HttpClient();
+    private static DefaultHttpClient client;
     private static Thread crankstartThread;
     private static String baseUrl = "http://localhost:" + port;
     public static final String TEST_RESOURCE = "/launcher-test.crank.txt";
@@ -55,6 +63,18 @@ public class CrankstartBootstrapTest {
         return result;
     }
     
+    @Before
+    public void setupHttpClient() {
+        client = new DefaultHttpClient(); 
+    }
+    
+    private void setAdminCredentials() {
+        client.getCredentialsProvider().setCredentials(
+                AuthScope.ANY, 
+                new UsernamePasswordCredentials("admin", "admin"));
+        client.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
+    }
+    
     @BeforeClass
     public static void testExtensionPropertyBeforeTests() {
         assertNull(TEST_SYSTEM_PROPERTY + " should not be set before tests", System.getProperty(TEST_SYSTEM_PROPERTY));
@@ -62,7 +82,8 @@ public class CrankstartBootstrapTest {
     
     @BeforeClass
     public static void setup() {
-        final GetMethod get = new GetMethod(baseUrl);
+        client = new DefaultHttpClient(); 
+        final HttpUriRequest get = new HttpGet(baseUrl);
         System.setProperty("http.port", String.valueOf(port));
         System.setProperty("osgi.storage.path", getOsgiStoragePath());
         
@@ -71,7 +92,7 @@ public class CrankstartBootstrapTest {
         final Reader input = new InputStreamReader(is);
         
         try {
-            client.executeMethod(get);
+            client.execute(get);
             fail("Expecting connection to " + port + " to fail before starting HTTP service");
         } catch(IOException expected) {
         }
@@ -101,20 +122,36 @@ public class CrankstartBootstrapTest {
         crankstartThread.join();
     }
     
+    private void closeConnection(HttpResponse r) throws IOException {
+        if(r != null && r.getEntity() != null) {
+            EntityUtils.consume(r.getEntity());
+        }
+    }
+    
     @Test
     @Retry(timeoutMsec=10000, intervalMsec=250)
     public void testHttpRoot() throws Exception {
-        final GetMethod get = new GetMethod(baseUrl);
-        client.executeMethod(get);
-        assertEquals("Expecting page not found at " + get.getURI(), 404, get.getStatusCode());
+        final HttpUriRequest get = new HttpGet(baseUrl);
+        HttpResponse response = null;
+        try {
+            response = client.execute(get);
+            assertEquals("Expecting page not found at " + get.getURI(), 404, response.getStatusLine().getStatusCode());
+        } finally {
+            closeConnection(response);
+        }
     }
     
     @Test
     @Retry(timeoutMsec=10000, intervalMsec=250)
     public void testSingleConfigServlet() throws Exception {
-        final GetMethod get = new GetMethod(baseUrl + "/single");
-        client.executeMethod(get);
-        assertEquals("Expecting success for " + get.getURI(), 200, get.getStatusCode());
+        final HttpUriRequest get = new HttpGet(baseUrl + "/single");
+        HttpResponse response = null;
+        try {
+            response = client.execute(get);
+            assertEquals("Expecting success for " + get.getURI(), 200, response.getStatusLine().getStatusCode());
+        } finally {
+            closeConnection(response);
+        }
     }
     
     @Test
@@ -122,9 +159,14 @@ public class CrankstartBootstrapTest {
     public void testConfigFactoryServlet() throws Exception {
         final String [] paths = { "/foo", "/bar/test" };
         for(String path : paths) {
-            final GetMethod get = new GetMethod(baseUrl + path);
-            client.executeMethod(get);
-            assertEquals("Expecting success for " + get.getURI(), 200, get.getStatusCode());
+            final HttpUriRequest get = new HttpGet(baseUrl + path);
+            HttpResponse response = null;
+            try {
+                response = client.execute(get);
+                assertEquals("Expecting success for " + get.getURI(), 200, response.getStatusLine().getStatusCode());
+            } finally {
+                closeConnection(response);
+            }
         }
     }
     
@@ -139,9 +181,42 @@ public class CrankstartBootstrapTest {
     @Retry(timeoutMsec=10000, intervalMsec=250)
     public void testJUnitServlet() throws Exception {
         final String path = "/system/sling/junit";
-        final GetMethod get = new GetMethod(baseUrl + path);
-        client.executeMethod(get);
-        assertEquals("Expecting JUnit servlet to be installed via sling extension command, at " + get.getURI(), 200, get.getStatusCode());
+        final HttpUriRequest get = new HttpGet(baseUrl + path);
+        HttpResponse response = null;
+        try {
+            response = client.execute(get);
+            assertEquals("Expecting JUnit servlet to be installed via sling extension command, at " + get.getURI(), 200, response.getStatusLine().getStatusCode());
+        } finally {
+            closeConnection(response);
+        }
+    }
+    
+    @Test
+    @Retry(timeoutMsec=10000, intervalMsec=250)
+    public void testFelixFormatConfig() throws Exception {
+        setAdminCredentials();
+        final String path = "/system/console/config/configuration-status-20140606-1347+0200.txt";
+        final HttpUriRequest get = new HttpGet(baseUrl + path);
+        HttpResponse response = null;
+        try {
+            response = client.execute(get);
+            assertEquals("Expecting config dump to be available at " + get.getURI(), 200, response.getStatusLine().getStatusCode());
+            assertNotNull("Expecting response entity", response.getEntity());
+            String encoding = "UTF-8";
+            if(response.getEntity().getContentEncoding() != null) {
+                encoding = response.getEntity().getContentEncoding().getValue();
+            }
+            final String content = IOUtils.toString(response.getEntity().getContent(), encoding);
+            final String [] expected = new String[] {
+                    "array = [foo, bar.from.launcher.test]",
+                    "service.ranking.launcher.test = 54321"
+            };
+            for(String exp : expected) {
+                assertTrue("Expecting config content to contain " + exp, content.contains(exp));
+            }
+        } finally {
+            closeConnection(response);
+        }
     }
     
     private static String getOsgiStoragePath() {
@@ -154,4 +229,4 @@ public class CrankstartBootstrapTest {
         tmpFolder.deleteOnExit();
         return tmpFolder.getAbsolutePath();
     }
-}
+}
\ No newline at end of file

Added: sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/PreemptiveAuthInterceptor.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/PreemptiveAuthInterceptor.java?rev=1600865&view=auto
==============================================================================
--- sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/PreemptiveAuthInterceptor.java (added)
+++ sling/trunk/contrib/crankstart/launcher/src/test/java/org/apache/sling/crankstart/launcher/PreemptiveAuthInterceptor.java Fri Jun  6 12:18:30 2014
@@ -0,0 +1,41 @@
+package org.apache.sling.crankstart.launcher;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+
+/** It's not like httpclient 4.1 makes this simple... */
+class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
+
+    public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
+
+        AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
+        CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
+        HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
+
+        // If not auth scheme has been initialized yet
+        if (authState.getAuthScheme() == null) {
+            AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
+
+            // Obtain credentials matching the target host
+            Credentials creds = credsProvider.getCredentials(authScope);
+
+            // If found, generate BasicScheme preemptively
+            if (creds != null) {
+                authState.setAuthScheme(new BasicScheme());
+                authState.setCredentials(creds);
+            }
+        }
+    }
+}

Modified: sling/trunk/contrib/crankstart/launcher/src/test/resources/launcher-test.crank.txt
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/crankstart/launcher/src/test/resources/launcher-test.crank.txt?rev=1600865&r1=1600864&r2=1600865&view=diff
==============================================================================
--- sling/trunk/contrib/crankstart/launcher/src/test/resources/launcher-test.crank.txt (original)
+++ sling/trunk/contrib/crankstart/launcher/src/test/resources/launcher-test.crank.txt Fri Jun  6 12:18:30 2014
@@ -57,6 +57,12 @@ config.factory org.apache.sling.cranksta
   path=/bar/test
   message=Not used
   
+# Test Felix format configs
+config felix.format.test FORMAT:felix.config
+  mongouri="mongodb://localhost:27017"
+  service.ranking.launcher.test=I"54321"
+  array=["foo","bar.from.launcher.test"]
+  
 # Test an extension command provided by our test-services bundle
 test.system.property the.test.system.property was set by test-services bundle