001/* 002 * Portions of this software was developed by employees of the National Institute 003 * of Standards and Technology (NIST), an agency of the Federal Government and is 004 * being made available as a public service. Pursuant to title 17 United States 005 * Code Section 105, works of NIST employees are not subject to copyright 006 * protection in the United States. This software may be subject to foreign 007 * copyright. Permission in the United States and in foreign countries, to the 008 * extent that NIST may hold copyright, to use, copy, modify, create derivative 009 * works, and distribute this software and its documentation without fee is hereby 010 * granted on a non-exclusive basis, provided that this notice and disclaimer 011 * of warranty appears in all copies. 012 * 013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 025 */ 026 027package gov.nist.secauto.metaschema.core.model.constraint; 028 029import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; 030import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; 031import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; 032import gov.nist.secauto.metaschema.core.util.CollectionUtil; 033import gov.nist.secauto.metaschema.core.util.ObjectUtils; 034 035import java.util.LinkedHashMap; 036import java.util.LinkedHashSet; 037import java.util.Map; 038import java.util.Objects; 039import java.util.Set; 040 041import javax.xml.namespace.QName; 042 043import edu.umd.cs.findbugs.annotations.NonNull; 044import edu.umd.cs.findbugs.annotations.Nullable; 045 046public abstract class AbstractConstraint implements IConstraint { // NOPMD - intentional data class 047 @Nullable 048 private final String id; 049 @Nullable 050 private final String formalName; 051 @Nullable 052 private final MarkupLine description; 053 @NonNull 054 private final ISource source; 055 @NonNull 056 private final Level level; 057 @NonNull 058 private final MetapathExpression target; 059 @Nullable 060 private final MarkupMultiline remarks; 061 @NonNull 062 private final Map<QName, Set<String>> properties; 063 064 /** 065 * Construct a new Metaschema constraint. 066 * 067 * @param id 068 * the optional identifier for the constraint 069 * @param formalName 070 * the constraint's formal name or {@code null} if not provided 071 * @param description 072 * the constraint's semantic description or {@code null} if not 073 * provided 074 * @param source 075 * information about the constraint source 076 * @param level 077 * the significance of a violation of this constraint 078 * @param target 079 * the Metapath expression identifying the nodes the constraint targets 080 * @param properties 081 * a collection of associated properties 082 * @param remarks 083 * optional remarks describing the intent of the constraint 084 */ 085 protected AbstractConstraint( 086 @Nullable String id, 087 @Nullable String formalName, 088 @Nullable MarkupLine description, 089 @NonNull ISource source, 090 @NonNull Level level, 091 @NonNull MetapathExpression target, 092 @NonNull Map<QName, Set<String>> properties, 093 @Nullable MarkupMultiline remarks) { 094 Objects.requireNonNull(target); 095 this.id = id; 096 this.formalName = formalName; 097 this.description = description; 098 this.source = source; 099 this.level = ObjectUtils.requireNonNull(level, "level"); 100 this.target = ObjectUtils.requireNonNull(target, "target"); 101 this.properties = properties; 102 this.remarks = remarks; 103 } 104 105 @Override 106 public String getId() { 107 return id; 108 } 109 110 @Override 111 public MarkupLine getDescription() { 112 return description; 113 } 114 115 @Override 116 public String getFormalName() { 117 return formalName; 118 } 119 120 @Override 121 public ISource getSource() { 122 return source; 123 } 124 125 @Override 126 @NonNull 127 public Level getLevel() { 128 return level; 129 } 130 131 @Override 132 public MetapathExpression getTarget() { 133 return target; 134 } 135 136 @Override 137 public Map<QName, Set<String>> getProperties() { 138 return CollectionUtil.unmodifiableMap(properties); 139 } 140 141 @Override 142 public MarkupMultiline getRemarks() { 143 return remarks; 144 } 145 146 public abstract static class AbstractConstraintBuilder< 147 T extends AbstractConstraintBuilder<T, 148 R>, 149 R extends AbstractConstraint> { 150 private String id; 151 private String formalName; 152 private MarkupLine description; 153 private ISource source; 154 @NonNull 155 private Level level = IConstraint.DEFAULT_LEVEL; 156 @NonNull 157 private MetapathExpression target = IConstraint.DEFAULT_TARGET; 158 @NonNull 159 private Map<QName, Set<String>> properties = new LinkedHashMap<>(); // NOPMD not thread safe 160 private MarkupMultiline remarks; 161 162 protected abstract T getThis(); 163 164 public T identifier(@NonNull String id) { 165 this.id = id; 166 return getThis(); 167 } 168 169 public T formalName(@NonNull String name) { 170 this.formalName = name; 171 return getThis(); 172 } 173 174 public T description(@NonNull MarkupLine description) { 175 this.description = description; 176 return getThis(); 177 } 178 179 public T source(@NonNull ISource source) { 180 this.source = source; 181 return getThis(); 182 } 183 184 public T level(@NonNull Level level) { 185 this.level = level; 186 return getThis(); 187 } 188 189 public T target(@NonNull MetapathExpression target) { 190 this.target = target; 191 return getThis(); 192 } 193 194 public T properties(@NonNull Map<QName, Set<String>> properties) { 195 this.properties = properties; 196 return getThis(); 197 } 198 199 public T property(@NonNull QName name, @NonNull String value) { 200 return property(name, CollectionUtil.singleton(value)); 201 } 202 203 public T property(@NonNull QName name, @NonNull Set<String> newValues) { 204 Set<String> existingValues = properties.get(name); 205 if (existingValues == null) { 206 existingValues = new LinkedHashSet<>(); 207 properties.put(name, existingValues); 208 } 209 210 existingValues.addAll(newValues); 211 return getThis(); 212 } 213 214 public T remarks(@NonNull MarkupMultiline remarks) { 215 this.remarks = remarks; 216 return getThis(); 217 } 218 219 protected void validate() { 220 ObjectUtils.requireNonNull(getSource()); 221 } 222 223 @NonNull 224 protected abstract R newInstance(); 225 226 @NonNull 227 public R build() { 228 validate(); 229 return newInstance(); 230 } 231 232 protected String getId() { 233 return id; 234 } 235 236 protected String getFormalName() { 237 return formalName; 238 } 239 240 protected MarkupLine getDescription() { 241 return description; 242 } 243 244 protected ISource getSource() { 245 return source; 246 } 247 248 @NonNull 249 protected Level getLevel() { 250 return level; 251 } 252 253 @NonNull 254 protected MetapathExpression getTarget() { 255 return target; 256 } 257 258 @NonNull 259 protected Map<QName, Set<String>> getProperties() { 260 return properties; 261 } 262 263 protected MarkupMultiline getRemarks() { 264 return remarks; 265 } 266 } 267}