/* * 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.HashSet; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.abdera2.common.misc.MoreFunctions; import com.google.common.base.Function; import com.google.common.collect.Iterables; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; import static org.apache.abdera2.common.misc.MorePredicates.*; /** *

* Provides a utility class helpful for determining which type of resource the client is requesting. Each resource type * (e.g. service doc, collection, entry, edit uri, media resource, etc) is assigned a regex pattern. Given the request * URI (path and querystring), this will determine which resource was selected and return an appropriate TargetMatcher. * TargetMatcher is essentially just a simplified version of the java.util.regex.Matcher that also specifies the * Resource Type. *

* *
 *  RequestContext request = ...
 *  RegexTargetResolver tr = new RegexTargetResolver();
 *  tr.setPattern("/atom",ResourceType.INTROSPECTION)
 *    .setPattern("/atom/([^/#?]+)",ResourceType.COLLECTION)
 *    .setPattern("/atom/([^/#?]+)/([^/#?]+)",ResourceType.ENTRY)
 *    .setPattern("/atom/([^/#?]+)/([^/#?]+)\\?edit",ResourceType.ENTRY_EDIT)
 *    .setPattern("/atom/([^/#?]+)/([^/#?]+)\\?media",ResourceType.MEDIA)
 *    .setPattern("/atom/([^/#?]+)/([^/#?]+)\\?edit-media",ResourceType.MEDIA_EDIT);
 *  
 *  Target target = tr.resolve(request);
 *  System.out.println(target.getType());
 *  System.out.println(targer.getParameter("foo"));
 * 
*/ public class RegexTargetResolver implements Function { protected final Map patterns; protected final Multimap fields = LinkedHashMultimap.create(); public RegexTargetResolver() { this.patterns = new HashMap(); } public RegexTargetResolver(Map patterns) { this.patterns = new HashMap(); for (Map.Entry entry : patterns.entrySet()) setPattern(entry.getKey(), entry.getValue()); } public RegexTargetResolver setPattern(String pattern, TargetType type) { return setPattern(pattern, type, new String[0]); } public RegexTargetResolver setPattern(String pattern, TargetType type, String... fields) { Pattern p = Pattern.compile(pattern); this.patterns.put(p, type); this.fields.putAll(p,Arrays.asList(fields)); return this; } public Target apply(R request) { String uri = request.getTargetPath(); for (Pattern pattern : patterns.keySet()) { Matcher matcher = pattern.matcher(uri); if (matcher.matches()) return getTarget( this.patterns.get(pattern), request, matcher, this.fields.get(pattern)); } return null; } protected Target getTarget( TargetType type, RequestContext request, Matcher matcher, Iterable fields) { return new RegexTarget(type, request, matcher, fields); } public String toString() { StringBuilder buf = new StringBuilder(); buf.append("Regex Target Resolver:\n"); for (Pattern pattern : patterns.keySet()) buf.append( String.format( "%s, Type: %s, Fields: %s", pattern, this.patterns.get(pattern), this.fields.get(pattern))); return buf.toString(); } public int hashCode() { return MoreFunctions.genHashCode(1, fields,patterns); } @SuppressWarnings("unchecked") public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final RegexTargetResolver other = (RegexTargetResolver)obj; if (fields == null) { if (other.fields != null) return false; } else if (!fields.equals(other.fields)) return false; if (patterns == null) { if (other.patterns != null) return false; } else if (!patterns.equals(other.patterns)) return false; return true; } public static class RegexTarget extends SimpleTarget implements Target { private static final long serialVersionUID = 165211244926064449L; protected Matcher matcher; protected Iterable fields; public RegexTarget( TargetType type, RequestContext context, Matcher matcher, Iterable fields) { super(type, context); this.matcher = matcher; this.fields = fields; } public String getParameter(String name) { if (fields == null) return super.getParameter(name); int idx = Iterables.indexOf(fields, equalsIgnoreCase(name)); return idx > -1 && idx <= matcher.groupCount()-1 ? matcher.group(idx+1) : super.getParameter(name); } public Iterable getParameterNames() { Iterable names = super.getParameterNames(); Set list = new HashSet(); for (String name : names) list.add(name); if (fields != null) Iterables.addAll(list, fields); return list; } @SuppressWarnings("unchecked") @Override public T getMatcher() { return (T)matcher.pattern(); } @Override public int hashCode() { String m = matcher.group(0); String p = matcher.pattern().pattern(); return MoreFunctions.genHashCode(1, m,p,type); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final RegexTarget other = (RegexTarget)obj; String m = matcher.group(0); String p = matcher.pattern().pattern(); String m2 = other.matcher.group(0); String p2 = other.matcher.pattern().pattern(); if (!super.equals(obj)) return false; if (m == null) { if (m2 != null) return false; } else if (!m.equals(m2)) return false; if (p == null) { if (p2 != null) return false; } else if (!p.equals(p2)) return false; if (type == null) { if (other.type != null) return false; } else if (!type.equals(other.type)) return false; return true; } public String toString() { String m = matcher.group(0); String p = matcher.pattern().pattern(); StringBuilder buf = new StringBuilder(); buf.append("RegexTarget[").append(p).append(" ==> ").append(m).append("] = ").append(type.toString()) .append("\n"); for (String param : getParameterNames()) { buf.append(" ").append(param).append(" = ").append(getParameter(param)).append("\n"); } return buf.toString(); } public String getIdentity() { return context.getUri().toString(); } } }