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