001 package org.kuali.common.aws.ec2.model.security;
002
003 import static com.google.common.collect.Lists.newArrayList;
004 import static org.kuali.common.util.ListUtils.equalElements;
005
006 import java.util.Collections;
007 import java.util.Comparator;
008 import java.util.List;
009
010 import org.hibernate.validator.constraints.NotEmpty;
011 import org.kuali.common.core.build.ValidatingBuilder;
012 import org.kuali.common.core.validate.annotation.IdiotProofImmutable;
013 import org.kuali.common.core.validate.annotation.ValidPort;
014 import org.kuali.common.util.ObjectUtils;
015
016 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
017 import com.google.common.base.Objects;
018 import com.google.common.collect.ComparisonChain;
019 import com.google.common.collect.ImmutableList;
020
021 /**
022 * This is an immutable, slimmed down, version of the comparable AWS permissions object. Only supports a single port (no port ranges) and CIDR notations.
023 */
024 @IdiotProofImmutable
025 @JsonDeserialize(builder = Permission.Builder.class)
026 public final class Permission {
027
028 @ValidPort
029 private final int port;
030
031 private final Protocol protocol;
032
033 @NotEmpty
034 private final ImmutableList<String> cidrNotations;
035
036 public static Permission create(int port) {
037 return builder(port).build();
038 }
039
040 public static Builder builder(int port) {
041 return new Builder(port);
042 }
043
044 public static class Builder extends ValidatingBuilder<Permission> {
045
046 // Required
047 private final int port;
048
049 // Optional
050 private List<String> cidrNotations = newArrayList(CIDR.ANY.getNotation());
051 private Protocol protocol = Protocol.TCP;
052
053 public Builder(int port) {
054 this.port = port;
055 }
056
057 public Builder withCidrNotations(List<String> cidrNotations) {
058 this.cidrNotations = cidrNotations;
059 return this;
060 }
061
062 public Builder withProtocol(Protocol protocol) {
063 this.protocol = protocol;
064 return this;
065 }
066
067 @Override
068 public Permission build() {
069 // Changing this has implications for equals(), be careful
070 this.cidrNotations = newArrayList(cidrNotations);
071 Collections.sort(cidrNotations);
072 return validate(new Permission(this));
073 }
074 }
075
076 private Permission(Builder builder) {
077 this.protocol = builder.protocol;
078 this.port = builder.port;
079 this.cidrNotations = ImmutableList.copyOf(builder.cidrNotations);
080 }
081
082 public Protocol getProtocol() {
083 return protocol;
084 }
085
086 public int getPort() {
087 return port;
088 }
089
090 public List<String> getCidrNotations() {
091 return cidrNotations;
092 }
093
094 @Override
095 public int hashCode() {
096 final int prime = 31;
097 int result = Objects.hashCode(port, protocol);
098 for (String notation : cidrNotations) {
099 result = result * prime + notation.hashCode();
100 }
101 return result;
102 }
103
104 @Override
105 public boolean equals(Object object) {
106
107 // They are the same object
108 if (this == object) {
109 return true;
110 }
111
112 // Make sure object isn't null and is a Permission object
113 if (ObjectUtils.notEqual(this, object)) {
114 return false;
115 }
116
117 // Cast to a Permission object
118 Permission a = this;
119 Permission b = (Permission) object;
120
121 // If they both have the exact same list of CIDR notations, they are equal
122 // This only works because Builder.build() sorts the CIDR notation list
123 return Objects.equal(a.port, b.port) && Objects.equal(a.protocol, b.protocol) && equalElements(a.cidrNotations, b.cidrNotations);
124
125 }
126
127 // Singleton enum pattern
128 public enum DefaultComparator implements Comparator<Permission> {
129 INSTANCE;
130
131 @Override
132 public int compare(Permission one, Permission two) {
133 return ComparisonChain.start().compare(one.getPort(), two.getPort()).compare(one.getProtocol(), two.getProtocol()).result();
134 }
135 }
136
137 }