001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019 package org.apache.isis.viewer.restfulobjects.applib;
020
021 import java.util.Map;
022
023 import javax.ws.rs.core.MediaType;
024 import javax.ws.rs.core.MultivaluedMap;
025 import javax.ws.rs.core.UriBuilder;
026
027 import org.jboss.resteasy.client.ClientExecutor;
028 import org.jboss.resteasy.client.ClientRequest;
029 import org.jboss.resteasy.specimpl.UriBuilderImpl;
030
031 import org.apache.isis.viewer.restfulobjects.applib.RestfulRequest.RequestParameter;
032 import org.apache.isis.viewer.restfulobjects.applib.links.LinkRepresentation;
033 import org.apache.isis.viewer.restfulobjects.applib.util.UrlEncodingUtils;
034
035 /**
036 * Configures the body, query string etc of a {@link ClientRequest}.
037 *
038 * <p>
039 * Needed because, unfortunately, {@link ClientRequest} does not seem to allow
040 * the query string to be set directly (only
041 * {@link ClientRequest#getQueryParameters() query parameters}). Instead, it is
042 * necessary to {@link UriBuilderImpl#replaceQuery(String) use} its underlying
043 * {@link UriBuilderImpl}.
044 */
045 public class ClientRequestConfigurer {
046
047 public static ClientRequestConfigurer create(final ClientExecutor executor, final String uriTemplate) {
048 final UriBuilder uriBuilder = new UriBuilderImpl().uriTemplate(uriTemplate);
049 final ClientRequest clientRequest = executor.createRequest(uriBuilder);
050 return new ClientRequestConfigurer(clientRequest, uriBuilder);
051 }
052
053 private final ClientRequest clientRequest;
054 private final UriBuilder uriBuilder;
055
056 ClientRequestConfigurer(final ClientRequest clientRequest, final UriBuilder uriBuilder) {
057 this.clientRequest = clientRequest;
058 this.uriBuilder = uriBuilder;
059 }
060
061 public ClientRequestConfigurer accept(final MediaType mediaType) {
062 clientRequest.accept(mediaType);
063 return this;
064 }
065
066 public ClientRequestConfigurer header(final String name, final String value) {
067 clientRequest.header(name, value);
068 return this;
069 }
070
071 /**
072 * Prerequisite to {@link #configureArgs(JsonRepresentation)} or
073 * {@link #configureArgs(Map)}.
074 */
075 public ClientRequestConfigurer setHttpMethod(final HttpMethod httpMethod) {
076 clientRequest.setHttpMethod(httpMethod.getJavaxRsMethod());
077 return this;
078 }
079
080 /**
081 * Used when creating a request with arguments to execute.
082 *
083 * <p>
084 * Typical flow is:
085 * <ul>
086 * <li> {@link RestfulClient#createRequest(HttpMethod, String)}
087 * <li> {@link RestfulRequest#withArg(RequestParameter, Object)} for each arg
088 * <li> {@link RestfulRequest#execute()} - which calls this method.
089 * </ul>
090 */
091 public ClientRequestConfigurer configureArgs(final Map<RequestParameter<?>, Object> args) {
092 if (clientRequest.getHttpMethod() == null) {
093 throw new IllegalStateException("Must set up http method first");
094 }
095
096 final JsonRepresentation argsAsMap = JsonRepresentation.newMap();
097 for (final RequestParameter<?> requestParam : args.keySet()) {
098 put(args, requestParam, argsAsMap);
099 }
100 getHttpMethod().setUpArgs(this, argsAsMap);
101 return this;
102 }
103
104 private <P> void put(final Map<RequestParameter<?>, Object> args, final RequestParameter<P> requestParam, final JsonRepresentation argsAsMap) {
105 @SuppressWarnings("unchecked")
106 final P value = (P) args.get(requestParam);
107 final String valueStr = requestParam.getParser().asString(value);
108 argsAsMap.mapPut(requestParam.getName(), valueStr);
109 }
110
111 /**
112 * Used when following links (
113 * {@link RestfulClient#follow(LinkRepresentation)}).
114 */
115 public ClientRequestConfigurer configureArgs(final JsonRepresentation requestArgs) {
116 if (clientRequest.getHttpMethod() == null) {
117 throw new IllegalStateException("Must set up http method first");
118 }
119
120 getHttpMethod().setUpArgs(this, requestArgs);
121 return this;
122 }
123
124 /**
125 * Called back from
126 * {@link HttpMethod#setUpArgs(ClientRequestConfigurer, JsonRepresentation)}
127 */
128 ClientRequestConfigurer body(final JsonRepresentation requestArgs) {
129 clientRequest.body(MediaType.APPLICATION_JSON_TYPE, requestArgs.toString());
130 return this;
131 }
132
133 /**
134 * Called back from
135 * {@link HttpMethod#setUpArgs(ClientRequestConfigurer, JsonRepresentation)}
136 */
137 ClientRequestConfigurer queryString(final JsonRepresentation requestArgs) {
138 if (requestArgs.size() == 0) {
139 return this;
140 }
141 final String queryString = UrlEncodingUtils.urlEncode(requestArgs.toString());
142 uriBuilder.replaceQuery(queryString);
143 return this;
144 }
145
146 /**
147 * Called back from
148 * {@link HttpMethod#setUpArgs(ClientRequestConfigurer, JsonRepresentation)}
149 */
150 ClientRequestConfigurer queryArgs(final JsonRepresentation requestArgs) {
151 final MultivaluedMap<String, String> queryParameters = clientRequest.getQueryParameters();
152 for (final Map.Entry<String, JsonRepresentation> entry : requestArgs.mapIterable()) {
153 final String param = entry.getKey();
154 final JsonRepresentation argRepr = entry.getValue();
155 final String arg = UrlEncodingUtils.urlEncode(argRepr.asArg());
156 queryParameters.add(param, arg);
157 }
158 return this;
159 }
160
161 /**
162 * For testing.
163 */
164 ClientRequest getClientRequest() {
165 return clientRequest;
166 }
167
168 HttpMethod getHttpMethod() {
169 final String httpMethod = clientRequest.getHttpMethod();
170 return HttpMethod.valueOf(httpMethod);
171 }
172
173 }