1 /* 2 * Copyright 2020-2022 Foreseeti AB <https://foreseeti.com> 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.mal_lang.langspec.builders; 18 19 import static java.util.Objects.requireNonNull; 20 import static org.mal_lang.langspec.Utils.requireIdentifier; 21 22 import jakarta.json.JsonObject; 23 import java.util.LinkedHashMap; 24 import java.util.List; 25 import java.util.Map; 26 27 /** 28 * A builder for creating {@link org.mal_lang.langspec.Asset} objects. 29 * 30 * @since 1.0.0 31 */ 32 public final class AssetBuilder { 33 private final String name; 34 private final MetaBuilder meta = new MetaBuilder(); 35 private final String category; 36 private final boolean isAbstract; 37 private final String superAsset; 38 private final Map<String, VariableBuilder> variables = new LinkedHashMap<>(); 39 private final Map<String, AttackStepBuilder> attackSteps = new LinkedHashMap<>(); 40 private byte[] svgIcon = null; 41 private byte[] pngIcon = null; 42 43 /** 44 * Constructs a new {@code AssetBuilder} object. 45 * 46 * @param name the name of the asset 47 * @param category the category of the asset 48 * @param isAbstract whether the asset is abstract 49 * @param superAsset the super asset of the asset, or {@code null} 50 * @throws java.lang.NullPointerException if {@code name} or {@code category} is {@code null} 51 * @throws java.lang.IllegalArgumentException if {@code name} or {@code category} is not a valid 52 * identifier 53 * @since 1.0.0 54 */ 55 public AssetBuilder(String name, String category, boolean isAbstract, String superAsset) { 56 this.name = requireIdentifier(name); 57 this.category = requireIdentifier(category); 58 this.isAbstract = isAbstract; 59 this.superAsset = superAsset; 60 } 61 62 /** 63 * Returns the name of this {@code AssetBuilder} object. 64 * 65 * @return the name of this {@code AssetBuilder} object 66 * @since 1.0.0 67 */ 68 public String getName() { 69 return this.name; 70 } 71 72 /** 73 * Returns the meta info of this {@code AssetBuilder} object. 74 * 75 * @return the meta info of this {@code AssetBuilder} object 76 * @since 1.0.0 77 */ 78 public MetaBuilder getMeta() { 79 return this.meta; 80 } 81 82 /** 83 * Returns the category of this {@code AssetBuilder} object. 84 * 85 * @return the category of this {@code AssetBuilder} object 86 * @since 1.0.0 87 */ 88 public String getCategory() { 89 return this.category; 90 } 91 92 /** 93 * Returns whether this {@code AssetBuilder} object is abstract. 94 * 95 * @return whether this {@code AssetBuilder} object is abstract 96 * @since 1.0.0 97 */ 98 public boolean isAbstract() { 99 return this.isAbstract; 100 } 101 102 /** 103 * Returns the super asset of this {@code AssetBuilder} object, or {@code null} if no super asset 104 * has been set. 105 * 106 * @return the super asset of this {@code AssetBuilder} object, or {@code null} if no super asset 107 * has been set 108 * @since 1.0.0 109 */ 110 public String getSuperAsset() { 111 return this.superAsset; 112 } 113 114 /** 115 * Returns a list of all variables in this {@code AssetBuilder} object. 116 * 117 * @return a list of all variables in this {@code AssetBuilder} object 118 * @since 1.0.0 119 */ 120 public List<VariableBuilder> getVariables() { 121 return List.copyOf(this.variables.values()); 122 } 123 124 /** 125 * Adds a variable to this {@code AssetBuilder} object. 126 * 127 * @param variable the variable to add 128 * @return this {@code AssetBuilder} object 129 * @throws java.lang.NullPointerException if {@code variable} is {@code null} 130 * @since 1.0.0 131 */ 132 public AssetBuilder addVariable(VariableBuilder variable) { 133 requireNonNull(variable); 134 this.variables.put(variable.getName(), variable); 135 return this; 136 } 137 138 /** 139 * Returns a list of all attack steps in this {@code AssetBuilder} object. 140 * 141 * @return a list of all attack steps in this {@code AssetBuilder} object 142 * @since 1.0.0 143 */ 144 public List<AttackStepBuilder> getAttackSteps() { 145 return List.copyOf(this.attackSteps.values()); 146 } 147 148 /** 149 * Adds an attack step to this {@code AssetBuilder} object. 150 * 151 * @param attackStep the attack step to add 152 * @return this {@code AssetBuilder} object 153 * @throws java.lang.NullPointerException if {@code attackStep} is {@code null} 154 * @since 1.0.0 155 */ 156 public AssetBuilder addAttackStep(AttackStepBuilder attackStep) { 157 requireNonNull(attackStep); 158 this.attackSteps.put(attackStep.getName(), attackStep); 159 return this; 160 } 161 162 /** 163 * Returns the SVG icon of this {@code AssetBuilder} object, or {@code null} if no SVG icon has 164 * been set. 165 * 166 * @return the SVG icon of this {@code AssetBuilder} object, or {@code null} if no SVG icon has 167 * been set 168 * @since 1.0.0 169 */ 170 public byte[] getSvgIcon() { 171 return this.svgIcon == null ? null : this.svgIcon.clone(); 172 } 173 174 /** 175 * Sets the SVG icon of this {@code AssetBuilder} object. 176 * 177 * @param svgIcon the SVG icon to set 178 * @return this {@code AssetBuilder} object 179 * @throws java.lang.NullPointerException if {@code svgIcon} is {@code null} 180 * @since 1.0.0 181 */ 182 public AssetBuilder setSvgIcon(byte[] svgIcon) { 183 this.svgIcon = requireNonNull(svgIcon).clone(); 184 return this; 185 } 186 187 /** 188 * Returns the PNG icon of this {@code AssetBuilder} object, or {@code null} if no PNG icon has 189 * been set. 190 * 191 * @return the PNG icon of this {@code AssetBuilder} object, or {@code null} if no PNG icon has 192 * been set 193 * @since 1.0.0 194 */ 195 public byte[] getPngIcon() { 196 return this.pngIcon == null ? null : this.pngIcon.clone(); 197 } 198 199 /** 200 * Sets the PNG icon of this {@code AssetBuilder} object. 201 * 202 * @param pngIcon the PNG icon to set 203 * @return this {@code AssetBuilder} object 204 * @throws java.lang.NullPointerException if {@code pngIcon} is {@code null} 205 * @since 1.0.0 206 */ 207 public AssetBuilder setPngIcon(byte[] pngIcon) { 208 this.pngIcon = requireNonNull(pngIcon).clone(); 209 return this; 210 } 211 212 /** 213 * Creates a new {@code AssetBuilder} from a {@link jakarta.json.JsonObject}. 214 * 215 * @param jsonAsset the {@link jakarta.json.JsonObject} 216 * @param svgIcons the SVG icons of the language 217 * @param pngIcons the PNG icons of the language 218 * @return a new {@code AssetBuilder} from a {@link jakarta.json.JsonObject} 219 * @throws java.lang.NullPointerException if {@code jsonAsset}, {@code svgIcons}, or {@code 220 * pngIcons} is {@code null} 221 * @since 1.0.0 222 */ 223 public static AssetBuilder fromJson( 224 JsonObject jsonAsset, Map<String, byte[]> svgIcons, Map<String, byte[]> pngIcons) { 225 requireNonNull(jsonAsset); 226 requireNonNull(svgIcons); 227 requireNonNull(pngIcons); 228 var builder = 229 new AssetBuilder( 230 jsonAsset.getString("name"), 231 jsonAsset.getString("category"), 232 jsonAsset.getBoolean("isAbstract"), 233 jsonAsset.isNull("superAsset") ? null : jsonAsset.getString("superAsset")); 234 builder.getMeta().fromJson(jsonAsset.getJsonObject("meta")); 235 for (var jsonVariable : jsonAsset.getJsonArray("variables")) { 236 builder.addVariable(VariableBuilder.fromJson(jsonVariable.asJsonObject())); 237 } 238 for (var jsonAttackStep : jsonAsset.getJsonArray("attackSteps")) { 239 builder.addAttackStep(AttackStepBuilder.fromJson(jsonAttackStep.asJsonObject())); 240 } 241 if (svgIcons.containsKey(builder.getName())) { 242 builder.setSvgIcon(svgIcons.get(builder.getName())); 243 } 244 if (pngIcons.containsKey(builder.getName())) { 245 builder.setPngIcon(pngIcons.get(builder.getName())); 246 } 247 return builder; 248 } 249 }