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