package de.axone.web.rest; import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.axone.tools.Str; import de.axone.web.Method; public interface RestFunctionRoute { public abstract Map<String, String> match( Method method, String uri ); public static class Simple implements RestFunctionRoute { private static final Pattern PATTERN_PATTERN = Pattern.compile( ":(\\w+)" ); private EnumSet<Method> methods; private final String patternString; private final Pattern pattern; private final List<String> parameterNames = new LinkedList<>(); private final Map<String,Integer> parameterIndizes = new TreeMap<>(); /* Constructor hell because of EnumSet */ public Simple( String pattern, Method method ){ this( pattern, EnumSet.of( method ) ); } public Simple( String pattern, Method m1, Method m2 ){ this( pattern, EnumSet.of( m1, m2 ) ); } public Simple( String pattern, Method m1, Method m2, Method m3 ){ this( pattern, EnumSet.of( m1, m2, m3 ) ); } public Simple( String pattern, Method m1, Method m2, Method m3, Method m4 ){ this( pattern, EnumSet.of( m1, m2, m3, m4 ) ); } public Simple( String pattern, Method first, Method ... rest ){ this( pattern, EnumSet.of( first, rest ) ); } public Simple( String pattern, EnumSet<Method> methods ){ this( pattern ); this.methods = methods; } public Simple( String pattern ){ this.patternString = pattern; Matcher m = PATTERN_PATTERN.matcher( pattern ); int i=0; StringBuffer compiled = new StringBuffer(); while( m.find() ){ String name = pattern.substring( m.start(), m.end() ); name = name.substring( 1 ); // remove : if( name.length() == 0 ) throw new IllegalArgumentException( ": must be followed by word charackters" ); parameterNames.add( name ); parameterIndizes.put( name, Integer.valueOf( i++ ) ); m.appendReplacement( compiled, "([a-zA-Z0-9_-]+)" ); } m.appendTail( compiled ); this.pattern = Pattern.compile( "^" + compiled.toString() + "$" ); } @Override public Map<String,String> match( Method method, String uri ){ if( methods != null ){ if( ! methods.contains( method ) ) return null; } return match( uri ); } Map<String,String> match( String uri ){ Matcher m = pattern.matcher( uri ); if( m.matches() ){ Map<String,String> result = new TreeMap<>(); for( int i=0; i<m.groupCount(); i++ ){ String name = parameterNames.get( i ); String value = m.group( i+1 ); result.put( name, value ); } return result; } else { return null; } } @Override public String toString(){ return patternString; } } public class Combined implements RestFunctionRoute { private final RestFunctionRoute [] routes; public Combined( RestFunctionRoute ... routes ){ this.routes = routes; } @Override public Map<String, String> match( Method method, String uri ) { Map<String,String> result; for( RestFunctionRoute route : routes ){ result = route.match( method, uri ); if( result != null ) return result; } return null; } @Override public String toString(){ return Str.join( ", ", routes ); } } }