<commit_before>/*
 * $Id$
 */
package org.xins.server;

import java.util.StringTokenizer;
import org.apache.oro.text.regex.Perl5Pattern;
import org.xins.util.MandatoryArgumentChecker;
import org.xins.util.text.FastStringBuffer;
import org.xins.util.text.ParseException;
import org.xins.util.text.SimplePatternParser;

/**
 * Access rule. This class can take a character string to produce an
 * {@link AccessRule} object from it.
 *
 * <h3>Descriptor format</h3>
 *
 * <p>A descriptor must comply to the following format:
 * <ul>
 *    <li>start with either <code>"allow"</code> or <code>"deny"</code>;
 *    <li>followed by any number of white space characters;
 *    <li>followed by a valid IP address;
 *    <li>followed by a slash character (<code>'/'</code>);
 *    <li>followed by a mask between 0 and 32 in decimal format, no leading zeroes;
 *    <li>followed by any number of white space characters;
 *    <li>followed by a simple pattern, see class {@link SimplePatternParser}.
 * </ul>
 *
 * <h3>Descriptor examples</h3>
 *
 * <p>Example of access rule descriptors:
 *
 * <dl>
 *    <dt><code>"allow&nbsp;172.16.58.3/32 *"</code></dt>
 *    <dd>Allows 172.16.58.3 to access any function.</dd>
 *
 *    <dt><code>"deny&nbsp;&nbsp;172.16.58.3/24\t_*"</code></dt>
 *    <dd>Denies all 194.134.168.x IP addresses to access any function
 *        starting with an underscore (<code>'_'</code>).</dd>
 * </dl>
 *
 * @version $Revision$ $Date$
 * @author <NAME> (<a href="mailto:<EMAIL>"><EMAIL></a>)
 * @author <NAME> (<a href="mailto:<EMAIL>"><EMAIL></a>)
 */
public final class AccessRule
extends Object {

   //-------------------------------------------------------------------------
   // Class fields
   //-------------------------------------------------------------------------

   //-------------------------------------------------------------------------
   // Class functions
   //-------------------------------------------------------------------------

   /**
    * Parses the specified character string to construct a new
    * <code>AccessRule</code> object.
    *
    * @param descriptor
    *    the access rule descriptor, the character string to parse, cannot be <code>null</code>.
    *    It also cannot be empty <code>(" ")</code>.
    *
    * @return
    *    an {@link AccessRule} instance, never <code>null</code>.
    *
    * @throws IllegalArgumentException
    *    if <code>descriptor == null</code>.
    *
    * @throws ParseException
    *    If there was a parsing error.
    */
   public static AccessRule parseAccessRule(String descriptor)
   throws IllegalArgumentException, ParseException {

      // Check preconditions
      MandatoryArgumentChecker.check("descriptor", descriptor);

      StringTokenizer tokenizer = new StringTokenizer(descriptor," \t\n\r");

      // Determine if it is an 'allow' or a 'deny' rule
      boolean allow;
      String token = nextToken(tokenizer);
      if ("allow".equals(token)) {
         allow = true;
      } else if ("deny".equals(token)) {
         allow = false;
      } else {
         throw new ParseException("First token of descriptor is \"" + token + "\", instead of either 'allow' or 'deny'.");
      }
      FastStringBuffer asString = new FastStringBuffer(40, token);

      // Determine the IP address to be checked
      token = nextToken(tokenizer);
      IPFilter filter = IPFilter.parseIPFilter(token);
      asString.append(' ');
      asString.append(filter.toString());

      // Determine the function the access is to be checked for
      token = nextToken(tokenizer);
      Perl5Pattern pattern = new SimplePatternParser().parseSimplePattern(token);
      asString.append(' ');
      asString.append(token);

      return new AccessRule(allow, filter, pattern, asString.toString());
   }

   /**
    * Returns the next token in the descriptor
    *
    * @param tokenizer
    *   The StringTokenizer to retrieve the next token from
    *
    * @return 
    *   The next token. Never <code>null</code>.
    *
    * @throws ParseException
    *   If <code>tokenizer.hasMoreTokens() == false</code>.
    */
   private static String nextToken(StringTokenizer tokenizer)
   throws ParseException {

      if (!tokenizer.hasMoreTokens()) {
         throw new ParseException("Too few tokens retrieved from the descriptor.");
      } else {
         return tokenizer.nextToken();
      }
   }


   //-------------------------------------------------------------------------
   // Constructors
   //-------------------------------------------------------------------------

   /**
    * Constructs a new <code>AccessRule</code>.
    *
    * @param allow
    *    flag that indicates if this rule grants access (<code>true</code>) or
    *    denies access (<code>false</code>).
    *
    * @param ipFilter
    *    filter used for matching (or not) IP addresses, cannot be
    *    <code>null</code>.
    *
    * @param functionNamePattern
    *    regular expression used for matching (or not) a function name; cannot be <code>null</code>.
    *
    * @throws IllegalArgumentException
    *    if <code>ipFilter == null || functionNamePattern == null</code>.
    */
   private AccessRule(boolean      allow,
                      IPFilter     ipFilter,
                      Perl5Pattern functionNamePattern,
                      String       asString)
   throws IllegalArgumentException {

      // Check preconditions
      MandatoryArgumentChecker.check("ipFilter", ipFilter,
                                     "functionNamePattern", functionNamePattern);

      _ipFilter = ipFilter;
      _allow    = allow;
      _asString = asString;
   }


   //-------------------------------------------------------------------------
   // Fields
   //-------------------------------------------------------------------------

   /**
    * The IP address filter used to create the access rule. Cannot be
    * <code>null</code>.
    */
   private final IPFilter _ipFilter;

   /**
    * If the access method is 'allow' or not.
    */
   private final boolean _allow;

   /**
    * String representation of this object. Cannot be <code>null</code>.
    */
   private final String _asString;


   //-------------------------------------------------------------------------
   // Methods
   //-------------------------------------------------------------------------

   /**
    * Returns if this rule is an <em>allow</em> or a <em>deny</em> rule.
    *
    * @return
    *    <code>true</code> if this is an <em>allow</em> rule, or
    *    <code>false</code> if this is a <em>deny</em> rule.
    */
   public boolean isAllowRule() {
      return _allow;
   }

   /**
    * Returns the IP filter.
    *
    * @return
    *    the IP filter, cannot be <code>null</code>.
    */
   public IPFilter getIPFilter() {
      return _ipFilter;
   }

   /**
    * Determines if the specified IP address and function match this rule.
    *
    * @param ip
    *    the IP address to match, cannot be <code>null</code>.
    *
    * @param functionName
    *    the name of the function to match, cannot be <code>null</code>.
    *
    * @return
    *    <code>true</code> if this rule matches, <code>false</code> otherwise.
    *
    * @throws IllegalArgumentException
    *    if <code>ip == null || functionName == null</code>.
    */
   public boolean match(String ip, String functionName)
   throws IllegalArgumentException {

      // Check preconditions
      MandatoryArgumentChecker.check("ip", ip, "functionName", functionName);

      return false; // TODO
   }

   /**
    * Returns a character string representation of this object. The returned
    * string is in the form:
    *
    * <blockquote><em>type a.b.c.d/m pattern</em></blockquote>
    *
    * where <em>type</em> is either <code>"allow"</code> or
    * <code>"deny"</code>, <em>a.b.c.d</em> is the base IP address, <em>m</em>
    * is the mask, and <em>pattern</em> is the function name simple pattern.
    *
    * @return
    *    a character string representation of this access rule, never
    *    <code>null</code>.
    */
   public String toString() {
      return _asString;
   }
}
<commit_msg>Checking function name pattern too.<commit_after>/*
 * $Id$
 */
package org.xins.server;

import java.util.StringTokenizer;
import org.apache.log4j.Logger;
import org.apache.oro.text.regex.Perl5Matcher;
import org.apache.oro.text.regex.Perl5Pattern;
import org.xins.util.MandatoryArgumentChecker;
import org.xins.util.text.FastStringBuffer;
import org.xins.util.text.ParseException;
import org.xins.util.text.SimplePatternParser;

/**
 * Access rule. This class can take a character string to produce an
 * {@link AccessRule} object from it.
 *
 * <h3>Descriptor format</h3>
 *
 * <p>A descriptor must comply to the following format:
 * <ul>
 *    <li>start with either <code>"allow"</code> or <code>"deny"</code>;
 *    <li>followed by any number of white space characters;
 *    <li>followed by a valid IP address;
 *    <li>followed by a slash character (<code>'/'</code>);
 *    <li>followed by a mask between 0 and 32 in decimal format, no leading zeroes;
 *    <li>followed by any number of white space characters;
 *    <li>followed by a simple pattern, see class {@link SimplePatternParser}.
 * </ul>
 *
 * <h3>Descriptor examples</h3>
 *
 * <p>Example of access rule descriptors:
 *
 * <dl>
 *    <dt><code>"allow&nbsp;172.16.58.3/32 *"</code></dt>
 *    <dd>Allows 172.16.58.3 to access any function.</dd>
 *
 *    <dt><code>"deny&nbsp;&nbsp;172.16.58.3/24\t_*"</code></dt>
 *    <dd>Denies all 194.134.168.x IP addresses to access any function
 *        starting with an underscore (<code>'_'</code>).</dd>
 * </dl>
 *
 * @version $Revision$ $Date$
 * @author <NAME> (<a href="mailto:<EMAIL>"><EMAIL></a>)
 * @author <NAME> (<a href="mailto:<EMAIL>"><EMAIL></a>)
 */
public final class AccessRule
extends Object {

   //-------------------------------------------------------------------------
   // Class fields
   //-------------------------------------------------------------------------

   /**
    * Log for this class.
    */
   private static final Logger LOG = Logger.getLogger(AccessRule.class.getName());

   /**
    * Pattern matcher.
    */
   private static final Perl5Matcher PATTERN_MATCHER = new Perl5Matcher();


   //-------------------------------------------------------------------------
   // Class functions
   //-------------------------------------------------------------------------

   /**
    * Parses the specified character string to construct a new
    * <code>AccessRule</code> object.
    *
    * @param descriptor
    *    the access rule descriptor, the character string to parse, cannot be <code>null</code>.
    *    It also cannot be empty <code>(" ")</code>.
    *
    * @return
    *    an {@link AccessRule} instance, never <code>null</code>.
    *
    * @throws IllegalArgumentException
    *    if <code>descriptor == null</code>.
    *
    * @throws ParseException
    *    If there was a parsing error.
    */
   public static AccessRule parseAccessRule(String descriptor)
   throws IllegalArgumentException, ParseException {

      // Check preconditions
      MandatoryArgumentChecker.check("descriptor", descriptor);

      StringTokenizer tokenizer = new StringTokenizer(descriptor," \t\n\r");

      // Determine if it is an 'allow' or a 'deny' rule
      boolean allow;
      String token = nextToken(tokenizer);
      if ("allow".equals(token)) {
         allow = true;
      } else if ("deny".equals(token)) {
         allow = false;
      } else {
         throw new ParseException("First token of descriptor is \"" + token + "\", instead of either 'allow' or 'deny'.");
      }
      FastStringBuffer asString = new FastStringBuffer(40, token);

      // Determine the IP address to be checked
      token = nextToken(tokenizer);
      IPFilter filter = IPFilter.parseIPFilter(token);
      asString.append(' ');
      asString.append(filter.toString());

      // Determine the function the access is to be checked for
      token = nextToken(tokenizer);
      Perl5Pattern pattern = new SimplePatternParser().parseSimplePattern(token);
      asString.append(' ');
      asString.append(token);

      return new AccessRule(allow, filter, pattern, asString.toString());
   }

   /**
    * Returns the next token in the descriptor
    *
    * @param tokenizer
    *   The StringTokenizer to retrieve the next token from
    *
    * @return 
    *   The next token. Never <code>null</code>.
    *
    * @throws ParseException
    *   If <code>tokenizer.hasMoreTokens() == false</code>.
    */
   private static String nextToken(StringTokenizer tokenizer)
   throws ParseException {

      if (!tokenizer.hasMoreTokens()) {
         throw new ParseException("Too few tokens retrieved from the descriptor.");
      } else {
         return tokenizer.nextToken();
      }
   }


   //-------------------------------------------------------------------------
   // Constructors
   //-------------------------------------------------------------------------

   /**
    * Constructs a new <code>AccessRule</code>.
    *
    * @param allow
    *    flag that indicates if this rule grants access (<code>true</code>) or
    *    denies access (<code>false</code>).
    *
    * @param ipFilter
    *    filter used for matching (or not) IP addresses, cannot be
    *    <code>null</code>.
    *
    * @param functionNamePattern
    *    regular expression used for matching (or not) a function name; cannot be <code>null</code>.
    *
    * @throws IllegalArgumentException
    *    if <code>ipFilter == null || functionNamePattern == null</code>.
    */
   private AccessRule(boolean      allow,
                      IPFilter     ipFilter,
                      Perl5Pattern functionNamePattern,
                      String       asString)
   throws IllegalArgumentException {

      // Check preconditions
      MandatoryArgumentChecker.check("ipFilter", ipFilter,
                                     "functionNamePattern", functionNamePattern);

      // Store the data
      _allow               = allow;
      _ipFilter            = ipFilter;
      _functionNamePattern = functionNamePattern;
      _asString            = asString;
   }


   //-------------------------------------------------------------------------
   // Fields
   //-------------------------------------------------------------------------

   /**
    * If the access method is 'allow' or not.
    */
   private final boolean _allow;

   /**
    * The IP address filter used to create the access rule. Cannot be
    * <code>null</code>.
    */
   private final IPFilter _ipFilter;

   /**
    * The function name pattern. Cannot be <code>null</code>.
    */
   private final Perl5Pattern _functionNamePattern;

   /**
    * String representation of this object. Cannot be <code>null</code>.
    */
   private final String _asString;


   //-------------------------------------------------------------------------
   // Methods
   //-------------------------------------------------------------------------

   /**
    * Returns if this rule is an <em>allow</em> or a <em>deny</em> rule.
    *
    * @return
    *    <code>true</code> if this is an <em>allow</em> rule, or
    *    <code>false</code> if this is a <em>deny</em> rule.
    */
   public boolean isAllowRule() {
      return _allow;
   }

   /**
    * Returns the IP filter.
    *
    * @return
    *    the IP filter, cannot be <code>null</code>.
    */
   public IPFilter getIPFilter() {
      return _ipFilter;
   }

   /**
    * Determines if the specified IP address and function match this rule.
    *
    * @param ip
    *    the IP address to match, cannot be <code>null</code>.
    *
    * @param functionName
    *    the name of the function to match, cannot be <code>null</code>.
    *
    * @return
    *    <code>true</code> if this rule matches, <code>false</code> otherwise.
    *
    * @throws IllegalArgumentException
    *    if <code>ip == null || functionName == null</code>.
    *
    * @throws ParseException
    *    if the specified IP address cannot be parsed.
    */
   public boolean match(String ip, String functionName)
   throws IllegalArgumentException, ParseException {

      // Check preconditions
      MandatoryArgumentChecker.check("ip", ip, "functionName", functionName);

      boolean matchIP       = _ipFilter.match(ip);
      boolean matchFunction = PATTERN_MATCHER.matches(functionName, _functionNamePattern);

System.out.println("AccessRule \"" + _asString + "\" IP=\"" + ip + "\"; function=\"" + functionName + "\": IP match=" + matchIP + "; Function match=" + matchFunction + '.');
      if (LOG.isDebugEnabled()) {
         LOG.debug("AccessRule \"" + _asString + "\" IP=\"" + ip + "\"; function=\"" + functionName + "\": IP match=" + matchIP + "; Function match=" + matchFunction + '.');
      }

      return matchIP && matchFunction;
   }

   /**
    * Returns a character string representation of this object. The returned
    * string is in the form:
    *
    * <blockquote><em>type a.b.c.d/m pattern</em></blockquote>
    *
    * where <em>type</em> is either <code>"allow"</code> or
    * <code>"deny"</code>, <em>a.b.c.d</em> is the base IP address, <em>m</em>
    * is the mask, and <em>pattern</em> is the function name simple pattern.
    *
    * @return
    *    a character string representation of this access rule, never
    *    <code>null</code>.
    */
   public String toString() {
      return _asString;
   }
}

{'fraction_non_alphanumeric': 0.20112910583941607, 'fraction_numerical': 0.005873631386861314, 'mean_word_length': 1.9010752688172043, 'pattern_counts': {'":': 2, '<': 243, '<?xml version=': 0, '>': 243, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '934004', 'n_tokens_mistral': 4911, 'n_tokens_neox': 4749, 'n_words': 1403}