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.IDataTypeAdapter; 030import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; 031import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; 032import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; 033import gov.nist.secauto.metaschema.core.util.ObjectUtils; 034 035import java.util.Map; 036import java.util.Set; 037import java.util.regex.Pattern; 038 039import javax.xml.namespace.QName; 040 041import edu.umd.cs.findbugs.annotations.NonNull; 042import edu.umd.cs.findbugs.annotations.Nullable; 043 044public final class DefaultMatchesConstraint 045 extends AbstractConstraint 046 implements IMatchesConstraint { 047 private final Pattern pattern; 048 private final IDataTypeAdapter<?> dataType; 049 050 /** 051 * Create a new matches constraint, which enforces a value pattern and/or data 052 * type. 053 * 054 * @param id 055 * the optional identifier for the constraint 056 * @param formalName 057 * the constraint's formal name or {@code null} if not provided 058 * @param description 059 * the constraint's semantic description or {@code null} if not 060 * provided 061 * @param source 062 * information about the constraint source 063 * @param level 064 * the significance of a violation of this constraint 065 * @param target 066 * the Metapath expression identifying the nodes the constraint targets 067 * @param properties 068 * a collection of associated properties 069 * @param pattern 070 * the value pattern to match or {@code null} if there is no match 071 * pattern 072 * @param dataType 073 * the value data type to match or {@code null} if there is no match 074 * data type 075 * @param remarks 076 * optional remarks describing the intent of the constraint 077 */ 078 private DefaultMatchesConstraint( 079 @Nullable String id, 080 @Nullable String formalName, 081 @Nullable MarkupLine description, 082 @NonNull ISource source, 083 @NonNull Level level, 084 @NonNull MetapathExpression target, 085 @NonNull Map<QName, Set<String>> properties, 086 @Nullable Pattern pattern, 087 @Nullable IDataTypeAdapter<?> dataType, 088 @Nullable MarkupMultiline remarks) { 089 super(id, formalName, description, source, level, target, properties, remarks); 090 if (pattern == null && dataType == null) { 091 throw new IllegalArgumentException("a pattern or data type must be provided"); 092 } 093 this.pattern = pattern; 094 this.dataType = dataType; 095 } 096 097 @Override 098 public Pattern getPattern() { 099 return pattern; 100 } 101 102 @Override 103 public IDataTypeAdapter<?> getDataType() { 104 return dataType; 105 } 106 107 @Override 108 public <T, R> R accept(IConstraintVisitor<T, R> visitor, T state) { 109 return visitor.visitMatchesConstraint(this, state); 110 } 111 112 @NonNull 113 public static Builder builder() { 114 return new Builder(); 115 } 116 117 public static final class Builder 118 extends AbstractConstraintBuilder<Builder, DefaultMatchesConstraint> { 119 private Pattern pattern; 120 private IDataTypeAdapter<?> datatype; 121 122 private Builder() { 123 // disable construction 124 } 125 126 public Builder regex(@NonNull String pattern) { 127 return regex(ObjectUtils.notNull(Pattern.compile(pattern))); 128 } 129 130 public Builder regex(@NonNull Pattern pattern) { 131 this.pattern = pattern; 132 return this; 133 } 134 135 public Builder datatype(@NonNull IDataTypeAdapter<?> datatype) { 136 this.datatype = datatype; 137 return this; 138 } 139 140 @Override 141 protected Builder getThis() { 142 return this; 143 } 144 145 @Override 146 protected void validate() { 147 super.validate(); 148 149 if (getPattern() == null && getDatatype() == null) { 150 throw new IllegalStateException("A pattern or data type must be provided at minimum."); 151 } 152 } 153 154 protected Pattern getPattern() { 155 return pattern; 156 } 157 158 protected IDataTypeAdapter<?> getDatatype() { 159 return datatype; 160 } 161 162 @Override 163 protected DefaultMatchesConstraint newInstance() { 164 return new DefaultMatchesConstraint( 165 getId(), 166 getFormalName(), 167 getDescription(), 168 ObjectUtils.notNull(getSource()), 169 getLevel(), 170 getTarget(), 171 getProperties(), 172 getPattern(), 173 getDatatype(), 174 getRemarks()); 175 } 176 } 177}