001/* 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2023 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.model.api; 021 022import ca.uhn.fhir.i18n.Msg; 023import ca.uhn.fhir.util.CoverageIgnore; 024import org.hl7.fhir.instance.model.api.IBase; 025 026import java.io.Serializable; 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.Iterator; 030import java.util.LinkedHashSet; 031import java.util.List; 032import java.util.Set; 033 034/** 035 * A collection of tags present on a single resource. TagList is backed by a {@link LinkedHashSet}, so the order of 036 * added tags will be consistent, but duplicates will not be preserved. 037 * 038 * <p> 039 * <b>Thread safety:</b> This class is not thread safe 040 * </p> 041 */ 042public class TagList implements Set<Tag>, Serializable, IBase { 043 044 public static final String ATTR_CATEGORY = "category"; 045 public static final String ELEMENT_NAME = "TagList"; 046 047 public static final String ELEMENT_NAME_LC = ELEMENT_NAME.toLowerCase(); 048 private static final long serialVersionUID = 1L; 049 private transient List<Tag> myOrderedTags; 050 private LinkedHashSet<Tag> myTagSet = new LinkedHashSet<Tag>(); 051 052 /** 053 * Constructor 054 */ 055 public TagList() { 056 super(); 057 } 058 059 /** 060 * Copy constructor 061 */ 062 public TagList(TagList theTags) { 063 if (theTags != null) { 064 for (Tag next : theTags) { 065 add(next); 066 } 067 } 068 } 069 070 @Override 071 public String toString() { 072 StringBuilder b = new StringBuilder(); 073 b.append("TagList[").append(size()).append(" tag(s)]"); 074 for (Tag next : this) { 075 b.append("\n * ").append(next.toString()); 076 } 077 return b.toString(); 078 } 079 080 @Override 081 public boolean add(Tag theE) { 082 myOrderedTags = null; 083 return myTagSet.add(theE); 084 } 085 086 @Override 087 public boolean addAll(Collection<? extends Tag> theC) { 088 myOrderedTags = null; 089 return myTagSet.addAll(theC); 090 } 091 092 /** 093 * @deprecated Tags wil become immutable in a future release of HAPI, so {@link #addTag(String, String, String)} 094 * should be used instead 095 */ 096 @Deprecated 097 public Tag addTag() { 098 myOrderedTags = null; 099 return addTag(null, null, null); 100 } 101 102 /** 103 * Add a new tag instance 104 * 105 * @param theScheme 106 * The tag scheme (the system) 107 * @param theTerm 108 * The tag term (the code) 109 * @return Returns the newly created tag instance. Note that the tag is added to the list by this method, so you 110 * generally do not need to interact directly with the added tag. 111 */ 112 public Tag addTag(String theScheme, String theTerm) { 113 Tag retVal = new Tag(theScheme, theTerm); 114 add(retVal); 115 myOrderedTags = null; 116 return retVal; 117 } 118 119 /** 120 * Add a new tag instance 121 * 122 * @param theScheme 123 * The tag scheme 124 * @param theTerm 125 * The tag term 126 * @param theLabel 127 * The tag label 128 * @return Returns the newly created tag instance. Note that the tag is added to the list by this method, so you 129 * generally do not need to interact directly with the added tag. 130 */ 131 public Tag addTag(String theScheme, String theTerm, String theLabel) { 132 Tag retVal = new Tag(theScheme, theTerm, theLabel); 133 add(retVal); 134 myOrderedTags = null; 135 return retVal; 136 } 137 138 @Override 139 public void clear() { 140 myOrderedTags = null; 141 myTagSet.clear(); 142 } 143 144 @Override 145 public boolean contains(Object theO) { 146 return myTagSet.contains(theO); 147 } 148 149 @Override 150 public boolean containsAll(Collection<?> theC) { 151 return myTagSet.containsAll(theC); 152 } 153 154 @Override 155 public boolean equals(Object obj) { 156 if (this == obj) 157 return true; 158 if (obj == null) 159 return false; 160 if (getClass() != obj.getClass()) 161 return false; 162 TagList other = (TagList) obj; 163 if (myTagSet == null) { 164 if (other.myTagSet != null) 165 return false; 166 } else if (!myTagSet.equals(other.myTagSet)) 167 return false; 168 return true; 169 } 170 171 /** 172 * Returns the tag at a given index - Note that the TagList is backed by a {@link LinkedHashSet}, so the order of 173 * added tags will be consistent, but duplicates will not be preserved. 174 */ 175 public Tag get(int theIndex) { 176 if (myOrderedTags == null) { 177 myOrderedTags = new ArrayList<Tag>(); 178 for (Tag next : myTagSet) { 179 myOrderedTags.add(next); 180 } 181 } 182 return myOrderedTags.get(theIndex); 183 } 184 185 public Tag getTag(String theScheme, String theTerm) { 186 for (Tag next : this) { 187 if (theScheme.equals(next.getScheme()) && theTerm.equals(next.getTerm())) { 188 return next; 189 } 190 } 191 return null; 192 } 193 194 public List<Tag> getTagsWithScheme(String theScheme) { 195 ArrayList<Tag> retVal = new ArrayList<Tag>(); 196 for (Tag next : this) { 197 if (theScheme.equals(next.getScheme())) { 198 retVal.add(next); 199 } 200 } 201 return retVal; 202 } 203 204 @Override 205 public int hashCode() { 206 return myTagSet.hashCode(); 207 } 208 209 @Override 210 public boolean isEmpty() { 211 for (Tag next : myTagSet) { 212 if (next.isEmpty() == false) { 213 return false; 214 } 215 } 216 return true; 217 } 218 219 @Override 220 public Iterator<Tag> iterator() { 221 return myTagSet.iterator(); 222 } 223 224 @Override 225 public boolean remove(Object theO) { 226 myOrderedTags = null; 227 return myTagSet.remove(theO); 228 } 229 230 @Override 231 public boolean removeAll(Collection<?> theC) { 232 myOrderedTags = null; 233 return myTagSet.removeAll(theC); 234 } 235 236 @Override 237 public boolean retainAll(Collection<?> theC) { 238 myOrderedTags = null; 239 return myTagSet.retainAll(theC); 240 } 241 242 @Override 243 public int size() { 244 return myTagSet.size(); 245 } 246 247 @Override 248 public Object[] toArray() { 249 return myTagSet.toArray(); 250 } 251 252 @Override 253 public <T> T[] toArray(T[] theA) { 254 return myTagSet.toArray(theA); 255 } 256 257 /** 258 * Returns false 259 */ 260 @Override 261 @CoverageIgnore 262 public boolean hasFormatComment() { 263 return false; 264 } 265 266 /** 267 * NOT SUPPORTED - Throws {@link UnsupportedOperationException} 268 */ 269 @Override 270 @CoverageIgnore 271 public List<String> getFormatCommentsPre() { 272 throw new UnsupportedOperationException(Msg.code(1895)); 273 } 274 275 /** 276 * NOT SUPPORTED - Throws {@link UnsupportedOperationException} 277 */ 278 @Override 279 @CoverageIgnore 280 public List<String> getFormatCommentsPost() { 281 throw new UnsupportedOperationException(Msg.code(1896)); 282 } 283 284 @Override 285 public Object getUserData(String theName) { 286 throw new UnsupportedOperationException(Msg.code(1897)); 287 } 288 289 @Override 290 public void setUserData(String theName, Object theValue) { 291 throw new UnsupportedOperationException(Msg.code(1898)); 292 } 293 294}