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 2016 ForgeRock AS. 015 */ 016 017package org.forgerock.api.models; 018 019import static org.forgerock.api.util.ValidationUtil.containsWhitespace; 020import static org.forgerock.api.util.ValidationUtil.isEmpty; 021 022import java.lang.reflect.Method; 023import java.util.Objects; 024 025import com.fasterxml.jackson.annotation.JsonInclude; 026import com.fasterxml.jackson.annotation.JsonProperty; 027import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 028import org.wrensecurity.guava.common.base.Strings; 029 030import org.forgerock.api.ApiValidationException; 031 032/** 033 * Class that represents the Action operation type in API descriptor. 034 */ 035@JsonDeserialize(builder = Action.Builder.class) 036@JsonInclude(JsonInclude.Include.NON_NULL) 037public final class Action extends Operation implements Comparable<Action> { 038 039 private final String name; 040 private final Schema request; 041 private final Schema response; 042 043 /** 044 * Protected contstructor of the Action. 045 * 046 * @param builder Action Builder 047 */ 048 private Action(Builder builder) { 049 super(builder); 050 this.name = builder.name; 051 this.request = builder.request; 052 this.response = builder.response; 053 054 if (isEmpty(name)) { 055 throw new ApiValidationException("name is required"); 056 } 057 if (containsWhitespace(name)) { 058 throw new ApiValidationException("name contains whitespace"); 059 } 060 } 061 062 /** 063 * Getter of the ID. 064 * 065 * @return Id 066 */ 067 public String getName() { 068 return name; 069 } 070 071 /** 072 * Getter of the request. 073 * 074 * @return Request 075 */ 076 public Schema getRequest() { 077 return request; 078 } 079 080 /** 081 * Getter of the response. 082 * 083 * @return Response 084 */ 085 public Schema getResponse() { 086 return response; 087 } 088 089 @Override 090 public boolean equals(Object o) { 091 if (this == o) { 092 return true; 093 } 094 if (o == null || getClass() != o.getClass()) { 095 return false; 096 } 097 if (!super.equals(o)) { 098 return false; 099 } 100 Action action = (Action) o; 101 return super.equals(o) 102 && Objects.equals(name, action.name) 103 && Objects.equals(request, action.request) 104 && Objects.equals(response, action.response); 105 } 106 107 @Override 108 public int hashCode() { 109 return Objects.hash(super.hashCode(), name, request, response); 110 } 111 112 /** 113 * Creates a new builder for Action. 114 * 115 * @return New builder instance 116 */ 117 public static final Builder action() { 118 return new Builder(); 119 } 120 121 /** 122 * Allocates the Action operation type to the given Resource Builder. 123 * 124 * @param resourceBuilder - Resource Builder to add the operation 125 */ 126 @Override 127 protected void allocateToResource(Resource.Builder resourceBuilder) { 128 resourceBuilder.action(this); 129 } 130 131 /** 132 * Builds an Action object using the data in the annotation. 133 * @param action The annotation that holds the data for the built object. 134 * @param annotated The action method. 135 * @param descriptor The root descriptor to add definitions to. 136 * @param relativeType The type relative to which schema resources should be resolved. 137 * @return Action instance. 138 */ 139 public static Action fromAnnotation(org.forgerock.api.annotations.Action action, Method annotated, 140 ApiDescription descriptor, Class<?> relativeType) { 141 Builder builder = action(); 142 String specifiedName = action.name(); 143 if (Strings.isNullOrEmpty(specifiedName)) { 144 if (annotated == null) { 145 throw new IllegalArgumentException("Action does not have a name: " + action); 146 } 147 specifiedName = annotated.getName(); 148 } 149 return builder.name(specifiedName) 150 .request(Schema.fromAnnotation(action.request(), descriptor, relativeType)) 151 .response(Schema.fromAnnotation(action.response(), descriptor, relativeType)) 152 .detailsFromAnnotation(action.operationDescription(), descriptor, relativeType) 153 .build(); 154 } 155 156 /** 157 * Compares two strings lexicographically. 158 * @param action Action to compare to 159 * @return the value {@code 0} if the argument string is equal to 160 * this string; a value less than {@code 0} if this string 161 * is lexicographically less than the string argument; and a 162 * value greater than {@code 0} if this string is 163 * lexicographically greater than the string argument. 164 */ 165 @Override 166 public int compareTo(Action action) { 167 return this.name.compareTo(action.getName()); 168 } 169 170 /** 171 * Builder class for creating the Action. 172 */ 173 public static final class Builder extends Operation.Builder<Builder> { 174 175 private String name; 176 private Schema request; 177 private Schema response; 178 179 @Override 180 protected Builder self() { 181 return this; 182 } 183 184 /** 185 * Set the Id. 186 * 187 * @param name Action name 188 * @return Builder 189 */ 190 @JsonProperty("name") 191 public Builder name(String name) { 192 this.name = name; 193 return this; 194 } 195 196 /** 197 * Set the request. 198 * 199 * @param request Action request 200 * @return Builder 201 */ 202 @JsonProperty("request") 203 public Builder request(Schema request) { 204 this.request = request; 205 return this; 206 } 207 208 /** 209 * Set the response. 210 * 211 * @param response Action resopnse 212 * @return Builder 213 */ 214 @JsonProperty("response") 215 public Builder response(Schema response) { 216 this.response = response; 217 return this; 218 } 219 220 /** 221 * Builds the Action instance. 222 * 223 * @return Action instance 224 */ 225 public Action build() { 226 return new Action(this); 227 } 228 } 229 230}