001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest.annotation; 014 015import static org.apache.juneau.http.HttpHeaders.*; 016import static org.apache.juneau.internal.ArrayUtils.*; 017import static org.apache.juneau.http.HttpParts.*; 018 019import java.lang.annotation.*; 020import java.nio.charset.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.annotation.*; 024import org.apache.juneau.encoders.*; 025import org.apache.juneau.reflect.*; 026import org.apache.juneau.rest.*; 027import org.apache.juneau.rest.converter.*; 028import org.apache.juneau.rest.guard.*; 029import org.apache.juneau.rest.httppart.*; 030import org.apache.juneau.rest.matcher.*; 031import org.apache.juneau.serializer.*; 032import org.apache.juneau.svl.*; 033 034/** 035 * Utility classes and methods for the {@link RestOptions @RestOptions} annotation. 036 * 037 * <h5 class='section'>See Also:</h5><ul> 038 * <li class='link'><a class="doclink" href="../../../../../index.html#jrs.RestOpAnnotatedMethods">@RestOp-Annotated Methods</a> 039 * </ul> 040 */ 041public class RestOptionsAnnotation { 042 043 //----------------------------------------------------------------------------------------------------------------- 044 // Static 045 //----------------------------------------------------------------------------------------------------------------- 046 047 /** Default value */ 048 public static final RestOptions DEFAULT = create().build(); 049 050 /** 051 * Instantiates a new builder for this class. 052 * 053 * @return A new builder object. 054 */ 055 public static Builder create() { 056 return new Builder(); 057 } 058 059 //----------------------------------------------------------------------------------------------------------------- 060 // Builder 061 //----------------------------------------------------------------------------------------------------------------- 062 063 /** 064 * Builder class. 065 * 066 * <h5 class='section'>See Also:</h5><ul> 067 * <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)} 068 * </ul> 069 */ 070 @SuppressWarnings("unchecked") 071 public static class Builder extends TargetedAnnotationMBuilder { 072 073 Class<? extends RestConverter>[] converters = new Class[0]; 074 Class<? extends RestGuard>[] guards = new Class[0]; 075 Class<? extends RestMatcher>[] matchers = new Class[0]; 076 Class<? extends Encoder>[] encoders = new Class[0]; 077 Class<? extends Serializer>[] serializers = new Class[0]; 078 OpSwagger swagger = OpSwaggerAnnotation.DEFAULT; 079 String clientVersion="", debug="", defaultAccept="", defaultCharset="", rolesDeclared="", roleGuard="", summary="", value=""; 080 String[] defaultRequestQueryData={}, defaultRequestAttributes={}, defaultRequestHeaders={}, defaultResponseHeaders={}, description={}, path={}, produces={}; 081 082 /** 083 * Constructor. 084 */ 085 protected Builder() { 086 super(RestOptions.class); 087 } 088 089 /** 090 * Instantiates a new {@link RestOptions @RestOptions} object initialized with this builder. 091 * 092 * @return A new {@link RestOptions @RestOptions} object. 093 */ 094 public RestOptions build() { 095 return new Impl(this); 096 } 097 098 /** 099 * Sets the {@link RestOptions#clientVersion()} property on this annotation. 100 * 101 * @param value The new value for this property. 102 * @return This object. 103 */ 104 public Builder clientVersion(String value) { 105 this.clientVersion = value; 106 return this; 107 } 108 109 /** 110 * Sets the {@link RestOptions#converters()} property on this annotation. 111 * 112 * @param value The new value for this property. 113 * @return This object. 114 */ 115 public Builder converters(Class<? extends RestConverter>...value) { 116 this.converters = value; 117 return this; 118 } 119 120 /** 121 * Sets the {@link RestOptions#debug()} property on this annotation. 122 * 123 * @param value The new value for this property. 124 * @return This object. 125 */ 126 public Builder debug(String value) { 127 this.debug = value; 128 return this; 129 } 130 131 /** 132 * Sets the {@link RestOptions#defaultAccept()} property on this annotation. 133 * 134 * @param value The new value for this property. 135 * @return This object. 136 */ 137 public Builder defaultAccept(String value) { 138 this.defaultAccept = value; 139 return this; 140 } 141 142 /** 143 * Sets the {@link RestOptions#defaultCharset()} property on this annotation. 144 * 145 * @param value The new value for this property. 146 * @return This object. 147 */ 148 public Builder defaultCharset(String value) { 149 this.defaultCharset = value; 150 return this; 151 } 152 153 /** 154 * Sets the {@link RestOptions#defaultRequestQueryData()} property on this annotation. 155 * 156 * @param value The new value for this property. 157 * @return This object. 158 */ 159 public Builder defaultRequestQueryData(String...value) { 160 this.defaultRequestQueryData = value; 161 return this; 162 } 163 164 /** 165 * Sets the {@link RestOptions#defaultRequestAttributes()} property on this annotation. 166 * 167 * @param value The new value for this property. 168 * @return This object. 169 */ 170 public Builder defaultRequestAttributes(String...value) { 171 this.defaultRequestAttributes = value; 172 return this; 173 } 174 175 /** 176 * Sets the {@link RestOptions#defaultRequestHeaders()} property on this annotation. 177 * 178 * @param value The new value for this property. 179 * @return This object. 180 */ 181 public Builder defaultRequestHeaders(String...value) { 182 this.defaultRequestHeaders = value; 183 return this; 184 } 185 186 /** 187 * Sets the {@link RestOptions#defaultResponseHeaders()} property on this annotation. 188 * 189 * @param value The new value for this property. 190 * @return This object. 191 */ 192 public Builder defaultResponseHeaders(String...value) { 193 this.defaultResponseHeaders = value; 194 return this; 195 } 196 197 /** 198 * Sets the {@link RestOptions#description()} property on this annotation. 199 * 200 * @param value The new value for this property. 201 * @return This object. 202 */ 203 public Builder description(String...value) { 204 this.description = value; 205 return this; 206 } 207 208 /** 209 * Sets the {@link RestOptions#encoders()} property on this annotation. 210 * 211 * @param value The new value for this property. 212 * @return This object. 213 */ 214 public Builder encoders(Class<? extends Encoder>...value) { 215 this.encoders = value; 216 return this; 217 } 218 219 /** 220 * Sets the {@link RestOptions#guards()} property on this annotation. 221 * 222 * @param value The new value for this property. 223 * @return This object. 224 */ 225 public Builder guards(Class<? extends RestGuard>...value) { 226 this.guards = value; 227 return this; 228 } 229 230 /** 231 * Sets the {@link RestOptions#matchers()} property on this annotation. 232 * 233 * @param value The new value for this property. 234 * @return This object. 235 */ 236 public Builder matchers(Class<? extends RestMatcher>...value) { 237 this.matchers = value; 238 return this; 239 } 240 241 /** 242 * Sets the {@link RestOptions#path()} property on this annotation. 243 * 244 * @param value The new value for this property. 245 * @return This object. 246 */ 247 public Builder path(String...value) { 248 this.path = value; 249 return this; 250 } 251 252 /** 253 * Sets the {@link RestOptions#produces()} property on this annotation. 254 * 255 * @param value The new value for this property. 256 * @return This object. 257 */ 258 public Builder produces(String...value) { 259 this.produces = value; 260 return this; 261 } 262 263 /** 264 * Sets the {@link RestOptions#roleGuard()} property on this annotation. 265 * 266 * @param value The new value for this property. 267 * @return This object. 268 */ 269 public Builder roleGuard(String value) { 270 this.roleGuard = value; 271 return this; 272 } 273 274 /** 275 * Sets the {@link RestOptions#rolesDeclared()} property on this annotation. 276 * 277 * @param value The new value for this property. 278 * @return This object. 279 */ 280 public Builder rolesDeclared(String value) { 281 this.rolesDeclared = value; 282 return this; 283 } 284 285 /** 286 * Sets the {@link RestOptions#serializers()} property on this annotation. 287 * 288 * @param value The new value for this property. 289 * @return This object. 290 */ 291 public Builder serializers(Class<? extends Serializer>...value) { 292 this.serializers = value; 293 return this; 294 } 295 296 /** 297 * Sets the {@link RestOptions#summary()} property on this annotation. 298 * 299 * @param value The new value for this property. 300 * @return This object. 301 */ 302 public Builder summary(String value) { 303 this.summary = value; 304 return this; 305 } 306 307 /** 308 * Sets the {@link RestOptions#swagger()} property on this annotation. 309 * 310 * @param value The new value for this property. 311 * @return This object. 312 */ 313 public Builder swagger(OpSwagger value) { 314 this.swagger = value; 315 return this; 316 } 317 318 /** 319 * Sets the {@link RestOptions#value()} property on this annotation. 320 * 321 * @param value The new value for this property. 322 * @return This object. 323 */ 324 public Builder value(String value) { 325 this.value = value; 326 return this; 327 } 328 329 // <FluentSetters> 330 331 @Override /* GENERATED - TargetedAnnotationBuilder */ 332 public Builder on(String...values) { 333 super.on(values); 334 return this; 335 } 336 337 @Override /* GENERATED - TargetedAnnotationTMBuilder */ 338 public Builder on(java.lang.reflect.Method...value) { 339 super.on(value); 340 return this; 341 } 342 343 // </FluentSetters> 344 } 345 346 //----------------------------------------------------------------------------------------------------------------- 347 // Implementation 348 //----------------------------------------------------------------------------------------------------------------- 349 350 private static class Impl extends TargetedAnnotationImpl implements RestOptions { 351 352 private final Class<? extends RestConverter>[] converters; 353 private final Class<? extends RestGuard>[] guards; 354 private final Class<? extends RestMatcher>[] matchers; 355 private final Class<? extends Encoder>[] encoders; 356 private final Class<? extends Serializer>[] serializers; 357 private final OpSwagger swagger; 358 private final String clientVersion, debug, defaultAccept, defaultCharset, rolesDeclared, roleGuard, summary, value; 359 private final String[] defaultRequestQueryData, defaultRequestAttributes, defaultRequestHeaders, defaultResponseHeaders, description, path, produces; 360 361 Impl(Builder b) { 362 super(b); 363 this.clientVersion = b.clientVersion; 364 this.converters = copyOf(b.converters); 365 this.debug = b.debug; 366 this.defaultAccept = b.defaultAccept; 367 this.defaultCharset = b.defaultCharset; 368 this.defaultRequestQueryData = copyOf(b.defaultRequestQueryData); 369 this.defaultRequestAttributes = copyOf(b.defaultRequestAttributes); 370 this.defaultRequestHeaders = copyOf(b.defaultRequestHeaders); 371 this.defaultResponseHeaders = copyOf(b.defaultResponseHeaders); 372 this.description = copyOf(b.description); 373 this.encoders = copyOf(b.encoders); 374 this.guards = copyOf(b.guards); 375 this.matchers = copyOf(b.matchers); 376 this.path = copyOf(b.path); 377 this.produces = copyOf(b.produces); 378 this.roleGuard = b.roleGuard; 379 this.rolesDeclared = b.rolesDeclared; 380 this.serializers = copyOf(b.serializers); 381 this.summary = b.summary; 382 this.swagger = b.swagger; 383 this.value = b.value; 384 postConstruct(); 385 } 386 387 @Override /* RestOptions */ 388 public String clientVersion() { 389 return clientVersion; 390 } 391 392 @Override /* RestOptions */ 393 public Class<? extends RestConverter>[] converters() { 394 return converters; 395 } 396 397 @Override /* RestOptions */ 398 public String debug() { 399 return debug; 400 } 401 402 @Override /* RestOptions */ 403 public String defaultAccept() { 404 return defaultAccept; 405 } 406 407 @Override /* RestOptions */ 408 public String defaultCharset() { 409 return defaultCharset; 410 } 411 412 @Override /* RestOptions */ 413 public String[] defaultRequestQueryData() { 414 return defaultRequestQueryData; 415 } 416 417 @Override /* RestOptions */ 418 public String[] defaultRequestAttributes() { 419 return defaultRequestAttributes; 420 } 421 422 @Override /* RestOptions */ 423 public String[] defaultRequestHeaders() { 424 return defaultRequestHeaders; 425 } 426 427 @Override /* RestOptions */ 428 public String[] defaultResponseHeaders() { 429 return defaultResponseHeaders; 430 } 431 432 @Override /* RestOptions */ 433 public String[] description() { 434 return description; 435 } 436 437 @Override /* RestOptions */ 438 public Class<? extends Encoder>[] encoders() { 439 return encoders; 440 } 441 442 @Override /* RestOptions */ 443 public Class<? extends RestGuard>[] guards() { 444 return guards; 445 } 446 447 @Override /* RestOptions */ 448 public Class<? extends RestMatcher>[] matchers() { 449 return matchers; 450 } 451 452 @Override /* RestOptions */ 453 public String[] path() { 454 return path; 455 } 456 457 @Override /* RestOptions */ 458 public String[] produces() { 459 return produces; 460 } 461 462 @Override /* RestOptions */ 463 public String roleGuard() { 464 return roleGuard; 465 } 466 467 @Override /* RestOptions */ 468 public String rolesDeclared() { 469 return rolesDeclared; 470 } 471 472 @Override /* RestOptions */ 473 public Class<? extends Serializer>[] serializers() { 474 return serializers; 475 } 476 477 @Override /* RestOptions */ 478 public String summary() { 479 return summary; 480 } 481 482 @Override /* RestOptions */ 483 public OpSwagger swagger() { 484 return swagger; 485 } 486 487 @Override /* RestOptions */ 488 public String value() { 489 return value; 490 } 491 } 492 493 //----------------------------------------------------------------------------------------------------------------- 494 // Appliers 495 //----------------------------------------------------------------------------------------------------------------- 496 497 /** 498 * Applies {@link RestOptions} annotations to a {@link org.apache.juneau.rest.RestOpContext.Builder}. 499 */ 500 public static class RestOpContextApply extends AnnotationApplier<RestOptions,RestOpContext.Builder> { 501 502 /** 503 * Constructor. 504 * 505 * @param vr The resolver for resolving values in annotations. 506 */ 507 public RestOpContextApply(VarResolverSession vr) { 508 super(RestOptions.class, RestOpContext.Builder.class, vr); 509 } 510 511 @Override 512 public void apply(AnnotationInfo<RestOptions> ai, RestOpContext.Builder b) { 513 RestOptions a = ai.inner(); 514 515 b.httpMethod("options"); 516 517 classes(a.serializers()).ifPresent(x -> b.serializers().set(x)); 518 classes(a.encoders()).ifPresent(x -> b.encoders().set(x)); 519 stream(a.produces()).map(MediaType::of).forEach(x -> b.produces(x)); 520 stream(a.defaultRequestHeaders()).map(x -> stringHeader(x)).forEach(x -> b.defaultRequestHeaders().setDefault(x)); 521 stream(a.defaultResponseHeaders()).map(x -> stringHeader(x)).forEach(x -> b.defaultResponseHeaders().setDefault(x)); 522 stream(a.defaultRequestAttributes()).map(x -> BasicNamedAttribute.ofPair(x)).forEach(x -> b.defaultRequestAttributes().add(x)); 523 stream(a.defaultRequestQueryData()).map(x -> basicPart(x)).forEach(x -> b.defaultRequestQueryData().setDefault(x)); 524 string(a.defaultAccept()).map(x -> accept(x)).ifPresent(x -> b.defaultRequestHeaders().setDefault(x)); 525 b.converters().append(a.converters()); 526 b.guards().append(a.guards()); 527 b.matchers().append(a.matchers()); 528 string(a.clientVersion()).ifPresent(x -> b.clientVersion(x)); 529 string(a.defaultCharset()).map(Charset::forName).ifPresent(x -> b.defaultCharset(x)); 530 stream(a.path()).forEach(x -> b.path(x)); 531 string(a.value()).ifPresent(x -> b.path(x)); 532 cdl(a.rolesDeclared()).forEach(x -> b.rolesDeclared(x)); 533 string(a.roleGuard()).ifPresent(x -> b.roleGuard(x)); 534 string(a.debug()).map(Enablement::fromString).ifPresent(x -> b.debug(x)); 535 } 536 } 537}