Thank you for your inquiry. DVSR_Sarma Krovi is no longer with the firm. For immediate assistance, please contact Reception at +1-212-478-0000.
Sincerely, The D. E. Shaw Group -- 8< --- CUT HERE -------------------------- CUT HERE --- >8 -- From: jc...@apache.org To: comm...@shindig.apache.org cc: Subject: svn commit: r1202283 - in /shindig/trunk: config/ java/common/src/main/java/org/apache/shindig/auth/ java/common/src/main/java/org/apache/shindig/common/util/ java/common/src/main/java/org/apache/shindig/config/ java/common/src/test/java/org/apache/shi... Author: jcian Date: Tue Nov 15 16:25:34 2011 New Revision: 1202283 URL: http://svn.apache.org/viewvc?rev=1202283&view=rev Log: SHINDIG-1660: Allow ContainerConfig stack to load property values from external resources and update BlobCrypterSecurityTokenCodec to use this new feature. Added: shindig/trunk/java/common/src/test/resources/classpath-accessible-test-file.txt Modified: shindig/trunk/config/container.js shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ResourceLoader.java shindig/trunk/java/common/src/main/java/org/apache/shindig/config/JsonContainerConfigLoader.java shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java shindig/trunk/java/common/src/test/java/org/apache/shindig/config/JsonContainerConfigLoaderTest.java Modified: shindig/trunk/config/container.js URL: http://svn.apache.org/viewvc/shindig/trunk/config/container.js?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/config/container.js (original) +++ shindig/trunk/config/container.js Tue Nov 15 16:25:34 2011 @@ -44,6 +44,9 @@ // Container must be an array; this allows multiple containers // to share configuration. + +// Note that you can embed values directly or you can choose to have values read from a file on disk +// or read from the classpath ("foo-key" : "file:///foo-file.txt" || "foo-key" : "res://foo-file.txt") // TODO: Move out accel container config into a separate accel.js file. {"gadgets.container" : ["default", "accel"], @@ -88,22 +91,23 @@ // Callback URL. Scheme relative URL for easy switch between https/http. "gadgets.uri.oauth.callbackTemplate" : "//%host%${CONTEXT_ROOT}/gadgets/oauthcallback", -// Use an insecure security token by default -"gadgets.securityTokenType" : "insecure", - // Config param to load Opensocial data for social // preloads in data pipelining. %host% will be // substituted with the current host. "gadgets.osDataUri" : "http://%host%${CONTEXT_ROOT}/rpc", -// Uncomment these to switch to a secure version. If both a key file and key are provided, the key -// will take precedence; thus, to use a key file, you must explicitly not provide a key. The -// best way to generate a key is to do something like this: +// Use an insecure security token by default +"gadgets.securityTokenType" : "insecure", + +// Uncomment the securityTokenType and one of the securityTokenKey's to switch to a secure version. +// Note that you can choose to use an embedded key, a filesystem reference or a classpath reference. +// The best way to generate a key is to do something like this: // dd if=/dev/random bs=32 count=1 | openssl base64 // -// "gadgets.securityTokenType" : "secure", -// "gadgets.securityTokenKeyFile" : "/path/to/key/file.txt", -// "gadgets.securityTokenKey" : "", +//"gadgets.securityTokenType" : "secure", +//"gadgets.securityTokenKey" : "default-insecure-embedded-key", +//"gadgets.securityTokenKey" : "file:///path/to/key/file.txt", +//"gadgets.securityTokenKey" : "res://some-file-on-the-classpath.txt", // OS 2.0 Gadget DOCTYPE: used in Gadgets with @specificationVersion 2.0 or greater and // quirksmode on Gadget has not been set. Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java (original) +++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodec.java Tue Nov 15 16:25:34 2011 @@ -24,15 +24,12 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.shindig.common.crypto.BasicBlobCrypter; import org.apache.shindig.common.crypto.BlobCrypter; import org.apache.shindig.common.crypto.BlobCrypterException; -import org.apache.shindig.common.util.ResourceLoader; import org.apache.shindig.config.ContainerConfig; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Maps; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -56,8 +53,6 @@ import com.google.inject.Singleton; public class BlobCrypterSecurityTokenCodec implements SecurityTokenCodec, ContainerConfig.ConfigObserver { private static final Logger LOG = Logger.getLogger(BlobCrypterSecurityTokenCodec.class.getName()); - public static final String SECURITY_TOKEN_KEY_FILE = "gadgets.securityTokenKeyFile"; - public static final String SECURITY_TOKEN_KEY = "gadgets.securityTokenKey"; public static final String SIGNED_FETCH_DOMAIN = "gadgets.signedFetchDomain"; @@ -109,14 +104,10 @@ public class BlobCrypterSecurityTokenCod private void loadContainers(ContainerConfig config, Collection<String> containers, Map<String, BlobCrypter> crypters, Map<String, String> domains) throws IOException { for (String container : containers) { - String keyFile = config.getString(container, SECURITY_TOKEN_KEY_FILE); String key = config.getString(container, SECURITY_TOKEN_KEY); if (key != null) { BlobCrypter crypter = loadCrypter(key); crypters.put(container, crypter); - } else if (keyFile != null) { - BlobCrypter crypter = loadCrypter(getKeyFromFile(keyFile)); - crypters.put(container, crypter); } String domain = config.getString(container, SIGNED_FETCH_DOMAIN); domains.put(container, domain); @@ -124,26 +115,13 @@ public class BlobCrypterSecurityTokenCod } /** - * Gets a key from the given keyFile. - * - * @param keyFile the key file from which to read the key - * @return the key - * @throws IOException if there was an error read the key file - */ - @VisibleForTesting - protected String getKeyFromFile(String keyFile) throws IOException { - return IOUtils.toString(ResourceLoader.open(keyFile), "UTF-8"); - } - - /** - * Load a BlobCrypter from the key file. Override this if you have your own - * BlobCrypter implementation. + * Load a BlobCrypter using the specified key. Override this if you have your own BlobCrypter + * implementation. * - * @param key The key to use for encryption + * @param key The security token key. * @return The BlobCrypter. - * @throws IOException If the key file is invalid. */ - protected BlobCrypter loadCrypter(String key) throws IOException { + protected BlobCrypter loadCrypter(String key) { return new BasicBlobCrypter(key); } Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java (original) +++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/DefaultSecurityTokenCodec.java Tue Nov 15 16:25:34 2011 @@ -18,6 +18,7 @@ */ package org.apache.shindig.auth; +import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -75,6 +76,11 @@ public class DefaultSecurityTokenCodec i return codec.encodeToken(token); } + @VisibleForTesting + protected SecurityTokenCodec getCodec() { + return codec; + } + public int getTokenTimeToLive() { return codec.getTokenTimeToLive(); } Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ResourceLoader.java URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ResourceLoader.java?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ResourceLoader.java (original) +++ shindig/trunk/java/common/src/main/java/org/apache/shindig/common/util/ResourceLoader.java Tue Nov 15 16:25:34 2011 @@ -31,19 +31,24 @@ import java.io.InputStream; * Handles loading contents from resource and file system files. */ public final class ResourceLoader { + public static final String RESOURCE_PREFIX = "res://"; + public static final String FILE_PREFIX = "file://"; + private ResourceLoader() {} /** * Opens a given path as either a resource or a file, depending on the path * name. * * If path starts with res://, we interpret it as a resource. - * Otherwise we attempt to load it as a file. + * If path starts with file://, or path has no prefix, we interpret it as a file. * @param path * @return The opened input stream */ public static InputStream open(String path) throws IOException { - if (path.startsWith("res://")) { - return openResource(path.substring(6)); + if (path.startsWith(RESOURCE_PREFIX)) { + return openResource(path.substring(RESOURCE_PREFIX.length())); + } else if (path.startsWith(FILE_PREFIX)) { + path = path.substring(FILE_PREFIX.length()); } File file = new File(path); return new FileInputStream(file); Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/config/JsonContainerConfigLoader.java URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/config/JsonContainerConfigLoader.java?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/java/common/src/main/java/org/apache/shindig/config/JsonContainerConfigLoader.java (original) +++ shindig/trunk/java/common/src/main/java/org/apache/shindig/config/JsonContainerConfigLoader.java Tue Nov 15 16:25:34 2011 @@ -25,6 +25,7 @@ import com.google.common.collect.Immutab import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.apache.commons.io.IOUtils; import org.apache.shindig.common.logging.i18n.MessageKeys; import org.apache.shindig.common.util.ResourceLoader; import org.apache.shindig.config.ContainerConfig.Transaction; @@ -273,6 +274,20 @@ public class JsonContainerConfigLoader { Map<String, Object> values = new HashMap<String, Object>(json.length(), 1); for (String key : keys) { Object val = jsonToConfig(json.opt(key)); + //If this is a string see if its a pointer to an external resource, and if so, load the resource + if (val instanceof String) { + String stringVal = (String) val; + if (stringVal.startsWith(ResourceLoader.RESOURCE_PREFIX) || + stringVal.startsWith(ResourceLoader.FILE_PREFIX)) { + try { + val = IOUtils.toString(ResourceLoader.open(stringVal), "UTF-8"); + } catch (IOException e) { + if (LOG.isLoggable(Level.WARNING)) { + LOG.logp(Level.WARNING, classname, "jsonToMap", MessageKeys.READING_CONFIG, e); + } + } + } + } values.put(key, val); } return Collections.unmodifiableMap(values); Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java (original) +++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/BlobCrypterSecurityTokenCodecTest.java Tue Nov 15 16:25:34 2011 @@ -22,14 +22,12 @@ import static org.junit.Assert.assertEqu import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.shindig.auth.AbstractSecurityToken.Keys; import org.apache.shindig.common.crypto.BasicBlobCrypter; import org.apache.shindig.common.crypto.BlobCrypter; -import org.apache.shindig.common.util.CharsetUtil; import org.apache.shindig.common.util.FakeTimeSource; import org.apache.shindig.config.BasicContainerConfig; import org.apache.shindig.config.ContainerConfig; @@ -56,71 +54,32 @@ public class BlobCrypterSecurityTokenCod .addContainer(makeContainer("default")) .addContainer(makeContainer("container")) .addContainer(makeContainer("example")) - .addContainer(makeContainer("keyOnlyNoFile", true)) .commit(); - codec = new CodecWithLoadStubbedOut(config); + codec = new BlobCrypterSecurityTokenCodec(config); timeSource = new FakeTimeSource(); } protected Map<String, Object> makeContainer(String container) { - return makeContainer(container, false); - } - - protected Map<String, Object> makeContainer(String container, boolean insertKey) { - if (insertKey) { - return ImmutableMap.<String, Object>of(ContainerConfig.CONTAINER_KEY, - ImmutableList.of(container), - BlobCrypterSecurityTokenCodec.SECURITY_TOKEN_KEY_FILE, - container, - BlobCrypterSecurityTokenCodec.SECURITY_TOKEN_KEY, - getContainerKey(container), - BlobCrypterSecurityTokenCodec.SIGNED_FETCH_DOMAIN, - container + ".com"); - } else { - return ImmutableMap.<String, Object>of(ContainerConfig.CONTAINER_KEY, - ImmutableList.of(container), - BlobCrypterSecurityTokenCodec.SECURITY_TOKEN_KEY_FILE, - container, - BlobCrypterSecurityTokenCodec.SIGNED_FETCH_DOMAIN, - container + ".com"); - } + return ImmutableMap.<String, Object>of(ContainerConfig.CONTAINER_KEY, + ImmutableList.of(container), + BlobCrypterSecurityTokenCodec.SECURITY_TOKEN_KEY, + getContainerKey(container), + BlobCrypterSecurityTokenCodec.SIGNED_FETCH_DOMAIN, + container + ".com"); } protected String getContainerKey(String container) { return "KEY FOR CONTAINER " + container; } - protected BlobCrypter getBlobCrypter(String fileName) { - BasicBlobCrypter c = new BasicBlobCrypter(CharsetUtil.getUtf8Bytes(fileName)); + protected BlobCrypter getBlobCrypter(String key) { + BasicBlobCrypter c = new BasicBlobCrypter(key); c.timeSource = timeSource; return c; } - /** - * Stubs out loading the key file. - */ - private class CodecWithLoadStubbedOut extends BlobCrypterSecurityTokenCodec { - - public CodecWithLoadStubbedOut(ContainerConfig config) { - super(config); - } - - /** - * @param file the location of the file. - * @return a crypter based on the name of the file passed in, rather than the contents. - * @throws IOException when passed a filename with 'fail' in it. - */ - @Override - protected String getKeyFromFile(String file) throws IOException { - if (file.contains("fail")) { - throw new IOException("Load failed: " + file); - } - return getContainerKey(file); - } - } - @Test - public void testCreateTokenUsingKeyFile() throws Exception { + public void testCreateToken() throws Exception { Map<String, String> values = new HashMap<String, String>(); values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml"); values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10)); @@ -227,18 +186,6 @@ public class BlobCrypterSecurityTokenCod } @Test - public void testLoadFailure() throws Exception { - config.newTransaction().addContainer(makeContainer("failure")).commit(); - - try { - new CodecWithLoadStubbedOut(config); - fail("Should have failed to load crypter"); - } catch (RuntimeException e) { - assertTrue(e.getMessage(), e.getMessage().contains("Load failed")); - } - } - - @Test public void testChangingContainers() throws Exception { String newContainer = "newcontainer"; Map<String, String> values = new HashMap<String, String>(); @@ -270,27 +217,4 @@ public class BlobCrypterSecurityTokenCod // pass } } - - @Test - public void testCreateTokenUsingKey() throws Exception { - Map<String, String> values = new HashMap<String, String>(); - values.put(Keys.APP_URL.getKey(), "http://www.example.com/gadget.xml"); - values.put(Keys.MODULE_ID.getKey(), Long.toString(12345L, 10)); - values.put(Keys.OWNER.getKey(), "owner"); - values.put(Keys.VIEWER.getKey(), "viewer"); - values.put(Keys.TRUSTED_JSON.getKey(), "trusted"); - - BlobCrypterSecurityToken t = new BlobCrypterSecurityToken("keyOnlyNoFile", null, null, values); - String encrypted = t.getContainer() + ":" + getBlobCrypter(getContainerKey("keyOnlyNoFile")).wrap(t.toMap()); - - SecurityToken t2 = codec.createToken(ImmutableMap.of(SecurityTokenCodec.SECURITY_TOKEN_NAME, encrypted)); - - assertEquals("http://www.example.com/gadget.xml", t2.getAppId()); - assertEquals("http://www.example.com/gadget.xml", t2.getAppUrl()); - assertEquals("keyOnlyNoFile.com", t2.getDomain()); - assertEquals(12345L, t2.getModuleId()); - assertEquals("owner", t2.getOwnerId()); - assertEquals("viewer", t2.getViewerId()); - assertEquals("trusted", t2.getTrustedJson()); - } } Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java (original) +++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/DefaultSecurityTokenCodecTest.java Tue Nov 15 16:25:34 2011 @@ -22,7 +22,6 @@ import static org.junit.Assert.assertEqu import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.FileNotFoundException; import java.util.Collection; import java.util.Collections; import java.util.Map; @@ -50,7 +49,7 @@ public class DefaultSecurityTokenCodecTe if ("default".equals(container)) { return tokenType; } - } else if ("gadgets.securityTokenKeyFile".equals(parameter)) { + } else if ("gadgets.securityTokenKey".equals(parameter)) { return "container key file: " + container; } return null; @@ -101,12 +100,7 @@ public class DefaultSecurityTokenCodecTe @Test public void testRealDecoder() throws Exception { // Just verifies that "secure" tokens get routed to the right decoder class. - try { - new DefaultSecurityTokenCodec(new FakeContainerConfig("secure")); - fail("Should have thrown"); - } catch (RuntimeException e) { - assertTrue("root cause should have been FileNotFoundException: " + e, - e.getCause() instanceof FileNotFoundException); - } + DefaultSecurityTokenCodec securityTokenCodec = new DefaultSecurityTokenCodec(new FakeContainerConfig("secure")); + assertTrue(securityTokenCodec.getCodec() instanceof BlobCrypterSecurityTokenCodec); } } Modified: shindig/trunk/java/common/src/test/java/org/apache/shindig/config/JsonContainerConfigLoaderTest.java URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/config/JsonContainerConfigLoaderTest.java?rev=1202283&r1=1202282&r2=1202283&view=diff ============================================================================== --- shindig/trunk/java/common/src/test/java/org/apache/shindig/config/JsonContainerConfigLoaderTest.java (original) +++ shindig/trunk/java/common/src/test/java/org/apache/shindig/config/JsonContainerConfigLoaderTest.java Tue Nov 15 16:25:34 2011 @@ -23,7 +23,9 @@ import static org.apache.shindig.config. import static org.apache.shindig.config.ContainerConfig.CONTAINER_KEY; import static org.apache.shindig.config.ContainerConfig.PARENT_KEY; import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import org.apache.shindig.common.util.ResourceLoader; import org.apache.shindig.expressions.Expressions; import org.json.JSONObject; import org.junit.Before; @@ -55,13 +57,15 @@ public class JsonContainerConfigLoaderTe private static final String[] ARRAY_VALUE = {"Hello", "World"}; private static final String ARRAY_ALT_VALUE = "Not an array"; + public static final String DYNAMICALLY_LOADED_VALUE_KEY = "dynamicallyLoadedValueKey"; + private ExpressionContainerConfig config; - private File createContainer(JSONObject json) throws Exception { - File file = File.createTempFile(getClass().getName(), ".json"); + private File createTemporaryFile(Object content, String extension) throws Exception { + File file = File.createTempFile(getClass().getName(), extension); file.deleteOnExit(); BufferedWriter out = new BufferedWriter(new FileWriter(file)); - out.write(json.toString()); + out.write(content.toString()); out.close(); return file; } @@ -79,7 +83,7 @@ public class JsonContainerConfigLoaderTe nested.put(NESTED_NAME, NESTED_VALUE); json.put(NESTED_KEY, nested); - return createContainer(json); + return createTemporaryFile(json, ".json"); } private void createConfigForTest(String containers) throws ContainerConfigException { @@ -117,7 +121,7 @@ public class JsonContainerConfigLoaderTe .put(NESTED_KEY, NESTED_VALUE); File parentFile = createDefaultContainer(); - File childFile = createContainer(json); + File childFile = createTemporaryFile(json, ".json"); createConfigForTest(childFile.getAbsolutePath() + JsonContainerConfigLoader.FILE_SEPARATOR + parentFile.getAbsolutePath()); @@ -139,7 +143,7 @@ public class JsonContainerConfigLoaderTe json.put(NESTED_KEY, nested); - File childFile = createContainer(json); + File childFile = createTemporaryFile(json, ".json"); File parentFile = createDefaultContainer(); createConfigForTest(childFile.getAbsolutePath() + JsonContainerConfigLoader.FILE_SEPARATOR + parentFile.getAbsolutePath()); @@ -179,7 +183,7 @@ public class JsonContainerConfigLoaderTe json.put(PARENT_KEY, "bad bad bad parent!"); json.put(ARRAY_NAME, ARRAY_ALT_VALUE); - createConfigForTest(createContainer(json).getAbsolutePath()); + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); } @Test @@ -198,7 +202,7 @@ public class JsonContainerConfigLoaderTe json.put("expression", "Hello, ${world}!"); json.put("world", "Earth"); - createConfigForTest(createContainer(json).getAbsolutePath()); + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); assertEquals("Hello, Earth!", config.getString(DEFAULT_CONTAINER, "expression")); } @@ -210,7 +214,7 @@ public class JsonContainerConfigLoaderTe json.put(CONTAINER_KEY, new String[]{DEFAULT_CONTAINER}); json.put("expression", "port=${SERVER_PORT}"); - createConfigForTest(createContainer(json).getAbsolutePath()); + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); assertEquals("port=8080", config.getString(DEFAULT_CONTAINER, "expression")); } @@ -223,7 +227,7 @@ public class JsonContainerConfigLoaderTe json.put("port", "${SERVER_PORT}"); json.put("host", "${SERVER_HOST}"); - createConfigForTest(createContainer(json).getAbsolutePath()); + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); assertEquals("8080", config.getString(DEFAULT_CONTAINER, "port")); assertEquals("8080", config.getString("testContainer", "port")); @@ -239,7 +243,7 @@ public class JsonContainerConfigLoaderTe json.put(PARENT_KEY, DEFAULT_CONTAINER); json.put("parentExpression", "${parent['" + TOP_LEVEL_NAME + "']}"); - File childFile = createContainer(json); + File childFile = createTemporaryFile(json, ".json"); File parentFile = createDefaultContainer(); createConfigForTest(childFile.getAbsolutePath() + JsonContainerConfigLoader.FILE_SEPARATOR + parentFile.getAbsolutePath()); @@ -251,7 +255,7 @@ public class JsonContainerConfigLoaderTe public void nullEntryEvaluation() throws Exception { // We use a JSON Object here to guarantee that we're well formed up front. JSONObject json = new JSONObject("{ 'gadgets.container' : ['default'], features : { osapi : null }}"); - createConfigForTest(createContainer(json).getAbsolutePath()); + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); assertNull(config.getMap("default", "features").get("osapi")); } @@ -261,11 +265,74 @@ public class JsonContainerConfigLoaderTe JSONObject parent = new JSONObject("{ 'gadgets.container' : ['default'], features : { osapi : 'foo' }}"); JSONObject child = new JSONObject("{ 'gadgets.container' : ['child'], features : null}"); JSONObject grand = new JSONObject("{ 'gadgets.container' : ['grand'], parent : 'child'}"); - createConfigForTest(createContainer(parent).getAbsolutePath()); - createConfigForTest(createContainer(child).getAbsolutePath()); - createConfigForTest(createContainer(grand).getAbsolutePath()); + createConfigForTest(createTemporaryFile(parent, ".json").getAbsolutePath()); + createConfigForTest(createTemporaryFile(child, ".json").getAbsolutePath()); + createConfigForTest(createTemporaryFile(grand, ".json").getAbsolutePath()); assertEquals("foo", config.getMap("default", "features").get("osapi")); assertNull(config.getProperty("child", "features")); assertNull(config.getProperty("grand", "features")); } + + @Test + public void resourceLoaderClasspathTest() throws Exception { + // Pointer to a file that we'll load from the classpath + String testFile = "classpath-accessible-test-file.txt"; + + // We use a JSON Object here to guarantee that we're well formed up front. + JSONObject json = new JSONObject(); + json.put(CONTAINER_KEY, new String[]{DEFAULT_CONTAINER}); + json.put(DYNAMICALLY_LOADED_VALUE_KEY, ResourceLoader.RESOURCE_PREFIX + testFile); + + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); + + assertEquals(testFile, config.getString(DEFAULT_CONTAINER, DYNAMICALLY_LOADED_VALUE_KEY).trim()); + } + + @Test + public void resourceLoaderFileTest() throws Exception { + // Create a temporary file that we can load from + String dynamicValue = "dynamic value"; + File temporaryFile = createTemporaryFile(dynamicValue, ".txt"); + + // We use a JSON Object here to guarantee that we're well formed up front. + JSONObject json = new JSONObject(); + json.put(CONTAINER_KEY, new String[]{DEFAULT_CONTAINER}); + json.put(DYNAMICALLY_LOADED_VALUE_KEY, ResourceLoader.FILE_PREFIX + temporaryFile.getAbsolutePath()); + + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); + + assertEquals(dynamicValue, config.getString(DEFAULT_CONTAINER, DYNAMICALLY_LOADED_VALUE_KEY).trim()); + } + + @Test + public void resourceLoaderClasspathFailureTest() throws Exception { + // Pointer to an invalid resource reference + String invalidResource = ResourceLoader.RESOURCE_PREFIX + "does-not-exist"; + + // We use a JSON Object here to guarantee that we're well formed up front. + JSONObject json = new JSONObject(); + json.put(CONTAINER_KEY, new String[]{DEFAULT_CONTAINER}); + json.put(DYNAMICALLY_LOADED_VALUE_KEY, invalidResource); + + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); + + // If we fail to load a resource a warning is logged and we just end up with the raw value back + assertEquals(invalidResource, config.getString(DEFAULT_CONTAINER, DYNAMICALLY_LOADED_VALUE_KEY)); + } + + @Test + public void resourceLoaderFileFailureTest() throws Exception { + // Pointer to an invalid resource reference + String invalidResource = ResourceLoader.FILE_PREFIX + "does-not-exist"; + + // We use a JSON Object here to guarantee that we're well formed up front. + JSONObject json = new JSONObject(); + json.put(CONTAINER_KEY, new String[]{DEFAULT_CONTAINER}); + json.put(DYNAMICALLY_LOADED_VALUE_KEY, invalidResource); + + createConfigForTest(createTemporaryFile(json, ".json").getAbsolutePath()); + + // If we fail to load a resource a warning is logged and we just end up with the raw value back + assertEquals(invalidResource, config.getString(DEFAULT_CONTAINER, DYNAMICALLY_LOADED_VALUE_KEY)); + } } Added: shindig/trunk/java/common/src/test/resources/classpath-accessible-test-file.txt URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/resources/classpath-accessible-test-file.txt?rev=1202283&view=auto ============================================================================== --- shindig/trunk/java/common/src/test/resources/classpath-accessible-test-file.txt (added) +++ shindig/trunk/java/common/src/test/resources/classpath-accessible-test-file.txt Tue Nov 15 16:25:34 2011 @@ -0,0 +1 @@ +classpath-accessible-test-file.txt \ No newline at end of file