Fixing SLING-1500 - Added a EL function to support getting a value with a default value or casting the result

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1494643 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/scripting/jsp/taglib/SlingFunctions.java b/src/main/java/org/apache/sling/scripting/jsp/taglib/SlingFunctions.java
index ec4c374..0b7192e 100644
--- a/src/main/java/org/apache/sling/scripting/jsp/taglib/SlingFunctions.java
+++ b/src/main/java/org/apache/sling/scripting/jsp/taglib/SlingFunctions.java
@@ -21,6 +21,7 @@
 import org.apache.sling.api.adapter.Adaptable;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -90,21 +91,6 @@
 	}
 
 	/**
-	 * Loads the Class for the name from the current thread's classload.
-	 * 
-	 * @param className
-	 *            The name of the class to load
-	 * @return the class
-	 * @throws ClassNotFoundException
-	 *             a class with the specified name could not be found
-	 */
-	private static Class<?> loadClass(String className)
-			throws ClassNotFoundException {
-		return Thread.currentThread().getContextClassLoader()
-				.loadClass(className);
-	}
-
-	/**
 	 * Gets the resource at the relative path to the provided resource.
 	 * 
 	 * @param base
@@ -142,13 +128,37 @@
 		log.trace("getResource");
 
 		log.debug("Getting resource at path {}", path);
-		if(resolver == null){
+		if (resolver == null) {
 			throw new IllegalArgumentException("Null resource resolver");
 		}
 		return resolver.getResource(path);
 	}
 
 	/**
+	 * Gets the value of the specified key from the ValueMap and either coerses
+	 * the value into the specified type or uses the specified type as a default
+	 * depending on the parameter passed in.
+	 * 
+	 * @param properties
+	 *            the ValueMap from which to retrieve the value
+	 * @param key
+	 *            the key for the value to retrieve
+	 * @param defaultOrType
+	 *            either the default value or the class to which to coerce the
+	 *            value
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public static final <E> E getValue(ValueMap properties, String key,
+			Object defaultOrType) {
+		if (defaultOrType instanceof Class<?>) {
+			return properties.get(key, (Class<E>) defaultOrType);
+		} else {
+			return properties.get(key, (E) defaultOrType);
+		}
+	}
+
+	/**
 	 * Method for allowing the invocation of the Sling Resource listChildren
 	 * method.
 	 * 
@@ -159,7 +169,7 @@
 	 */
 	public static final Iterator<Resource> listChildren(Resource resource) {
 		log.trace("listChildren");
-		
+
 		Iterator<Resource> children = null;
 		if (resource != null) {
 			log.debug("Listing children at path {}", resource.getPath());
@@ -169,4 +179,19 @@
 		}
 		return children;
 	}
+
+	/**
+	 * Loads the Class for the name from the current thread's classload.
+	 * 
+	 * @param className
+	 *            The name of the class to load
+	 * @return the class
+	 * @throws ClassNotFoundException
+	 *             a class with the specified name could not be found
+	 */
+	private static Class<?> loadClass(String className)
+			throws ClassNotFoundException {
+		return Thread.currentThread().getContextClassLoader()
+				.loadClass(className);
+	}
 }
diff --git a/src/main/resources/META-INF/sling.tld b/src/main/resources/META-INF/sling.tld
index 9eb1872..4473e1a 100644
--- a/src/main/resources/META-INF/sling.tld
+++ b/src/main/resources/META-INF/sling.tld
@@ -42,6 +42,13 @@
 		<function-signature>org.apache.sling.api.resource.Resource getResource(org.apache.sling.api.resource.ResourceResolver,java.lang.String)</function-signature>
 	</function>
 
+    <function>
+        <name>getValue</name>
+        <function-class>org.apache.sling.scripting.jsp.taglib.SlingFunctions</function-class>
+        <function-signature>java.lang.Object getValue(org.apache.sling.api.resource.ValueMap,java.lang.String,java.lang.Object)</function-signature>
+    </function>
+	
+
 	<function>
 		<name>listChildren</name>
 		<function-class>org.apache.sling.scripting.jsp.taglib.SlingFunctions</function-class>
diff --git a/src/test/java/org/apache/sling/scripting/jsp/taglib/TestSlingFunctions.java b/src/test/java/org/apache/sling/scripting/jsp/taglib/TestSlingFunctions.java
index c87bca2..ab27229 100644
--- a/src/test/java/org/apache/sling/scripting/jsp/taglib/TestSlingFunctions.java
+++ b/src/test/java/org/apache/sling/scripting/jsp/taglib/TestSlingFunctions.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 
@@ -45,6 +46,7 @@
 			.getLogger(TestGetResourceTag.class);
 	private MockResource resource;
 	private MockResourceResolver resolver;
+	private Date date;
 	private static final String TEST_PATH = "/content";
 
 	/**
@@ -68,6 +70,9 @@
 			}
 		};
 		resource = new MockResource(resolver, TEST_PATH, "test");
+		this.date = new Date();
+		resource.addProperty("date", date);
+		resource.addProperty("long", new Long(0L));
 		resolver.addResource(resource);
 		MockResource child1 = new MockResource(resolver, TEST_PATH + "/child1",
 				"test");
@@ -127,6 +132,34 @@
 	}
 
 	@Test
+	public void testGetValue(){
+		log.info("testGetValue");
+		Resource resource = SlingFunctions.getResource(resolver, TEST_PATH);
+		ValueMap properties = resource.adaptTo(ValueMap.class);
+		
+		log.info("Testing using class coersion");
+		Date retrievedDate = SlingFunctions.getValue(properties, "date", Date.class);
+		assertEquals(date,retrievedDate);
+		assertTrue(retrievedDate instanceof Date);
+		
+		log.info("Testing with default value on existing key");
+		Long retrievedLong = SlingFunctions.getValue(properties, "long", new Long(-123L));
+		assertEquals(new Long(0L),retrievedLong);
+		assertTrue(retrievedLong instanceof Long);
+		
+		log.info("Testing with no value and class coersion");
+		Date fakeDate = SlingFunctions.getValue(properties, "date1", Date.class);
+		assertTrue(fakeDate == null);
+		
+		log.info("Testing with no value and default specified");
+		Long fakeLong = SlingFunctions.getValue(properties, "long1", new Long(-123L));
+		assertEquals(new Long(-123L),fakeLong);
+		assertTrue(fakeLong instanceof Long);
+
+		log.info("Tests successful!");
+	}
+	
+	@Test
 	public void testListChildResources() {
 		log.info("testListChildResources");
 		Iterator<Resource> children = SlingFunctions.listChildren(resource);