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 }