001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.arg;
018
019import java.lang.reflect.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.http.annotation.*;
023import org.apache.juneau.httppart.bean.*;
024import org.apache.juneau.commons.lang.*;
025import org.apache.juneau.commons.reflect.*;
026import org.apache.juneau.rest.*;
027import org.apache.juneau.rest.annotation.*;
028
029/**
030 * Resolves method parameters and parameter types annotated with {@link Response} on {@link RestOp}-annotated Java methods.
031 *
032 * <p>
033 * The parameter value must be of type {@link Value} that accepts a value that is then set via:
034 * <p class='bjava'>
035 *    <jv>opSession</jv>
036 *       .{@link RestOpSession#getResponse() getResponse}()
037 *       .{@link RestResponse#setContent(Object) setOutput}(<jv>value</jv>);
038 * </p>
039 *
040 * <h5 class='section'>See Also:</h5><ul>
041 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ResponseBeans">@Response Beans</a>
042 * </ul>
043 */
044public class ResponseBeanArg implements RestOpArg {
045
046   private static final AnnotationProvider AP = AnnotationProvider.INSTANCE;
047
048   /**
049    * Static creator.
050    *
051    * @param paramInfo The Java method parameter being resolved.
052    * @param annotations The annotations to apply to any new part parsers.
053    * @return A new {@link ResponseBeanArg}, or <jk>null</jk> if the parameter is not annotated with {@link Response}.
054    */
055   public static ResponseBeanArg create(ParameterInfo paramInfo, AnnotationWorkList annotations) {
056      if (AP.has(Response.class, paramInfo))
057         return new ResponseBeanArg(paramInfo, annotations);
058      return null;
059   }
060
061   final ResponseBeanMeta meta;
062
063   private final Type type;
064
065   /**
066    * Constructor.
067    *
068    * @param paramInfo The Java method parameter being resolved.
069    * @param annotations The annotations to apply to any new part parsers.
070    */
071   protected ResponseBeanArg(ParameterInfo paramInfo, AnnotationWorkList annotations) {
072      this.type = paramInfo.getParameterType().innerType();
073      this.meta = ResponseBeanMeta.create(paramInfo, annotations);
074      var c = type instanceof Class ? (Class<?>)type : type instanceof ParameterizedType ? (Class<?>)((ParameterizedType)type).getRawType() : null;
075      if (c != Value.class)
076         throw new ArgException(paramInfo, "Type must be Value<?> on parameter annotated with @Response annotation");
077   }
078
079   @Override /* Overridden from RestOpArg */
080   public Object resolve(RestOpSession opSession) throws Exception {
081      var v = new Value<>();
082      v.listener(o -> {
083         RestRequest req = opSession.getRequest();
084         RestResponse res = opSession.getResponse();
085         ResponseBeanMeta meta = req.getOpContext().getResponseBeanMeta(o);
086         if (meta == null)
087            meta = ResponseBeanArg.this.meta;
088         res.setResponseBeanMeta(meta);
089         res.setContent(o);
090      });
091      return v;
092   }
093}