001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.model.filter; 021 022 023import java.text.Format; 024import java.text.MessageFormat; 025 026 027/** 028 * An encoder for LDAP filters. 029 * 030 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 031 */ 032public class FilterEncoder 033{ 034 private static final String[] EMPTY = new String[0]; 035 036 037 /** 038 * Formats a filter and handles encoding of special characters in the value arguments using the 039 * <valueencoding> rule as described in <a href="http://www.ietf.org/rfc/rfc4515.txt">RFC 4515</a>. 040 * <p> 041 * Example of filter template format: <code>(&(cn={0})(uid={1}))</code> 042 * 043 * @param filterTemplate the filter with placeholders 044 * @param values the values to encode and substitute 045 * @return the formatted filter with escaped values 046 * @throws IllegalArgumentException if the number of values does not match the number of placeholders in the template 047 */ 048 public static String format( String filterTemplate, String... values ) throws IllegalArgumentException 049 { 050 if ( values == null ) 051 { 052 values = EMPTY; 053 } 054 055 MessageFormat mf = new MessageFormat( filterTemplate ); 056 057 // check element count and argument count 058 Format[] formats = mf.getFormatsByArgumentIndex(); 059 if ( formats.length != values.length ) 060 { 061 // TODO: I18n 062 String msg = "Filter template {0} has {1} placeholders but {2} arguments provided."; 063 throw new IllegalArgumentException( MessageFormat.format( msg, filterTemplate, formats.length, 064 values.length ) ); 065 } 066 067 // encode arguments 068 for ( int i = 0; i < values.length; i++ ) 069 { 070 values[i] = encodeFilterValue( values[i] ); 071 } 072 073 // format the filter 074 String format = mf.format( values ); 075 return format; 076 } 077 078 079 /** 080 * Handles encoding of special characters in LDAP search filter assertion values using the 081 * <valueencoding> rule as described in <a href="http://www.ietf.org/rfc/rfc4515.txt">RFC 4515</a>. 082 * 083 * @param value Right hand side of "attrId=value" assertion occurring in an LDAP search filter. 084 * @return Escaped version of <code>value</code> 085 */ 086 public static String encodeFilterValue( String value ) 087 { 088 StringBuilder sb = null; 089 090 for ( int i = 0; i < value.length(); i++ ) 091 { 092 char ch = value.charAt( i ); 093 String replace = null; 094 095 switch ( ch ) 096 { 097 case '*': 098 replace = "\\2A"; 099 break; 100 101 case '(': 102 replace = "\\28"; 103 break; 104 105 case ')': 106 replace = "\\29"; 107 break; 108 109 case '\\': 110 replace = "\\5C"; 111 break; 112 113 case '\0': 114 replace = "\\00"; 115 break; 116 } 117 118 if ( replace != null ) 119 { 120 if ( sb == null ) 121 { 122 sb = new StringBuilder( value.length() * 2 ); 123 sb.append( value.substring( 0, i ) ); 124 } 125 sb.append( replace ); 126 } 127 else if ( sb != null ) 128 { 129 sb.append( ch ); 130 } 131 } 132 133 return ( sb == null ? value : sb.toString() ); 134 } 135}