FELIX-4060 : Fix servlet context DTOs and check servlet context helper name according to spec

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1661330 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
index cbf89c0..d7e43db 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
@@ -119,7 +119,7 @@
     protected String getStringProperty(final ServiceReference<T> ref, final String key)
     {
         final Object value = ref.getProperty(key);
-        return (value instanceof String) ? (String) value : null;
+        return (value instanceof String) ? ((String) value).trim(): null;
     }
 
     protected String[] getStringArrayProperty(ServiceReference<T> ref, String key)
@@ -128,11 +128,18 @@
 
         if (value instanceof String)
         {
-            return new String[] { (String) value };
+            return new String[] { ((String) value).trim() };
         }
         else if (value instanceof String[])
         {
-            return (String[]) value;
+            final String[] arr = (String[]) value;
+            for(int i=0; i<arr.length; i++)
+            {
+                if ( arr[i] != null )
+                {
+                    arr[i] = arr[i].trim();
+                }
+            }
         }
         else if (value instanceof Collection<?>)
         {
@@ -142,7 +149,7 @@
             int i = 0;
             for (Object current : collectionValues)
             {
-                values[i++] = current != null ? String.valueOf(current) : null;
+                values[i++] = current != null ? String.valueOf(current).trim() : null;
             }
 
             return values;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
index 9eaf2af..0df24f7 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
@@ -20,6 +20,7 @@
 
 import java.util.Map;
 
+import org.apache.felix.http.base.internal.util.PatternUtil;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.context.ServletContextHelper;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
@@ -68,7 +69,7 @@
     {
         if ( !this.isEmpty(path) )
         {
-        	if ( path.equals("/") ) 
+        	if ( path.equals("/") )
         	{
         		return true;
         	}
@@ -84,8 +85,9 @@
     @Override
     public boolean isValid()
     {
-        // TODO - check if name has valid value
-        return super.isValid() && !this.isEmpty(this.name) && isValidPath();
+        return super.isValid()
+                && PatternUtil.isValidSymbolicName(this.name)
+                && isValidPath();
     }
 
     public String getName()
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
index 80792e6..eb4dcc1 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
@@ -33,6 +33,12 @@
 import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.runtime.dto.ErrorPageDTO;
+import org.osgi.service.http.runtime.dto.FailedErrorPageDTO;
+import org.osgi.service.http.runtime.dto.FailedFilterDTO;
+import org.osgi.service.http.runtime.dto.FailedListenerDTO;
+import org.osgi.service.http.runtime.dto.FailedResourceDTO;
+import org.osgi.service.http.runtime.dto.FailedServletContextDTO;
+import org.osgi.service.http.runtime.dto.FailedServletDTO;
 import org.osgi.service.http.runtime.dto.FilterDTO;
 import org.osgi.service.http.runtime.dto.ListenerDTO;
 import org.osgi.service.http.runtime.dto.ResourceDTO;
@@ -64,12 +70,12 @@
         RuntimeDTO runtimeDTO = new RuntimeDTO();
         runtimeDTO.attributes = createAttributes();
         //TODO <**
-        runtimeDTO.failedErrorPageDTOs = null;
-        runtimeDTO.failedFilterDTOs = null;
-        runtimeDTO.failedListenerDTOs = null;
-        runtimeDTO.failedResourceDTOs = null;
-        runtimeDTO.failedServletContextDTOs = null;
-        runtimeDTO.failedServletDTOs = null;
+        runtimeDTO.failedErrorPageDTOs = new FailedErrorPageDTO[0];
+        runtimeDTO.failedFilterDTOs = new FailedFilterDTO[0];
+        runtimeDTO.failedListenerDTOs = new FailedListenerDTO[0];
+        runtimeDTO.failedResourceDTOs = new FailedResourceDTO[0];
+        runtimeDTO.failedServletContextDTOs = new FailedServletContextDTO[0];
+        runtimeDTO.failedServletDTOs = new FailedServletDTO[0];
         //**>
         runtimeDTO.servletContextDTOs = createContextDTOs();
         return runtimeDTO;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java b/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
index 7ff1d32..708c628 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
@@ -18,9 +18,11 @@
  */
 package org.apache.felix.http.base.internal.util;
 
+import java.util.StringTokenizer;
+
 /**
  * Some convenience utilities to deal with path patterns.
- * 
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class PatternUtil
@@ -32,11 +34,81 @@
         // see Servlet 3.0, section 12.2
         // - replace '*.' prefixes with a regex that matches extensions...
         result = result.replaceFirst("^\\Q*.\\E(.*)$", "\\^(.*)(\\\\.\\\\Q$1\\\\E)\\$");
-        // - replace '/*' suffixes with a regex that matches paths (actually, 
-        //   the path should also start with a leading slash, but we're a bit 
+        // - replace '/*' suffixes with a regex that matches paths (actually,
+        //   the path should also start with a leading slash, but we're a bit
         //   more liberal on this one)...
         result = result.replaceFirst("^(.*)\\Q/*\\E$", "\\^($1)(|/.*)\\$");
         return result;
     }
 
+    // check for valid symbolic name
+    public static boolean isValidSymbolicName(final String name)
+    {
+        if ( name == null || name.isEmpty() )
+        {
+            return false;
+        }
+        boolean valid = true;
+        boolean expectToken = false;
+        boolean done = false;
+        final StringTokenizer st = new StringTokenizer(name, ".", true);
+        while ( !done && st.hasMoreTokens() )
+        {
+            final String token = st.nextToken();
+            if ( expectToken )
+            {
+                if ( !".".equals(token) )
+                {
+                    valid = false;
+                    done = true;
+                }
+                else
+                {
+                    expectToken = false;
+                }
+            }
+            else
+            {
+                if ( ".".equals(token) )
+                {
+                    valid = false;
+                    done = true;
+                }
+                else
+                {
+                    int i = 0;
+                    while ( i < token.length() && valid )
+                    {
+                        final char c = token.charAt(i);
+                        i++;
+                        if ( c >= 'a' && c <= 'z' )
+                        {
+                            continue;
+                        }
+                        if ( c >= 'A' && c <= 'Z' )
+                        {
+                            continue;
+                        }
+                        if ( c >= '0' && c <= '9' )
+                        {
+                            continue;
+                        }
+                        if ( c == '-' || c == '_' )
+                        {
+                            continue;
+                        }
+                        valid = false;
+                        done = true;
+                    }
+                }
+                expectToken = true;
+            }
+        }
+        if ( !expectToken )
+        {
+            valid = false;
+        }
+
+        return valid;
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
index a31484d..d756fe2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
@@ -513,7 +513,10 @@
         {
             for (List<ContextHandler> contextHandlerList : this.contextMap.values())
             {
-                contextHandlers.addAll(contextHandlerList);
+                if ( !contextHandlerList.isEmpty() )
+                {
+                    contextHandlers.add(contextHandlerList.get(0));
+                }
             }
             handlerRuntimes = registry.getRuntime();
             listenerRuntimes = listenerRegistry.getContextRuntimes();
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java
index 5ebc971..602906e 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java
@@ -29,7 +29,7 @@
 
 /**
  * Test cases for {@link PatternUtil}.
- * 
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class PatternUtilTest
@@ -71,4 +71,13 @@
         assertFalse(p6.matcher("/index.gz").matches());
     }
 
+    @Test
+    public void testSymbolicName()
+    {
+        assertTrue(PatternUtil.isValidSymbolicName("default"));
+        assertFalse(PatternUtil.isValidSymbolicName("$bad#"));
+        assertTrue(PatternUtil.isValidSymbolicName("abcdefghijklmnopqrstuvwyz"));
+        assertTrue(PatternUtil.isValidSymbolicName("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+        assertTrue(PatternUtil.isValidSymbolicName("0123456789-_"));
+    }
 }