001/* 002 * Copyright (c) 2023 Chris K Wensel <[email protected]>. All Rights Reserved. 003 * 004 * This Source Code Form is subject to the terms of the Mozilla Public 005 * License, v. 2.0. If a copy of the MPL was not distributed with this 006 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 007 */ 008 009package clusterless.commons.naming; 010 011import java.util.Objects; 012 013/** 014 * Creates an identifier to use as an export/import key for provider output/export values. 015 * <p/> 016 * <pre> 017 * aws:qualifier:[stage:]scopeName:scopeVersion:resourceNS:resourceType:resourceName 018 * </pre> 019 * <p/> 020 * Where the qualifier represents the type of value being exported/imported: 021 * - id 022 * - name 023 * - arn 024 * <p/> 025 * Where stage is the stage of the deployment, such as dev, test, prod, etc. It is optional. 026 * <p/> 027 * scopeName and scopeVersion are analogous to project names and versions. 028 * <p/> 029 * Resources are identified by a namespace, type, and name. 030 * <p/> 031 * 032 * <pre> 033 * ref:aws:id:project-a:20230101:core:compute:spot 034 * ref:aws:id:dev:project-a:20230101:core:compute:spot 035 * </pre> 036 */ 037public final class Ref { 038 public static Ref ref() { 039 return new Ref(); 040 } 041 042 public static Ref idRef() { 043 return new Ref().withQualifier(Qualifier.Id); 044 } 045 046 public static Ref arnRef() { 047 return new Ref().withQualifier(Qualifier.Arn); 048 } 049 050 public static Ref nameRef() { 051 return new Ref().withQualifier(Qualifier.Name); 052 } 053 054 public static boolean isRef(String value) { 055 return value != null && value.startsWith("ref:"); 056 } 057 058 public static String provider(String value) { 059 return value != null ? value.split(":")[1] : null; 060 } 061 062 final Label provider; 063 final Qualifier qualifier; 064 final Stage stage; 065 final Label scope; 066 final Fixed scopeVersion; 067 final Label resourceNs; 068 final Fixed resourceType; 069 final Label resourceName; 070 071 public Ref() { 072 provider = null; 073 stage = Stage.nullStage(); 074 scope = null; 075 scopeVersion = null; 076 resourceNs = null; 077 resourceType = null; 078 resourceName = null; 079 qualifier = null; 080 } 081 082 private Ref(Label provider, Qualifier qualifier, Stage stage, Label scope, Fixed scopeVersion, Label resourceNs, Fixed resourceType, Label resourceName) { 083 this.provider = provider; 084 this.qualifier = qualifier; 085 this.stage = stage == null ? Stage.nullStage() : stage.asLower(); 086 this.scope = scope; 087 this.scopeVersion = scopeVersion; 088 this.resourceNs = resourceNs; 089 this.resourceType = resourceType; 090 this.resourceName = resourceName; 091 } 092 093 public Ref withProvider(String provider) { 094 Objects.requireNonNull(provider); 095 return withProvider(Label.of(provider)); 096 } 097 098 public Ref withProvider(Label provider) { 099 Label.requireNonEmpty(provider); 100 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 101 } 102 103 public Ref withStage(Stage stage) { 104 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 105 } 106 107 public Ref withScope(String scope) { 108 return withScope(Label.of(scope)); 109 } 110 111 public Ref withScope(Label scope) { 112 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 113 } 114 115 public Ref withScopeVersion(String scopeVersion) { 116 return withScopeVersion(Fixed.of(scopeVersion)); 117 } 118 119 public Ref withScopeVersion(Fixed scopeVersion) { 120 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 121 } 122 123 public Ref withResourceNs(String resourceNs) { 124 return withResourceNs(Label.of(resourceNs)); 125 } 126 127 public Ref withResourceNs(Label resourceNs) { 128 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 129 } 130 131 public Ref withResourceType(String resourceType) { 132 return withResourceType(Fixed.of(resourceType)); 133 } 134 135 public Ref withResourceType(Fixed resourceType) { 136 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 137 } 138 139 public Ref withResourceName(String resourceName) { 140 return withResourceName(Label.of(resourceName)); 141 } 142 143 public Ref withResourceName(Label resourceName) { 144 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 145 } 146 147 public Ref withQualifier(Qualifier qualifier) { 148 return new Ref(provider, qualifier, stage, scope, scopeVersion, resourceNs, resourceType, resourceName); 149 } 150 151 public Label provider() { 152 return provider; 153 } 154 155 public Stage stage() { 156 return stage; 157 } 158 159 public Label scope() { 160 return scope; 161 } 162 163 public Fixed scopeVersion() { 164 return scopeVersion; 165 } 166 167 public Label resourceNs() { 168 return resourceNs; 169 } 170 171 public Fixed resourceType() { 172 return resourceType; 173 } 174 175 public Label resourceName() { 176 return resourceName; 177 } 178 179 public Qualifier qualifier() { 180 return qualifier; 181 } 182 183 public Label resourceLabel() { 184 requireNonNull(resourceNs, "resourceNs required"); 185 requireNonNull(resourceType, "resourceType required"); 186 requireNonNull(resourceName, "resourceName required"); 187 188 return Label.NULL 189 .with(resourceNs) 190 .with(Label.of(resourceType.value())) 191 .with(resourceName); 192 } 193 194 public Label label() { 195 requireNonNull(provider, "provider required"); 196 requireNonNull(qualifier, "qualifier required"); 197 requireNonNull(scope, "scope required"); 198 requireNonNull(scopeVersion, "scopeVersion required"); 199 requireNonNull(resourceNs, "resourceNs required"); 200 requireNonNull(resourceType, "resourceType required"); 201 requireNonNull(resourceName, "resourceName required"); 202 203 return Label.of("ref") 204 .with(provider) 205 .with(qualifier) 206 .with(stage) 207 .with(scope) 208 .with(scopeVersion) 209 .with(resourceNs) 210 .with(Label.of(resourceType.value())) 211 .with(resourceName); 212 } 213 214 private static void requireNonNull(Label label, String message) { 215 Objects.requireNonNull(label, message); 216 217 if (label.isNull()) { 218 throw new NullPointerException(message); 219 } 220 } 221 222 223 public String exportName() { 224 return label().lowerColonPath(); 225 } 226 227 @Override 228 public String toString() { 229 return exportName(); 230 } 231 232 @Override 233 public boolean equals(Object o) { 234 if (this == o) return true; 235 if (o == null || getClass() != o.getClass()) return false; 236 Ref ref = (Ref) o; 237 return Objects.equals(provider, ref.provider) && Objects.equals(stage, ref.stage) && Objects.equals(scope, ref.scope) && Objects.equals(scopeVersion, ref.scopeVersion) && Objects.equals(resourceNs, ref.resourceNs) && Objects.equals(resourceType, ref.resourceType) && Objects.equals(resourceName, ref.resourceName) && qualifier == ref.qualifier; 238 } 239 240 @Override 241 public int hashCode() { 242 return Objects.hash(provider, stage, scope, scopeVersion, resourceNs, resourceType, resourceName, qualifier); 243 } 244 245 public enum Qualifier implements Label.EnumLabel { 246 Name, 247 Id, 248 Arn; 249 } 250}