/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.isis.viewer.restfulobjects.applib.client;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.google.common.collect.Maps;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.core.BaseClientResponse;
import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
import org.apache.isis.viewer.restfulobjects.applib.util.Parser;
public final class RestfulRequest {
public enum DomainModel {
NONE, SIMPLE, FORMAL, SELECTABLE;
public static Parser<DomainModel> parser() {
return new Parser<RestfulRequest.DomainModel>() {
@Override
public DomainModel valueOf(final String str) {
return DomainModel.valueOf(str.toUpperCase());
}
@Override
public String asString(final DomainModel t) {
return t.name().toLowerCase();
}
};
}
@Override
public String toString() {
return name().toLowerCase();
}
}
public static class RequestParameter<Q> {
public static RequestParameter<List<List<String>>> FOLLOW_LINKS = new RequestParameter<List<List<String>>>("x-ro-follow-links", Parser.forListOfListOfStrings(), Collections.<List<String>> emptyList());
public static RequestParameter<Integer> PAGE = new RequestParameter<Integer>("x-ro-page", Parser.forInteger(), 1);
public static RequestParameter<Integer> PAGE_SIZE = new RequestParameter<Integer>("x-ro-page-size", Parser.forInteger(), 25);
public static RequestParameter<List<String>> SORT_BY = new RequestParameter<List<String>>("x-ro-sort-by", Parser.forListOfStrings(), Collections.<String> emptyList());
public static RequestParameter<DomainModel> DOMAIN_MODEL = new RequestParameter<DomainModel>("x-ro-domain-model", DomainModel.parser(), DomainModel.FORMAL);
public static RequestParameter<Boolean> VALIDATE_ONLY = new RequestParameter<Boolean>("x-ro-validate-only", Parser.forBoolean(), false);
private final String name;
private final Parser<Q> parser;
private final Q defaultValue;
private RequestParameter(final String name, final Parser<Q> parser, final Q defaultValue) {
this.name = name;
this.parser = parser;
this.defaultValue = defaultValue;
}
public String getName() {
return name;
}
public Parser<Q> getParser() {
return parser;
}
public Q valueOf(final JsonRepresentation parameterRepresentation) {
if (parameterRepresentation == null) {
return defaultValue;
}
if (!parameterRepresentation.isMap()) {
return defaultValue;
}
final Q parsedValue = getParser().valueOf(parameterRepresentation.getRepresentation(getName()));
return parsedValue != null ? parsedValue : defaultValue;
}
public Q getDefault() {
return defaultValue;
}
@Override
public String toString() {
return getName();
}
}
public static class Header<X> {
public static Header<String> IF_MATCH = new Header<String>("If-Match", Parser.forString());
public static Header<List<MediaType>> ACCEPT = new Header<List<MediaType>>("Accept", Parser.forListOfJaxRsMediaTypes());
private final String name;
private final Parser<X> parser;
/**
* public visibility for testing purposes only.
*/
public Header(final String name, final Parser<X> parser) {
this.name = name;
this.parser = parser;
}
public String getName() {
return name;
}
public Parser<X> getParser() {
return parser;
}
void setHeader(final ClientRequestConfigurer clientRequestConfigurer, final X t) {
clientRequestConfigurer.header(getName(), parser.asString(t));
}
@Override
public String toString() {
return getName();
}
}
private final ClientRequestConfigurer clientRequestConfigurer;
private final Map<RequestParameter<?>, Object> args = Maps.newLinkedHashMap();
public RestfulRequest(final ClientRequestConfigurer clientRequestConfigurer) {
this.clientRequestConfigurer = clientRequestConfigurer;
}
public <T> RestfulRequest withHeader(final Header<T> header, final T t) {
header.setHeader(clientRequestConfigurer, t);
return this;
}
public <T> RestfulRequest withHeader(final Header<List<T>> header, final T... ts) {
header.setHeader(clientRequestConfigurer, Arrays.asList(ts));
return this;
}
public <Q> RestfulRequest withArg(final RestfulRequest.RequestParameter<Q> queryParam, final String argStrFormat, final Object... args) {
final String argStr = String.format(argStrFormat, args);
final Q arg = queryParam.getParser().valueOf(argStr);
return withArg(queryParam, arg);
}
public <Q> RestfulRequest withArg(final RestfulRequest.RequestParameter<Q> queryParam, final Q arg) {
args.put(queryParam, arg);
return this;
}
public RestfulResponse<JsonRepresentation> execute() {
try {
if (!args.isEmpty()) {
clientRequestConfigurer.configureArgs(args);
}
final ClientRequest clientRequest = clientRequestConfigurer.getClientRequest();
final Response response = clientRequest.execute();
// this is a bit hacky
@SuppressWarnings("unchecked")
final BaseClientResponse<String> restEasyResponse = (BaseClientResponse<String>) response;
restEasyResponse.setReturnType(String.class);
return RestfulResponse.ofT(response);
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
}
@SuppressWarnings("unchecked")
public <T extends JsonRepresentation> RestfulResponse<T> executeT() {
final RestfulResponse<JsonRepresentation> restfulResponse = execute();
return (RestfulResponse<T>) restfulResponse;
}
/**
* For testing only.
*/
ClientRequestConfigurer getClientRequestConfigurer() {
return clientRequestConfigurer;
}
}