001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2015 ForgeRock AS. 015 */ 016 017package org.forgerock.json.resource; 018 019import static org.forgerock.http.routing.RouteMatchers.resourceApiVersionMatcher; 020import static org.forgerock.http.routing.RouteMatchers.uriMatcher; 021 022import java.util.ArrayList; 023import java.util.List; 024 025import org.forgerock.http.routing.ResourceApiVersionBehaviourManager; 026import org.forgerock.http.routing.RoutingMode; 027import org.forgerock.http.routing.Version; 028import org.forgerock.services.context.Context; 029import org.forgerock.services.routing.RouteMatch; 030import org.forgerock.services.routing.RouteMatcher; 031 032/** 033 * A utility class that contains methods for creating route matchers. 034 */ 035public final class RouteMatchers { 036 037 private RouteMatchers() { 038 } 039 040 /** 041 * Creates a {@code RouteMatcher} instance that matches {@code Request}s 042 * with the provided {@literal mode} and {@literal template}. 043 * 044 * @param mode The routing mode. 045 * @param template The uri template. 046 * @return A {@code RouteMatcher} instance. 047 */ 048 public static RouteMatcher<Request> requestUriMatcher(RoutingMode mode, String template) { 049 return new RequestUriRouteMatcher(uriMatcher(mode, template)); 050 } 051 052 /** 053 * Creates a new {@code ResourceApiVersionBehaviourManager} which is responsibly 054 * for managing whether warning headers are returned and the default 055 * version behaviour when the {@literal Accept-API-Version} header is not 056 * present on the request. 057 * 058 * @return A new {@code ResourceApiVersionBehaviourManager}. 059 */ 060 public static ResourceApiVersionBehaviourManager newResourceApiVersionBehaviourManager() { 061 return org.forgerock.http.routing.RouteMatchers.newResourceApiVersionBehaviourManager(); 062 } 063 064 /** 065 * Creates a {@code Filter} which MUST be placed, in the route, before any 066 * API Version routing takes place. 067 * 068 * <p>The filter will add the required {@code Context}s, default version 069 * behaviour and response headers.</p> 070 * 071 * @param behaviourManager A {@code ResourceApiVersionBehaviourManager} instance. 072 * @return A {@code Filter} instance. 073 */ 074 public static Filter resourceApiVersionContextFilter(ResourceApiVersionBehaviourManager behaviourManager) { 075 return new ResourceApiVersionRoutingFilter(behaviourManager); 076 } 077 078 /** 079 * Creates a {@code RouteMatcher} instance that matches the request 080 * resource API version with the provided {@literal version}. 081 * 082 * @param version The API version of the resource. 083 * @return A {@code RouteMatcher} instance. 084 */ 085 public static RouteMatcher<Request> requestResourceApiVersionMatcher(Version version) { 086 return new RequestApiVersionRouteMatcher(resourceApiVersionMatcher(version)); 087 } 088 089 /** 090 * A CREST specific {@code RouteMatcher} which extracts the requests 091 * resource name from a {@code Request} and passes it as a 092 * {@code ResourcePath} to the common {@code ResourcePath} route predicate. 093 */ 094 private static final class RequestUriRouteMatcher extends RouteMatcher<Request> { 095 096 private final RouteMatcher<List<String>> delegate; 097 098 private RequestUriRouteMatcher(RouteMatcher<List<String>> delegate) { 099 this.delegate = delegate; 100 } 101 102 @Override 103 public RouteMatch evaluate(Context context, Request request) { 104 final List<String> pathElements = new ArrayList<>(request.getResourcePathObject().size()); 105 for (String pathElement : request.getResourcePathObject()) { 106 pathElements.add(pathElement); 107 } 108 return delegate.evaluate(context, pathElements); 109 } 110 111 @Override 112 public String toString() { 113 return delegate.toString(); 114 } 115 116 @Override 117 public boolean equals(Object o) { 118 if (this == o) { 119 return true; 120 } 121 if (!(o instanceof RequestUriRouteMatcher)) { 122 return false; 123 } 124 RequestUriRouteMatcher that = (RequestUriRouteMatcher) o; 125 return delegate.equals(that.delegate); 126 } 127 128 @Override 129 public int hashCode() { 130 return delegate.hashCode(); 131 } 132 } 133 134 /** 135 * A CREST specific {@code RouteMatcher} which extracts the resource API 136 * version from a {@code Request} and passes it to the common 137 * {@code Version} route matcher. 138 */ 139 private static final class RequestApiVersionRouteMatcher extends RouteMatcher<Request> { 140 141 private final RouteMatcher<Version> delegate; 142 143 private RequestApiVersionRouteMatcher(RouteMatcher<Version> delegate) { 144 this.delegate = delegate; 145 } 146 147 @Override 148 public RouteMatch evaluate(Context context, Request request) { 149 return delegate.evaluate(context, request.getResourceVersion()); 150 } 151 152 @Override 153 public String toString() { 154 return delegate.toString(); 155 } 156 157 @Override 158 public boolean equals(Object o) { 159 if (this == o) { 160 return true; 161 } 162 if (!(o instanceof RequestApiVersionRouteMatcher)) { 163 return false; 164 } 165 RequestApiVersionRouteMatcher that = (RequestApiVersionRouteMatcher) o; 166 return delegate.equals(that.delegate); 167 } 168 169 @Override 170 public int hashCode() { 171 return delegate.hashCode(); 172 } 173 } 174}