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.openig.http; 018 019import static org.forgerock.http.routing.RouteMatchers.requestUriMatcher; 020import static org.forgerock.http.routing.RoutingMode.STARTS_WITH; 021 022import org.forgerock.http.Handler; 023import org.forgerock.http.protocol.Request; 024import org.forgerock.http.routing.Router; 025import org.forgerock.openig.heap.GenericHeaplet; 026import org.forgerock.services.routing.RouteMatcher; 027 028/** 029 * Registry for OpenIG REST API endpoints. 030 * 031 * <p>Components can use that class to register additional endpoints into the {@literal /openig/api} namespace: 032 * 033 * <ul> 034 * <li>{@literal /openig/api/system/objects/[heap-object-name]} for components defined in {@code config.json}</li> 035 * <li>{@literal /openig/api/system/objects/.../[router-name]/routes/[route-name]/objects/[heap-object-name]} for 036 * components defined inside routes</li> 037 * </ul> 038 * 039 * @see GenericHeaplet#endpointRegistry() 040 */ 041public final class EndpointRegistry { 042 private final Router router; 043 private final String path; 044 045 /** 046 * Creates a registry around the given Router instance. 047 * Registered endpoints will be sub-elements of the given {@code router}. 048 * 049 * @param router base Router 050 * @param path path for this registry 051 */ 052 public EndpointRegistry(final Router router, final String path) { 053 this.router = router; 054 this.path = path; 055 } 056 057 /** 058 * Registers a new endpoint under the given {@code name}. 059 * 060 * <p>Equivalent to calling this {@code Router} code: 061 * <pre> 062 * {@code 063 * router.addRoute(requestUriMatcher(STARTS_WITH, name), handler); 064 * } 065 * </pre> 066 * 067 * @param name 068 * registered endpoint name 069 * @param handler 070 * endpoint implementation 071 * @return a handle for later endpoint un-registration 072 */ 073 public Registration register(final String name, final Handler handler) { 074 RouteMatcher<Request> matcher = requestUriMatcher(STARTS_WITH, name); 075 router.addRoute(matcher, handler); 076 return new Registration(router, matcher, pathInfo(name)); 077 } 078 079 /** 080 * Returns the path info computed by appending the given {@code name} to this registry's path. 081 * 082 * @param name 083 * path element to append 084 * @return composed path 085 */ 086 public String pathInfo(String name) { 087 StringBuilder sb = new StringBuilder(path); 088 if (!name.startsWith("/")) { 089 sb.append("/"); 090 } 091 sb.append(name); 092 if (name.endsWith("/")) { 093 sb.deleteCharAt(sb.length() - 1); 094 } 095 return sb.toString(); 096 } 097 098 /** 099 * Returns this registry's base path. 100 * @return this registry's base path. 101 */ 102 public String getPath() { 103 return path; 104 } 105 106 /** 107 * Handle for un-registering an endpoint. 108 */ 109 public static class Registration { 110 private final Router router; 111 private final RouteMatcher<Request> matcher; 112 private final String path; 113 114 Registration(final Router router, final RouteMatcher<Request> matcher, String path) { 115 this.router = router; 116 this.matcher = matcher; 117 this.path = path; 118 } 119 120 /** 121 * Un-register the endpoint. 122 */ 123 public void unregister() { 124 router.removeRoute(matcher); 125 } 126 127 /** 128 * Returns this endpoint's path. 129 * @return this endpoint's path. 130 */ 131 public String getPath() { 132 return path; 133 } 134 } 135 136}