// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.enterprise.connector.util.filter;

import com.google.enterprise.connector.spi.Document;
import com.google.enterprise.connector.spi.Principal;
import com.google.enterprise.connector.spi.Property;
import com.google.enterprise.connector.spi.RepositoryException;
import com.google.enterprise.connector.spi.SimpleProperty;
import com.google.enterprise.connector.spi.SpiConstants;
import com.google.enterprise.connector.spi.Value;
import com.google.enterprise.connector.spi.SpiConstants.CaseSensitivityType;
import com.google.enterprise.connector.spiimpl.PrincipalValue;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 */
public class AclPropertyFilter extends AbstractDocumentFilter {

  /** The logger for this class. */
  private static final Logger LOGGER = Logger.getLogger(
      AclPropertyFilter.class.getName());

  /** case sensitivity type flag. */
  protected CaseSensitivityType caseSensitivityType;

  private static final Set<String> aclUsersGroups;

  static {
    aclUsersGroups = new HashSet<String>();
    aclUsersGroups.add(SpiConstants.PROPNAME_ACLUSERS);
    aclUsersGroups.add(SpiConstants.PROPNAME_ACLDENYUSERS);
    aclUsersGroups.add(SpiConstants.PROPNAME_ACLGROUPS);
    aclUsersGroups.add(SpiConstants.PROPNAME_ACLDENYGROUPS);
  }

  /**
   *
   */
  public void setCaseSensitivityType(String caseSensitivityType) {
    if (caseSensitivityType.equalsIgnoreCase(
            CaseSensitivityType.EVERYTHING_CASE_INSENSITIVE.toString())) {
      this.caseSensitivityType = 
          CaseSensitivityType.EVERYTHING_CASE_INSENSITIVE;
    } else if (caseSensitivityType.equalsIgnoreCase(
            CaseSensitivityType.EVERYTHING_CASE_SENSITIVE.toString())) {
      this.caseSensitivityType = CaseSensitivityType.EVERYTHING_CASE_SENSITIVE;
    }
  }

  /**
   * Finds a {@link Property} by {@code name}. If the requested property is 
   * ACL property, then checks for case sensitivity type and modifies the value
   * if different than specified in filter. Returns ACL property with modified 
   * values.
   * <p/>
   */
  @Override
  public Property findProperty(Document source, String name)
      throws RepositoryException {
    if (caseSensitivityType == null) {
      return source.findProperty(name);
    }

    if (aclUsersGroups.contains(name)) {
      List<Value> values = super.getPropertyValues(source, name);
      ArrayList<Value> newValues = new ArrayList<Value>(values.size());
      for (Value value : values) {
        Principal principal = (value instanceof PrincipalValue)
            ? ((PrincipalValue) value).getPrincipal()
            : new Principal(value.toString().trim());

        if (principal.getCaseSensitivityType() != caseSensitivityType) {
          if (LOGGER.isLoggable(Level.FINEST)) {
            LOGGER.finest("Changing " + principal.getName()
                + " caseSensitivityType to " + caseSensitivityType);
          }

          Principal newPrincipal = new Principal(principal.getPrincipalType(),
              principal.getNamespace(), principal.getName(),
                  caseSensitivityType);

          newValues.add(new PrincipalValue(newPrincipal));
        } else {
          newValues.add(new PrincipalValue(principal));
        }
      }
      return new SimpleProperty(newValues);
    } else {
      return source.findProperty(name);
    }
  }
}

@@ -1359,16 +1359,877 @@
 %0A%0A/**%0A *
+ A %7B@link Document%7D filter that forces the %7B@link CaseSensitivityType%7D field%0A * for all ACL %7B@link com.google.enterprise.connector.spi.Principal Principals%7D%0A * supplied by the connector to be set to a specified value.%0A * %3Cp/%3E%0A * This will over-ride any %7B@link CaseSensitivityType%7D that may have been set%0A * by the connector, and supply one if none was set by the connector.%0A * %3Cp/%3E%0A * %3Cb%3EExample %7B@code documentFilters.xml%7D Configurations:%3C/b%3E%0A * %3Cp/%3E%0A * The following example forces all ACL Principals for all fed documents to be%0A * considered case-insensitive.%0A * %3Cpre%3E%3Ccode%3E%0A   &lt;!-- Force case-insensitive ACLs. --&gt;%0A   &lt;bean id=%22CaseInsensitiveACLs%22%0A      class=%22com.google.enterprise.connector.util.filter.AclPropertyFilter%22&gt;%0A     &lt;property name=%22caseSensitivityType%22 value=%22everything-case-insensitive%22/&gt;%0A   &lt;/bean&gt;%0A   %3C/code%3E%3C/pre%3E
 %0A */%0Apub
@@ -2432,17 +2432,17 @@
 %0A%0A  /** 
-c
+C
 ase sens
@@ -2873,16 +2873,376 @@
 /**%0A   *
+ Sets the %7B@link CaseSensitivityType%7D to be used for all ACL%0A   * %7B@link com.google.enterprise.connector.spi.Principal Principals%7D%0A   * supplied by the connector.%0A   *%0A   * @param caseSensitivityType a String representation of a%0A   *        %7B@link CaseSensitivityType%7D; i.e. %7B@code everything-case-sensitive%7D%0A   *        or %7B@code everything-case-insensitive%7D.
 %0A   */%0A 
@@ -3353,36 +3353,32 @@
 reCase(%0A        
-    
 CaseSensitivityT
@@ -3566,28 +3566,24 @@
 IgnoreCase(%0A
-    
         Case

Fix bug 6494509: Add SPI javadoc for AclPropertyFilter. Code Review: http://codereview.appspot.com/6348051