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 */ 019package org.apache.isis.viewer.restfulobjects.applib.client; 020 021import java.util.Arrays; 022import java.util.Collections; 023import java.util.List; 024import java.util.Map; 025 026import javax.ws.rs.core.MediaType; 027import javax.ws.rs.core.Response; 028 029import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation; 030import org.apache.isis.viewer.restfulobjects.applib.util.Parser; 031import org.jboss.resteasy.client.core.BaseClientResponse; 032 033import com.google.common.collect.Maps; 034 035public 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.FORMAL); 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.forListOfJaxRsMediaTypes()); 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}