/************************************************************************* * Copyright 2009-2012 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.compute.common.internal.tags; import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; import com.google.common.base.CharMatcher; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; /** * Methods for working with {@link Filter}s */ public class Filters { public static final String DEFAULT_FILTERS = "default"; /** * Generate a Filter for the given filters. * * @param filters The filter items * @param resourceType The resource class to be filtered * @return The filter * @throws InvalidFilterException If a filter is invalid */ @Nonnull public static Filter generate( final Iterable<com.eucalyptus.compute.common.Filter> filters, final Class<?> resourceType ) throws InvalidFilterException { return generate( filters, resourceType, DEFAULT_FILTERS ); } /** * Generate a Filter for the given filters. * * @param filters The filter items * @param resourceType The resource class to be filtered * @param qualifier The filter qualifier (in case of multiple filter sets for a type) * @return The filter * @throws InvalidFilterException If a filter is invalid */ @Nonnull public static Filter generate( final Iterable<com.eucalyptus.compute.common.Filter> filters, final Class<?> resourceType, final String qualifier ) throws InvalidFilterException { return generateFor( filters, resourceType, qualifier ).generate(); } /** * Get a FiltersBuilder for the given filters. * * @param filters The filter items * @param resourceType The resource class to be filtered * @return The filter */ @Nonnull public static FiltersBuilder generateFor( final Iterable<com.eucalyptus.compute.common.Filter> filters, final Class<?> resourceType ) { return generateFor( filters, resourceType, DEFAULT_FILTERS ); } /** * Get a FiltersBuilder for the given filters. * * @param filters The filter items * @param resourceType The resource class to be filtered * @param qualifier The filter qualifier (in case of multiple filter sets for a type) * @return The filter */ @Nonnull public static FiltersBuilder generateFor( final Iterable<com.eucalyptus.compute.common.Filter> filters, final Class<?> resourceType, final String qualifier ) { return new FiltersBuilder( filters, resourceType, qualifier ); } /** * Escape any wildcards in a filter value so it can be used as a literal. * * <p>Escapes \ * and ? using a \<\p> * * @param filterValue The value to escape * @return The escaped filter value */ @Nonnull public static String escape( @Nonnull final CharSequence filterValue ) { final String escaped; final CharMatcher syntaxMatcher = CharMatcher.anyOf("\\*?"); if ( syntaxMatcher.matchesAnyOf( filterValue ) ) { final StringBuilder escapedBuffer = new StringBuilder( filterValue.length( ) + 8 ); for ( int i=0; i<filterValue.length(); i++ ) { final char character = filterValue.charAt( i ); switch ( character ) { case '\\': case '*': case '?': escapedBuffer.append( '\\' ); // fall through default: escapedBuffer.append( character ); } } escaped = escapedBuffer.toString( ); } else { escaped = filterValue.toString( ); } return escaped; } public static class FiltersBuilder { private final Iterable<com.eucalyptus.compute.common.Filter> filters; private final Class<?> resourceType; private final String qualifier; private final Map<String,Set<String>> internalFilters = Maps.newHashMap(); public FiltersBuilder( final Iterable<com.eucalyptus.compute.common.Filter> filters, final Class<?> resourceType, final String qualifier ) { this.filters = filters; this.resourceType = resourceType; this.qualifier = qualifier; } /** * Add internal filters with wildcard support if any values present. * * @param name The filter name * @param values The filter values with wildcards * @return This builder for call chaining */ @Nonnull public FiltersBuilder withOptionalInternalFilter( final String name, final Iterable<String> values ) { if ( values.iterator().hasNext() ) { internalFilters.put( name, ImmutableSet.copyOf( values ) ); } return this; } @Nonnull public Filter generate() throws InvalidFilterException { Filter filter; final FilterSupport support = FilterSupport.forResource( resourceType, qualifier ); if ( support == null ) { filter = Filter.alwaysTrue(); } else { filter = support.generate( toMap( filters ), false ); if ( !internalFilters.isEmpty() ) { filter = filter.and( support.generate( internalFilters, true ) ); } } return filter; } } private static Map<String, Set<String>> toMap( final Iterable<com.eucalyptus.compute.common.Filter> filters ) { final ImmutableMap.Builder<String,Set<String>> filterMapBuilder = ImmutableMap.builder(); for ( final com.eucalyptus.compute.common.Filter filter : filters ) { final Set<String> values = ImmutableSet.copyOf( Iterables.transform( filter.getValueSet(), NullToEmptyString.INSTANCE ) ); filterMapBuilder.put( filter.getName(), values ); } return filterMapBuilder.build(); } private enum NullToEmptyString implements Function<String,String> { INSTANCE; @Override public String apply( final String text ) { return text == null ? "" : text; } } }