]> WPIA git - gigi.git/blobdiff - lib/jetty/org/eclipse/jetty/util/IPAddressMap.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / util / IPAddressMap.java
diff --git a/lib/jetty/org/eclipse/jetty/util/IPAddressMap.java b/lib/jetty/org/eclipse/jetty/util/IPAddressMap.java
new file mode 100644 (file)
index 0000000..7cbbcab
--- /dev/null
@@ -0,0 +1,364 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+
+/* ------------------------------------------------------------ */
+/**
+ * Internet address map to object
+ * <p>
+ * Internet addresses may be specified as absolute address or as a combination of 
+ * four octet wildcard specifications (a.b.c.d) that are defined as follows.
+ * </p>
+ * <pre>
+ * nnn - an absolute value (0-255)
+ * mmm-nnn - an inclusive range of absolute values, 
+ *           with following shorthand notations:
+ *           nnn- => nnn-255
+ *           -nnn => 0-nnn
+ *           -    => 0-255
+ * a,b,... - a list of wildcard specifications
+ * </pre>
+ */
+@SuppressWarnings("serial")
+public class IPAddressMap<TYPE> extends HashMap<String, TYPE>
+{
+    private final HashMap<String,IPAddrPattern> _patterns = new HashMap<String,IPAddrPattern>();
+
+    /* --------------------------------------------------------------- */
+    /** Construct empty IPAddressMap.
+     */
+    public IPAddressMap()
+    {
+        super(11);
+    }
+   
+    /* --------------------------------------------------------------- */
+    /** Construct empty IPAddressMap.
+     * 
+     * @param capacity initial capacity
+     */
+    public IPAddressMap(int capacity)
+    {
+        super (capacity);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Insert a new internet address into map
+     * 
+     * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
+     */
+    @Override
+    public TYPE put(String addrSpec, TYPE object)
+        throws IllegalArgumentException
+    {
+        if (addrSpec == null || addrSpec.trim().length() == 0)
+            throw new IllegalArgumentException("Invalid IP address pattern: "+addrSpec);
+        
+        String spec = addrSpec.trim();
+        if (_patterns.get(spec) == null)
+            _patterns.put(spec,new IPAddrPattern(spec));
+        
+        return super.put(spec, object);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Retrieve the object mapped to the specified internet address literal
+     * 
+     * @see java.util.HashMap#get(java.lang.Object)
+     */
+    @Override
+    public TYPE get(Object key)
+    {
+        return super.get(key);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Retrieve the first object that is associated with the specified 
+     * internet address by taking into account the wildcard specifications.
+     * 
+     * @param addr internet address
+     * @return associated object
+     */
+    public TYPE match(String addr)
+    {
+        Map.Entry<String, TYPE> entry = getMatch(addr);
+        return entry==null ? null : entry.getValue();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Retrieve the first map entry that is associated with the specified 
+     * internet address by taking into account the wildcard specifications.
+     * 
+     * @param addr internet address
+     * @return map entry associated
+     */
+    public Map.Entry<String, TYPE> getMatch(String addr)
+    {
+        if (addr != null)
+        {
+            for(Map.Entry<String, TYPE> entry: super.entrySet())
+            {
+                if (_patterns.get(entry.getKey()).match(addr))
+                {
+                    return entry;
+                }
+            }
+        }
+        return null;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Retrieve a lazy list of map entries associated with specified
+     * internet address by taking into account the wildcard specifications.
+     * 
+     * @param addr  internet address
+     * @return lazy list of map entries
+     */
+    public Object getLazyMatches(String addr)
+    {
+        if (addr == null)
+            return LazyList.getList(super.entrySet());
+        
+        Object entries = null;
+        for(Map.Entry<String, TYPE> entry: super.entrySet())
+        {
+            if (_patterns.get(entry.getKey()).match(addr))
+            {
+                entries = LazyList.add(entries,entry);
+            }
+        }
+        return entries;        
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * IPAddrPattern
+     * 
+     * Represents internet address wildcard. 
+     * Matches the wildcard to provided internet address.
+     */
+    private static class IPAddrPattern
+    {
+        private final OctetPattern[] _octets = new OctetPattern[4];
+        /* ------------------------------------------------------------ */
+        /**
+         * Create new IPAddrPattern
+         * 
+         * @param value internet address wildcard specification
+         * @throws IllegalArgumentException if wildcard specification is invalid
+         */
+        public IPAddrPattern(String value)
+            throws IllegalArgumentException
+        {
+            if (value == null || value.trim().length() == 0)
+                throw new IllegalArgumentException("Invalid IP address pattern: "+value);
+                
+            try
+            {
+                StringTokenizer parts = new StringTokenizer(value, ".");
+                
+                String part;
+                for (int idx=0; idx<4; idx++)
+                {
+                    part = parts.hasMoreTokens() ? parts.nextToken().trim() : "0-255";
+                    
+                    int len = part.length();
+                    if (len == 0 && parts.hasMoreTokens())
+                        throw new IllegalArgumentException("Invalid IP address pattern: "+value);
+                    
+                    _octets[idx] = new OctetPattern(len==0 ? "0-255" : part);
+                }
+            }
+            catch (IllegalArgumentException ex)
+            {
+                throw new IllegalArgumentException("Invalid IP address pattern: "+value, ex);
+            }
+        }
+        
+        /* ------------------------------------------------------------ */
+        /**
+         * Match the specified internet address against the wildcard
+         * 
+         * @param value internet address
+         * @return true if specified internet address matches wildcard specification
+         * 
+         * @throws IllegalArgumentException if specified internet address is invalid
+         */
+        public boolean match(String value)
+            throws IllegalArgumentException
+        {
+            if (value == null || value.trim().length() == 0)
+                throw new IllegalArgumentException("Invalid IP address: "+value);
+            
+            try
+            {
+                StringTokenizer parts = new StringTokenizer(value, ".");
+                
+                boolean result = true;
+                for (int idx=0; idx<4; idx++)
+                {
+                    if (!parts.hasMoreTokens())
+                        throw new IllegalArgumentException("Invalid IP address: "+value);
+                        
+                    if (!(result &= _octets[idx].match(parts.nextToken())))
+                        break;
+                }
+                return result;
+            }
+            catch (IllegalArgumentException ex)
+            {
+                throw new IllegalArgumentException("Invalid IP address: "+value, ex);
+            }
+        }
+    }
+        
+    /* ------------------------------------------------------------ */
+    /**
+     * OctetPattern
+     * 
+     * Represents a single octet wildcard.
+     * Matches the wildcard to the specified octet value.
+     */
+    private static class OctetPattern extends BitSet
+    {
+        private final BitSet _mask = new BitSet(256);
+        
+        /* ------------------------------------------------------------ */
+        /**
+         * Create new OctetPattern
+         * 
+         * @param octetSpec octet wildcard specification
+         * @throws IllegalArgumentException if wildcard specification is invalid
+         */
+        public OctetPattern(String octetSpec)
+            throws IllegalArgumentException
+        {
+            try
+            {
+                if (octetSpec != null)
+                {
+                    String spec = octetSpec.trim();
+                    if(spec.length() == 0)
+                    {
+                        _mask.set(0,255);
+                    }
+                    else
+                    {
+                        StringTokenizer parts = new StringTokenizer(spec,",");
+                        while (parts.hasMoreTokens())
+                        {
+                            String part = parts.nextToken().trim();
+                            if (part.length() > 0)
+                            {
+                                if (part.indexOf('-') < 0)
+                                {
+                                    Integer value = Integer.valueOf(part);
+                                    _mask.set(value);
+                                }
+                                else
+                                {
+                                    int low = 0, high = 255;
+                                    
+                                    String[] bounds = part.split("-",-2);
+                                    if (bounds.length != 2)
+                                    {
+                                        throw new IllegalArgumentException("Invalid octet spec: "+octetSpec);
+                                    }
+                                    
+                                    if (bounds[0].length() > 0)
+                                    {
+                                        low = Integer.parseInt(bounds[0]);
+                                    }
+                                    if (bounds[1].length() > 0)
+                                    {
+                                        high = Integer.parseInt(bounds[1]);
+                                    }
+                                    
+                                    if (low > high)
+                                    {
+                                        throw new IllegalArgumentException("Invalid octet spec: "+octetSpec);
+                                    }
+                                    
+                                    _mask.set(low, high+1);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            catch (NumberFormatException ex)
+            {
+                throw new IllegalArgumentException("Invalid octet spec: "+octetSpec, ex);
+            }
+        }
+        
+        /* ------------------------------------------------------------ */
+        /**
+         * Match specified octet value against the wildcard
+         * 
+         * @param value octet value
+         * @return true if specified octet value matches the wildcard
+         * @throws IllegalArgumentException if specified octet value is invalid
+         */
+        public boolean match(String value)
+            throws IllegalArgumentException
+        {
+            if (value == null || value.trim().length() == 0)
+                throw new IllegalArgumentException("Invalid octet: "+value);
+
+            try
+            {
+                int number = Integer.parseInt(value);
+                return match(number);
+            }
+            catch (NumberFormatException ex)
+            {
+                throw new IllegalArgumentException("Invalid octet: "+value);
+            }
+        }
+        
+        /* ------------------------------------------------------------ */
+        /**
+         * Match specified octet value against the wildcard
+         * 
+         * @param number octet value
+         * @return true if specified octet value matches the wildcard
+         * @throws IllegalArgumentException if specified octet value is invalid
+         */
+        public boolean match(int number)
+            throws IllegalArgumentException
+        {
+            if (number < 0 || number > 255)
+                throw new IllegalArgumentException("Invalid octet: "+number);
+            
+            return _mask.get(number);
+        }
+    }   
+}