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.DynamicContext; 032import gov.nist.secauto.metaschema.core.metapath.ISequence; 033import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; 034import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem; 035 036import java.net.URI; 037import java.util.HashMap; 038import java.util.Map; 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 046/** 047 * Represents a rule constraining the model of a Metaschema assembly, field or 048 * flag. Provides a common interface for all constraint definitions. 049 */ 050public interface IConstraint { 051 /** 052 * The degree to which a constraint violation is significant. 053 * <p> 054 * These values are ordered from least significant to most significant. 055 */ 056 enum Level { 057 /** 058 * A violation of the constraint represents a point of interest. 059 */ 060 INFORMATIONAL, 061 /** 062 * A violation of the constraint represents a potential issue with the content. 063 */ 064 WARNING, 065 /** 066 * A violation of the constraint represents a fault in the content. This may 067 * include issues around compatibility, integrity, consistency, etc. 068 */ 069 ERROR, 070 /** 071 * A violation of the constraint represents a serious fault in the content that 072 * will prevent typical use of the content. 073 */ 074 CRITICAL; 075 } 076 077 /** 078 * The default level to use if no level is provided. 079 */ 080 @NonNull 081 Level DEFAULT_LEVEL = Level.ERROR; 082 /** 083 * The default target Metapath expression to use if no target is provided. 084 */ 085 @NonNull 086 MetapathExpression DEFAULT_TARGET = MetapathExpression.CONTEXT_NODE; 087 /** 088 * The default target Metapath expression to use if no target is provided. 089 */ 090 @NonNull 091 String DEFAULT_TARGET_METAPATH = "."; 092 093 /** 094 * Retrieve the unique identifier for the constraint. 095 * 096 * @return the identifier or {@code null} if no identifier is defined 097 */ 098 @Nullable 099 String getId(); 100 101 @Nullable 102 MarkupLine getDescription(); 103 104 @Nullable 105 String getFormalName(); 106 107 /** 108 * Get information about the source of the constraint. 109 * 110 * @return the source information 111 */ 112 @NonNull 113 ISource getSource(); 114 115 /** 116 * The significance of a violation of this constraint. 117 * 118 * @return the level 119 */ 120 @NonNull 121 Level getLevel(); 122 123 @NonNull 124 Map<QName, Set<String>> getProperties(); 125 126 /** 127 * Retrieve the Metapath expression to use to query the targets of the 128 * constraint. 129 * 130 * @return a Metapath expression 131 */ 132 @NonNull 133 MetapathExpression getTarget(); 134 135 /** 136 * Based on the provided {@code contextNodeItem}, find all nodes matching the 137 * target expression. 138 * 139 * @param contextNodeItem 140 * the node item to evaluate the target expression against 141 * @return the matching nodes as a sequence 142 * @see #getTarget() 143 */ 144 @NonNull 145 default ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets( 146 @NonNull IDefinitionNodeItem<?, ?> contextNodeItem) { 147 return getTarget().evaluate(contextNodeItem); 148 } 149 150 /** 151 * Based on the provided {@code contextNodeItem}, find all nodes matching the 152 * target expression. 153 * 154 * @param item 155 * the node item to evaluate the target expression against 156 * @param dynamicContext 157 * the Metapath evaluation context to use 158 * @return the matching nodes as a sequence 159 * @see #getTarget() 160 */ 161 @NonNull 162 default ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(@NonNull IDefinitionNodeItem<?, ?> item, 163 @NonNull DynamicContext dynamicContext) { 164 return item.hasValue() ? getTarget().evaluate(item, dynamicContext) : ISequence.empty(); 165 } 166 167 /** 168 * Retrieve the remarks associated with the constraint. 169 * 170 * @return the remarks or {@code null} if no remarks are defined 171 */ 172 MarkupMultiline getRemarks(); 173 174 <T, R> R accept(@NonNull IConstraintVisitor<T, R> visitor, T state); 175 176 interface ISource { 177 enum SourceType { 178 /** 179 * A constraint embedded in a model. 180 */ 181 MODEL, 182 /** 183 * A constraint defined externally from a model. 184 */ 185 EXTERNAL; 186 } 187 188 @NonNull 189 SourceType getSourceType(); 190 191 @Nullable 192 URI getSource(); 193 } 194 195 final class InternalModelSource implements ISource { 196 @NonNull 197 private static final ISource SINGLETON = new InternalModelSource(); 198 199 @NonNull 200 public static ISource instance() { 201 return SINGLETON; 202 } 203 204 private InternalModelSource() { 205 // reduce visibility 206 } 207 208 @Override 209 public SourceType getSourceType() { 210 return SourceType.MODEL; 211 } 212 213 @Override 214 public URI getSource() { 215 // always null 216 return null; 217 } 218 } 219 220 final class ExternalModelSource implements IConstraint.ISource { 221 @NonNull 222 private static final Map<URI, ExternalModelSource> sources = new HashMap<>(); // NOPMD - intentional 223 @NonNull 224 private final URI modelUri; 225 226 @NonNull 227 public static ISource instance(@NonNull URI location) { 228 ISource retval; 229 synchronized (sources) { 230 retval = sources.get(location); 231 if (retval == null) { 232 retval = new ExternalModelSource(location); 233 } 234 } 235 return retval; 236 } 237 238 private ExternalModelSource(@NonNull URI modelSource) { 239 this.modelUri = modelSource; 240 } 241 242 @Override 243 public SourceType getSourceType() { 244 return SourceType.MODEL; 245 } 246 247 @NonNull 248 @Override 249 public URI getSource() { 250 return modelUri; 251 } 252 } 253 254 final class ExternalSource implements IConstraint.ISource { 255 @NonNull 256 private static final Map<URI, ExternalSource> sources = new HashMap<>(); // NOPMD - intentional 257 258 @NonNull 259 private final URI modelUri; 260 261 @NonNull 262 public static ISource instance(@NonNull URI location) { 263 ISource retval; 264 synchronized (sources) { 265 retval = sources.get(location); 266 if (retval == null) { 267 retval = new ExternalModelSource(location); 268 } 269 } 270 return retval; 271 } 272 273 private ExternalSource(@NonNull URI modelSource) { 274 this.modelUri = modelSource; 275 } 276 277 @Override 278 public SourceType getSourceType() { 279 return SourceType.EXTERNAL; 280 } 281 282 @NonNull 283 @Override 284 public URI getSource() { 285 return modelUri; 286 } 287 } 288}