Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2016 Google Inc.
*
* Licensed 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 com.google.api.tools.framework.aspects.http.model;
import com.google.api.HttpRule;
import com.google.api.tools.framework.model.Field;
import com.google.api.tools.framework.model.FieldSelector;
import com.google.api.tools.framework.model.MessageType;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.inject.Key;
import java.util.List;
/**
* Describes the mapping of a method to HTTP. Attached by the aspects to methods which do have an
* http configuration.
*/
public class HttpAttribute {
/** Key used to access this attribute. */
public static final Key KEY = Key.get(HttpAttribute.class);
/** Base class for path segments. */
public abstract static class PathSegment {
/** Returns the syntax of this segment. */
public abstract String syntax();
@Override
public String toString() {
return syntax();
}
/** Returns the syntax for a full path given as a list of segments. */
public static String toSyntax(Iterable parts) {
return toSyntax(parts, true);
}
static String toSyntax(Iterable parts, boolean leadingSeparator) {
StringBuilder result = new StringBuilder();
for (PathSegment part : parts) {
if (leadingSeparator || result.length() > 0) {
result.append(part.separator());
}
result.append(part.syntax());
}
return result.toString();
}
/** Returns the separator to be used before this path segment. Defaults to '/'. */
String separator() {
return "/";
}
}
/**
* A path segment representing a wildcard, which is bounded (matches 1 segment) or unbounded
* (matches 1 or more segments).
*/
public static class WildcardSegment extends PathSegment {
private final boolean unbounded;
public WildcardSegment(boolean unbounded) {
this.unbounded = unbounded;
}
public boolean isUnbounded() {
return unbounded;
}
@Override
public String syntax() {
return unbounded ? "**" : "*";
}
}
/** A path segment representing a literal. */
public static class LiteralSegment extends PathSegment {
private final String literal;
private final boolean isTrailingCustomVerb;
public LiteralSegment(String literal) {
this.literal = literal;
this.isTrailingCustomVerb = false;
}
public LiteralSegment(String literal, boolean isTrailingCustomVerb) {
this.literal = literal;
this.isTrailingCustomVerb = isTrailingCustomVerb;
}
public String getLiteral() {
return literal;
}
public boolean isTrailingCustomVerb() {
return isTrailingCustomVerb;
}
@Override
public String syntax() {
return literal;
}
@Override
String separator() {
return isTrailingCustomVerb ? ":" : "/";
}
}
/** A path segment representing a field reference. */
public static class FieldSegment extends PathSegment {
private final String fieldPath;
private final ImmutableList subPath;
private FieldSelector selector;
public FieldSegment(String fieldPath, ImmutableList subPath) {
this.fieldPath = Preconditions.checkNotNull(fieldPath);
this.subPath = Preconditions.checkNotNull(subPath);
}
public String getFieldPath() {
return null == selector ? fieldPath : selector.toString();
}
public ImmutableList getSubPath() {
return subPath;
}
/** Gets the field this segment links to. */
public FieldSelector getFieldSelector() {
return selector;
}
/** Sets the field this segment links to. */
public void setFieldSelector(FieldSelector selector) {
this.selector = selector;
}
@Override
public String syntax() {
StringBuilder result = new StringBuilder();
result.append('{');
result.append(getFieldPath());
if (!subPath.isEmpty()) {
result.append('=');
result.append(PathSegment.toSyntax(subPath, false));
}
result.append('}');
return result.toString();
}
}
private HttpRule currentRule;
private final MethodKind methodKind;
private final MessageType message;
private final ImmutableList path;
private final String body;
private final boolean isFromIdl;
private final ImmutableList additionalBindings;
private final boolean isPrimary;
private RestMethod restMethod;
private ImmutableList flattenedPath;
/**
* Constructs an http binding for the given method kind, message, path, and body. See
* documentation of the getters for the meaning of those values.
*/
public HttpAttribute(
HttpRule rule,
MethodKind methodKind,
MessageType message,
ImmutableList path,
String body,
boolean isFromIdl,
ImmutableList additionalBindings,
boolean isPrimary) {
this.currentRule = Preconditions.checkNotNull(rule);
this.methodKind = Preconditions.checkNotNull(methodKind);
this.message = Preconditions.checkNotNull(message);
this.path = Preconditions.checkNotNull(path);
this.body = body;
this.isFromIdl = isFromIdl;
this.additionalBindings = Preconditions.checkNotNull(additionalBindings);
this.isPrimary = isPrimary;
}
/** Creates an empty binding for a method which is not exposed via http. */
public static HttpAttribute noConfig(MessageType message) {
HttpAttribute config =
new HttpAttribute(
HttpRule.getDefaultInstance(),
MethodKind.NONE,
message,
ImmutableList.of(),
null,
false,
ImmutableList.of(),
true);
config.setFields(ImmutableList.of(), ImmutableList.of());
return config;
}
/** Returns the name of the any field specified in the underlying http rule. */
public String getAnySpecifiedFieldInHttpRule() {
String fieldName;
if (Strings.isNullOrEmpty(getHttpRule().getSelector())) {
fieldName = "post";
switch (getMethodKind()) {
case GET:
fieldName = "get";
break;
case PUT:
fieldName = "put";
break;
case POST:
fieldName = "post";
break;
case PATCH:
fieldName = "patch";
break;
case DELETE:
fieldName = "delete";
break;
default:
fieldName = "post";
break;
}
} else {
fieldName = "selector";
}
return fieldName;
}
/** Returns true if this is the primary binding. */
public boolean isPrimary() {
return isPrimary;
}
/** Returns the associated rest method. Each HTTP binding has one. */
public RestMethod getRestMethod() {
return restMethod;
}
/** Sets the rest method. */
public void setRestMethod(RestMethod method) {
this.restMethod = method;
}
/**
* Create a new HTTP binding where the HTTP paths are rooted underneath the provided path.
* replaces the first segment in the path by the list of literal segments obtained from the
* newRoot parameter.
*/
public HttpAttribute reroot(final String newRoot) {
// Compute new path.
ImmutableList.Builder changedPath = ImmutableList.builder();
for (String comp : Splitter.on('/').omitEmptyStrings().trimResults().split(newRoot)) {
changedPath.add(new LiteralSegment(comp));
}
changedPath.addAll(path.subList(1, path.size()));
// Change rule.
HttpRule.Builder changedRule = currentRule.toBuilder();
String changedPathPattern = PathSegment.toSyntax(changedPath.build());
switch (currentRule.getPatternCase()) {
case GET:
changedRule.setGet(changedPathPattern);
break;
case PUT:
changedRule.setPut(changedPathPattern);
break;
case POST:
changedRule.setPost(changedPathPattern);
break;
case PATCH:
changedRule.setPatch(changedPathPattern);
break;
case DELETE:
changedRule.setDelete(changedPathPattern);
break;
default:
// TODO Shouldn't this have a case for CUSTOM? How is this reroot() used?
break;
}
// Change additional bindings.
ImmutableList changedAdditionalBindings =
FluentIterable.from(additionalBindings)
.transform(
new Function() {
@Override
public HttpAttribute apply(HttpAttribute attrib) {
return attrib.reroot(newRoot);
}
})
.toList();
// Return new binding.
HttpAttribute attrib =
new HttpAttribute(
changedRule.build(),
methodKind,
message,
changedPath.build(),
body,
isFromIdl,
changedAdditionalBindings,
isPrimary);
attrib.pathSelectors = pathSelectors;
attrib.bodySelectors = bodySelectors;
attrib.paramSelectors = paramSelectors;
return attrib;
}
/**
* Returns an {@link Iterable} that includes the primary binding (the current one) and all
* additional bindings. The primary binding is always the first item in the {@link Iterable}.
*/
public Iterable getAllBindings() {
return FluentIterable.from(ImmutableList.of(this)).append(additionalBindings);
}
// -------------------------------------------------------------------------
// Syntax
/** Gets the underlying http rule. */
public HttpRule getHttpRule() {
return currentRule;
}
/** Gets the http method kind. */
public MethodKind getMethodKind() {
return methodKind;
}
/** Gets the request message this configuration is associated with. */
public MessageType getMessage() {
return message;
}
/** Gets the path as a list of segments. */
public ImmutableList getPath() {
return path;
}
/** Gets the flattened path, where all FieldSegments have been replaced by their sub-paths. */
public ImmutableList getFlatPath() {
if (flattenedPath != null) {
return flattenedPath;
}
ImmutableList.Builder builder = ImmutableList.builder();
flatten(builder, path);
return flattenedPath = builder.build();
}
private void flatten(Builder builder, ImmutableList path) {
for (PathSegment segm : path) {
if (segm instanceof FieldSegment) {
FieldSegment fieldSegm = (FieldSegment) segm;
if (fieldSegm.subPath.isEmpty()) {
// looking at {name}, will be replaced by '*'.
builder.add(new WildcardSegment(false));
} else {
flatten(builder, ((FieldSegment) segm).getSubPath());
}
} else {
builder.add(segm);
}
}
}
/** Gets the body or null if none specified. */
public String getBody() {
return body;
}
/** Return true if the http binding information is from IDL. */
public boolean isFromIdl() {
return isFromIdl;
}
/** Returns true if the body is configured to include unbound fields. */
public boolean bodyCapturesUnboundFields() {
return "*".equals(body);
}
// -------------------------------------------------------------------------
// Attributes belonging to merged stage
private ImmutableList pathSelectors;
private ImmutableList paramSelectors;
private ImmutableList bodySelectors;
/** Gets the fields which are bound via the path. */
public ImmutableList getPathSelectors() {
return pathSelectors;
}
/** Gets fields which are bound via parameters. */
public ImmutableList getParamSelectors() {
return paramSelectors;
}
/** Get fields which are bound via the body. */
public ImmutableList getBodySelectors() {
return bodySelectors;
}
/**
* Sets the parameter and body fields. Also derives the path fields from the path, assuming they
* have been resolved.
*/
public void setFields(
ImmutableList paramFields, ImmutableList bodyFields) {
this.paramSelectors = paramFields;
this.bodySelectors = bodyFields;
this.pathSelectors =
FluentIterable.from(path)
.filter(FieldSegment.class)
.filter(
new Predicate() {
@Override
public boolean apply(FieldSegment seg) {
return seg.getFieldSelector() != null;
}
})
.transform(
new Function() {
@Override
public FieldSelector apply(FieldSegment seg) {
return seg.getFieldSelector();
}
})
.toList();
}
// -------------------------------------------------------------------------
// Attributes belonging to scoped stage
private ImmutableList visiblePathSelectors;
private ImmutableList visibleParamSelectors;
private ImmutableList visibleBodySelectors;
/** Gets visible fields which are bound via the path. */
public ImmutableList getVisiblePathSelectors() {
if (visiblePathSelectors == null) {
visiblePathSelectors = buildVisibleSelectors(pathSelectors);
}
return visiblePathSelectors;
}
/** Gets visible fields which are bound via parameters. */
public ImmutableList getVisibleParamSelectors() {
if (visibleParamSelectors == null) {
visibleParamSelectors = buildVisibleSelectors(paramSelectors);
}
return visibleParamSelectors;
}
/** Gets visible fields which are bound via body. */
public ImmutableList getVisibleBodySelectors() {
if (visibleBodySelectors == null) {
visibleBodySelectors = buildVisibleSelectors(bodySelectors);
}
return visibleBodySelectors;
}
private ImmutableList buildVisibleSelectors(List selectors) {
ImmutableList.Builder listBuilder = ImmutableList.builder();
for (FieldSelector selector : selectors) {
boolean hasInvisibleField = false;
for (Field field : selector.getFields()) {
if (!field.isReachable()) {
hasInvisibleField = true;
break;
}
}
// Only include FieldSelector that has no invisible field.
if (!hasInvisibleField) {
listBuilder.add(selector);
}
}
return listBuilder.build();
}
public ImmutableList getAdditionalBindings() {
return additionalBindings;
}
}