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