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.Arrays;
022 import java.util.Collections;
023 import java.util.List;
024 import java.util.Map;
025
026 import javax.ws.rs.core.MediaType;
027 import javax.ws.rs.core.Response;
028
029 import com.google.common.collect.Maps;
030
031 import org.jboss.resteasy.client.core.BaseClientResponse;
032
033 import org.apache.isis.viewer.restfulobjects.applib.util.Parser;
034
035 public final class RestfulRequest {
036
037 public enum DomainModel {
038 NONE, SIMPLE, FORMAL, SELECTABLE;
039
040 public static Parser<DomainModel> parser() {
041 return new Parser<RestfulRequest.DomainModel>() {
042
043 @Override
044 public DomainModel valueOf(final String str) {
045 return DomainModel.valueOf(str.toUpperCase());
046 }
047
048 @Override
049 public String asString(final DomainModel t) {
050 return t.name().toLowerCase();
051 }
052 };
053 }
054
055 @Override
056 public String toString() {
057 return name().toLowerCase();
058 }
059 }
060
061 public static class RequestParameter<Q> {
062
063 public static RequestParameter<List<List<String>>> FOLLOW_LINKS = new RequestParameter<List<List<String>>>("x-ro-follow-links", Parser.forListOfListOfStrings(), Collections.<List<String>> emptyList());
064 public static RequestParameter<Integer> PAGE = new RequestParameter<Integer>("x-ro-page", Parser.forInteger(), 1);
065 public static RequestParameter<Integer> PAGE_SIZE = new RequestParameter<Integer>("x-ro-page-size", Parser.forInteger(), 25);
066 public static RequestParameter<List<String>> SORT_BY = new RequestParameter<List<String>>("x-ro-sort-by", Parser.forListOfStrings(), Collections.<String> emptyList());
067 public static RequestParameter<DomainModel> DOMAIN_MODEL = new RequestParameter<DomainModel>("x-ro-domain-model", DomainModel.parser(), DomainModel.SIMPLE);
068 public static RequestParameter<Boolean> VALIDATE_ONLY = new RequestParameter<Boolean>("x-ro-validate-only", Parser.forBoolean(), false);
069
070 private final String name;
071 private final Parser<Q> parser;
072 private final Q defaultValue;
073
074 private RequestParameter(final String name, final Parser<Q> parser, final Q defaultValue) {
075 this.name = name;
076 this.parser = parser;
077 this.defaultValue = defaultValue;
078 }
079
080 public String getName() {
081 return name;
082 }
083
084 public Parser<Q> getParser() {
085 return parser;
086 }
087
088 public Q valueOf(final JsonRepresentation parameterRepresentation) {
089 if (parameterRepresentation == null) {
090 return defaultValue;
091 }
092 if (!parameterRepresentation.isMap()) {
093 return defaultValue;
094 }
095 final Q parsedValue = getParser().valueOf(parameterRepresentation.getRepresentation(getName()));
096 return parsedValue != null ? parsedValue : defaultValue;
097 }
098
099 public Q getDefault() {
100 return defaultValue;
101 }
102
103 @Override
104 public String toString() {
105 return getName();
106 }
107 }
108
109 public static class Header<X> {
110 public static Header<String> IF_MATCH = new Header<String>("If-Match", Parser.forString());
111 public static Header<List<MediaType>> ACCEPT = new Header<List<MediaType>>("Accept", Parser.forListOfMediaTypes());
112
113 private final String name;
114 private final Parser<X> parser;
115
116 /**
117 * public visibility for testing purposes only.
118 */
119 public Header(final String name, final Parser<X> parser) {
120 this.name = name;
121 this.parser = parser;
122 }
123
124 public String getName() {
125 return name;
126 }
127
128 public Parser<X> getParser() {
129 return parser;
130 }
131
132 void setHeader(final ClientRequestConfigurer clientRequestConfigurer, final X t) {
133 clientRequestConfigurer.header(getName(), parser.asString(t));
134 }
135
136 @Override
137 public String toString() {
138 return getName();
139 }
140 }
141
142 private final ClientRequestConfigurer clientRequestConfigurer;
143 private final Map<RequestParameter<?>, Object> args = Maps.newLinkedHashMap();
144
145 public RestfulRequest(final ClientRequestConfigurer clientRequestConfigurer) {
146 this.clientRequestConfigurer = clientRequestConfigurer;
147 }
148
149 public <T> RestfulRequest withHeader(final Header<T> header, final T t) {
150 header.setHeader(clientRequestConfigurer, t);
151 return this;
152 }
153
154 public <T> RestfulRequest withHeader(final Header<List<T>> header, final T... ts) {
155 header.setHeader(clientRequestConfigurer, Arrays.asList(ts));
156 return this;
157 }
158
159 public <Q> RestfulRequest withArg(final RestfulRequest.RequestParameter<Q> queryParam, final String argStrFormat, final Object... args) {
160 final String argStr = String.format(argStrFormat, args);
161 final Q arg = queryParam.getParser().valueOf(argStr);
162 return withArg(queryParam, arg);
163 }
164
165 public <Q> RestfulRequest withArg(final RestfulRequest.RequestParameter<Q> queryParam, final Q arg) {
166 args.put(queryParam, arg);
167 return this;
168 }
169
170 public RestfulResponse<JsonRepresentation> execute() {
171 try {
172 if (!args.isEmpty()) {
173 clientRequestConfigurer.configureArgs(args);
174 }
175 final Response response = clientRequestConfigurer.getClientRequest().execute();
176
177 // this is a bit hacky
178 @SuppressWarnings("unchecked")
179 final BaseClientResponse<String> restEasyResponse = (BaseClientResponse<String>) response;
180 restEasyResponse.setReturnType(String.class);
181
182 return RestfulResponse.ofT(response);
183 } catch (final Exception ex) {
184 throw new RuntimeException(ex);
185 }
186 }
187
188 @SuppressWarnings("unchecked")
189 public <T extends JsonRepresentation> RestfulResponse<T> executeT() {
190 final RestfulResponse<JsonRepresentation> restfulResponse = execute();
191 return (RestfulResponse<T>) restfulResponse;
192 }
193
194 /**
195 * For testing only.
196 */
197 ClientRequestConfigurer getClientRequestConfigurer() {
198 return clientRequestConfigurer;
199 }
200
201 }