de.otto.jsonhome.model.Hints Maven / Gradle / Ivy
/*
* Copyright 2012 Guido Steinacker
*
* 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 de.otto.jsonhome.model;
import java.util.*;
import static de.otto.jsonhome.model.Documentation.emptyDocs;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableSet;
import static java.util.EnumSet.copyOf;
import static java.util.EnumSet.noneOf;
/**
* Hints are used to describe a resource: the allowed HTTP methods, the supported representations,
* required preconditions of an operation, the current status and possibly some documentation.
*
* All these information are optional. You should not completely rely on the information of the hints.
* For example, only because the hints do no contain a HTTP method, this must not necessarily mean that
* the method is not allowed for a resource.
*
* However, the JsonHomeGenerator will fortunately always find useful and correct hints...
*
* This implementation is immutable.
*
* @author Guido Steinacker
* @since 30.09.12
* @see http://tools.ietf.org/html/draft-nottingham-json-home-02#section-5
*/
public final class Hints {
public static final Hints EMPTY_HINTS = hints(
EnumSet.noneOf(Allow.class), Collections.emptyList()
);
private final Set allows;
private final List representations;
private final List acceptPut;
private final List acceptPost;
private final List acceptPatch;
private final List acceptRanges;
private final List preferences;
private final List preconditionReq;
private final List authReq;
private final Status status;
private final Documentation docs;
/**
* Returns an empty Hints instance.
*
* @return EMPTY_HINTS
*/
public static Hints emptyHints() {
return EMPTY_HINTS;
}
/**
* Creates hints with information about allowed HTTP methods and the supported representations of the resource.
*
* The status is set to Status.OK, all other fields will be empty (but not null).
*
* @param allows the allowed HTTP methods
* @param representations the representations of the resource
* @return Hints
*/
public static Hints hints(final Set allows,
final List representations) {
return hints(allows,
representations,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
Status.OK,
emptyDocs());
}
public static Hints hints(final Set allows,
final List representations,
final List acceptPut,
final List acceptPost,
final List acceptPatch,
final List acceptRanges,
final List preferences,
final List preconditionReq,
final List authReq,
final Status status,
final Documentation docs) {
return new Hints(
allows,
representations, acceptPut, acceptPost, acceptPatch,
acceptRanges,
preferences,
preconditionReq,
authReq,
status,
docs);
}
private Hints(final Set allows,
final List representations,
final List acceptPut,
final List acceptPost,
final List acceptPatch,
final List acceptRanges,
final List preferences,
final List preconditionReq,
final List authReq,
final Status status,
final Documentation docs) {
if (!acceptPost.isEmpty() && !allows.contains(Allow.POST)) {
throw new IllegalArgumentException("POST is not allowed but accept-post is provided.");
}
if (!acceptPut.isEmpty() && !allows.contains(Allow.PUT)) {
throw new IllegalArgumentException("PUT is not allowed but accept-put is provided.");
}
if (!acceptPatch.isEmpty() && !allows.contains(Allow.PATCH)) {
throw new IllegalArgumentException("PATCH is not allowed but accept-patch is provided.");
}
this.allows = unmodifiableSet(copyOf(allows));
this.representations = unmodifiableList(new ArrayList(representations));
this.acceptPut = acceptPut;
this.acceptPost = acceptPost;
this.acceptPatch = acceptPatch;
this.acceptRanges = unmodifiableList(acceptRanges);
this.preferences = unmodifiableList(preferences);
this.preconditionReq = unmodifiableList(new ArrayList(preconditionReq));
this.authReq = unmodifiableList(new ArrayList(authReq));
this.status = status != null ? status : Status.OK;
this.docs = docs != null ? docs : emptyDocs();
}
/**
* @return the list of allowed HTTP methods.
* @see http://tools.ietf.org/html/draft-nottingham-json-home-02#section-5.1
*/
public Set getAllows() {
return allows;
}
/**
* @return the list of representations supported for this resource link.
* @see http://tools.ietf.org/html/draft-nottingham-json-home-02#section-5.2
*/
public List getRepresentations() {
return representations;
}
/**
* @return the accept-put hint, declaring the accepted representations of a HTTP PUT request.
*/
public List getAcceptPut() {
return acceptPut;
}
/**
* @return the accept-post hint, declaring the accepted representations of a HTTP POST request.
*/
public List getAcceptPost() {
return acceptPost;
}
/**
* @return the accept-patch hint, declaring the accepted representations of a HTTP PATCH request.
*/
public List getAcceptPatch() {
return acceptPatch;
}
/**
* @return the accept-ranges hint, declaring the accepted range requests .
*/
public List getAcceptRanges() {
return acceptRanges;
}
/**
* @return the preferences supported by the hinted resource.
*/
public List getPreferences() {
return preferences;
}
/**
* @return the required preconditions.
*/
public List getPreconditionReq() {
return preconditionReq;
}
/**
* @return the required authentication.
*/
public List getAuthReq() {
return authReq;
}
/**
* @return Status specifies whether the resource is OK, DEPRECATED or GONE.
*/
public Status getStatus() {
return status;
}
/**
* Human-readable documentation of a ResourceLink.
*
* @return Documentation
*/
public Documentation getDocs() {
return docs;
}
/**
* Merges the hints of two resource links..
*
* @param other the hints of the other resource link
* @return a new, merged Hints instance
*/
public Hints mergeWith(final Hints other) {
final EnumSet allows = this.allows.isEmpty() ? noneOf(Allow.class) : copyOf(this.allows);
allows.addAll(other.getAllows());
final Set representations = new LinkedHashSet(this.representations);
representations.addAll(other.getRepresentations());
final Set acceptPut = new LinkedHashSet(this.acceptPut);
acceptPut.addAll(other.getAcceptPut());
final Set acceptPost = new LinkedHashSet(this.acceptPost);
acceptPost.addAll(other.getAcceptPost());
final Set acceptPatch = new LinkedHashSet(this.acceptPatch);
acceptPatch.addAll(other.getAcceptPatch());
final Set acceptRanges = new LinkedHashSet(this.acceptRanges);
acceptRanges.addAll(other.getAcceptRanges());
final Set preferences = new LinkedHashSet(this.preferences);
preferences.addAll(other.getPreferences());
final Set preconditionReq = new LinkedHashSet(this.preconditionReq);
preconditionReq.addAll(other.getPreconditionReq());
final List mergedAuth = mergeAuthReq(other.getAuthReq());
return hints(
allows,
new ArrayList(representations),
new ArrayList(acceptPut),
new ArrayList(acceptPost),
new ArrayList(acceptPatch),
new ArrayList(acceptRanges),
new ArrayList(preferences),
new ArrayList(preconditionReq),
mergedAuth,
status.mergeWith(other.getStatus()),
docs.mergeWith(other.getDocs())
);
}
private List mergeAuthReq(final List otherAuthReq) {
final Map> authReq = new TreeMap>();
for (final Authentication auth : this.authReq) {
authReq.put(auth.getScheme(), new TreeSet(auth.getRealms()));
}
for (final Authentication auth : otherAuthReq) {
if (authReq.containsKey(auth.getScheme())) {
authReq.get(auth.getScheme()).addAll(auth.getRealms());
} else {
authReq.put(auth.getScheme(), new TreeSet(auth.getRealms()));
}
}
final List mergedAuth = new ArrayList();
for (final String scheme : authReq.keySet()) {
mergedAuth.add(Authentication.authReq(scheme, new ArrayList(authReq.get(scheme))));
}
return mergedAuth;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Hints hints = (Hints) o;
if (acceptPatch != null ? !acceptPatch.equals(hints.acceptPatch) : hints.acceptPatch != null) return false;
if (acceptPost != null ? !acceptPost.equals(hints.acceptPost) : hints.acceptPost != null) return false;
if (acceptPut != null ? !acceptPut.equals(hints.acceptPut) : hints.acceptPut != null) return false;
if (acceptRanges != null ? !acceptRanges.equals(hints.acceptRanges) : hints.acceptRanges != null) return false;
if (allows != null ? !allows.equals(hints.allows) : hints.allows != null) return false;
if (authReq != null ? !authReq.equals(hints.authReq) : hints.authReq != null) return false;
if (docs != null ? !docs.equals(hints.docs) : hints.docs != null) return false;
if (preconditionReq != null ? !preconditionReq.equals(hints.preconditionReq) : hints.preconditionReq != null)
return false;
if (preferences != null ? !preferences.equals(hints.preferences) : hints.preferences != null) return false;
if (representations != null ? !representations.equals(hints.representations) : hints.representations != null)
return false;
if (status != hints.status) return false;
return true;
}
@Override
public int hashCode() {
int result = allows != null ? allows.hashCode() : 0;
result = 31 * result + (representations != null ? representations.hashCode() : 0);
result = 31 * result + (acceptPut != null ? acceptPut.hashCode() : 0);
result = 31 * result + (acceptPost != null ? acceptPost.hashCode() : 0);
result = 31 * result + (acceptPatch != null ? acceptPatch.hashCode() : 0);
result = 31 * result + (acceptRanges != null ? acceptRanges.hashCode() : 0);
result = 31 * result + (preferences != null ? preferences.hashCode() : 0);
result = 31 * result + (preconditionReq != null ? preconditionReq.hashCode() : 0);
result = 31 * result + (authReq != null ? authReq.hashCode() : 0);
result = 31 * result + (status != null ? status.hashCode() : 0);
result = 31 * result + (docs != null ? docs.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Hints{" +
"allows=" + allows +
", representations=" + representations +
", acceptPut=" + acceptPut +
", acceptPost=" + acceptPost +
", acceptPatch=" + acceptPatch +
", acceptRanges=" + acceptRanges +
", preferences=" + preferences +
", preconditionReq=" + preconditionReq +
", authReq=" + authReq +
", status=" + status +
", docs=" + docs +
'}';
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy