/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. The ASF licenses this file to You * 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. For additional information regarding * copyright in this work, please see the NOTICE file in the top level * directory of this distribution. */ package org.apache.abdera2.common.protocol; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.abdera2.common.iri.IRI; import org.apache.abdera2.common.misc.ExceptionHelper; import org.apache.abdera2.common.misc.MoreFunctions; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; /** * A TargetResolver based on a Set of Function objects. Each * Function is attempted in the order it is added to the * resolver. If the Function returns a Target, execution * stops and the target is returned, otherwise the next * function in the list is tried */ public class TargetFunctionResolver implements Function { public static TargetFunctionResolver create( TargetFunction... functions) { return create(Arrays.asList(functions)); } public static TargetFunctionResolver create( Iterable> functions) { return new TargetFunctionResolver(functions); } protected final Set> functions = new LinkedHashSet>(); private TargetFunctionResolver( Iterable> functions) { Iterables.addAll(this.functions, functions); } public TargetFunctionResolver addFunction( TargetFunction function) { this.functions.add(function); return this; } public Target apply(R request) { for (TargetFunction f : functions) { Target target = f.apply(request); if (target != null) return target; } return null; } @Override public int hashCode() { return MoreFunctions.genHashCode(1, functions); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TargetFunctionResolver other = (TargetFunctionResolver) obj; if (functions == null) { if (other.functions != null) return false; } else if (!functions.equals(other.functions)) return false; return true; } /** * A Function that Resolves a Target from a RequestContext */ public static abstract class TargetFunction implements Function { } /** * Returns a Generator used to build PredicateTargetfunction instances */ public static PredicateTargetFunction.Generator make() { return new PredicateTargetFunction.Generator(); } /** * A TargetFunction that is based on a map of Predicates and Functions. * The RequestContext is tested against each Predicate in the order the * Predicate was added. If apply() returns true, the associated Function * is used to return the appropriate Target instance. */ public static class PredicateTargetFunction extends TargetFunction { public static class Generator implements Supplier> { private final Map,Function> map = new LinkedHashMap,Function>(); public Generator set(Predicate test, Function function) { map.put(test,function); return this; } public TargetFunction get() { return new PredicateTargetFunction(map); } } private final Map,Function> map = new HashMap,Function>(); protected PredicateTargetFunction( Map,Function> map) { this.map.putAll(map); } public Target apply(R input) { try { for (Predicate test : map.keySet()) if (test.apply(input)) return map.get(test).apply(input); return null; } catch (Throwable t) { throw ExceptionHelper.propogate(t); } } } /** * A TargetFunction that resolves Targets based primarily off the * Request URI */ public static abstract class RequestUriFunction extends TargetFunction implements Function { public Target apply(R input) { return apply(input,input.getResolvedUri()); } protected abstract Target apply(R context,IRI uri); } /** * A Predicate that tests the Request URI */ public static abstract class RequestUriPredicate implements Predicate { public boolean apply(R input) { return apply(input.getResolvedUri()); } protected abstract boolean apply(IRI uri); } /** * A TargetFunction that performs a Regex Pattern match on the * Request URI. If the Pattern matches, a RegexTarget instance * is returned. This Function can be used either directly by * the TargetFunctionResolver or as part of the PredicateTargetFunction */ public static class RegexUriFunction extends RequestUriFunction { private final Pattern pattern; private final TargetType type; private final Iterable fields; public RegexUriFunction(TargetType type, Pattern pattern, String... fields) { this.type = type; this.pattern = pattern; this.fields = Arrays.asList(fields); } public RegexUriFunction(TargetType type, String pattern, String... fields) { this(type,Pattern.compile(pattern),fields); } protected Target apply(R context,IRI uri) { Matcher matcher = pattern.matcher(uri.toString()); return matcher.matches() ? new RegexTargetResolver.RegexTarget(type,context,matcher,fields) : null; } } /** * Predicate that tests the Request URI against a Regex Pattern */ public static class RegexUriPredicate extends RequestUriPredicate { private final Pattern pattern; public RegexUriPredicate(Pattern pattern) { this.pattern = pattern; } public RegexUriPredicate(String pattern) { this(Pattern.compile(pattern)); } protected boolean apply(IRI uri) { return pattern.matcher(uri.toString()).matches(); } } public static Function functionForRegex(Pattern pattern, TargetType type, String... fields) { return new RegexUriFunction(type,pattern,fields); } public static Function functionForRegex(String pattern, TargetType type, String... fields) { return new RegexUriFunction(type,pattern,fields); } public static Predicate predicateForRegex(Pattern pattern) { return new RegexUriPredicate(pattern); } public static Predicate predicateForRegex(String pattern) { return new RegexUriPredicate(pattern); } }