001/* 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2024 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) return true; 157 if (obj == null) return false; 158 if (getClass() != obj.getClass()) return false; 159 TagList other = (TagList) obj; 160 if (myTagSet == null) { 161 if (other.myTagSet != null) return false; 162 } else if (!myTagSet.equals(other.myTagSet)) return false; 163 return true; 164 } 165 166 /** 167 * Returns the tag at a given index - Note that the TagList is backed by a {@link LinkedHashSet}, so the order of 168 * added tags will be consistent, but duplicates will not be preserved. 169 */ 170 public Tag get(int theIndex) { 171 if (myOrderedTags == null) { 172 myOrderedTags = new ArrayList<Tag>(); 173 for (Tag next : myTagSet) { 174 myOrderedTags.add(next); 175 } 176 } 177 return myOrderedTags.get(theIndex); 178 } 179 180 public Tag getTag(String theScheme, String theTerm) { 181 for (Tag next : this) { 182 if (theScheme.equals(next.getScheme()) && theTerm.equals(next.getTerm())) { 183 return next; 184 } 185 } 186 return null; 187 } 188 189 public List<Tag> getTagsWithScheme(String theScheme) { 190 ArrayList<Tag> retVal = new ArrayList<Tag>(); 191 for (Tag next : this) { 192 if (theScheme.equals(next.getScheme())) { 193 retVal.add(next); 194 } 195 } 196 return retVal; 197 } 198 199 @Override 200 public int hashCode() { 201 return myTagSet.hashCode(); 202 } 203 204 @Override 205 public boolean isEmpty() { 206 for (Tag next : myTagSet) { 207 if (next.isEmpty() == false) { 208 return false; 209 } 210 } 211 return true; 212 } 213 214 @Override 215 public Iterator<Tag> iterator() { 216 return myTagSet.iterator(); 217 } 218 219 @Override 220 public boolean remove(Object theO) { 221 myOrderedTags = null; 222 return myTagSet.remove(theO); 223 } 224 225 @Override 226 public boolean removeAll(Collection<?> theC) { 227 myOrderedTags = null; 228 return myTagSet.removeAll(theC); 229 } 230 231 @Override 232 public boolean retainAll(Collection<?> theC) { 233 myOrderedTags = null; 234 return myTagSet.retainAll(theC); 235 } 236 237 @Override 238 public int size() { 239 return myTagSet.size(); 240 } 241 242 @Override 243 public Object[] toArray() { 244 return myTagSet.toArray(); 245 } 246 247 @Override 248 public <T> T[] toArray(T[] theA) { 249 return myTagSet.toArray(theA); 250 } 251 252 /** 253 * Returns false 254 */ 255 @Override 256 @CoverageIgnore 257 public boolean hasFormatComment() { 258 return false; 259 } 260 261 /** 262 * NOT SUPPORTED - Throws {@link UnsupportedOperationException} 263 */ 264 @Override 265 @CoverageIgnore 266 public List<String> getFormatCommentsPre() { 267 throw new UnsupportedOperationException(Msg.code(1895)); 268 } 269 270 /** 271 * NOT SUPPORTED - Throws {@link UnsupportedOperationException} 272 */ 273 @Override 274 @CoverageIgnore 275 public List<String> getFormatCommentsPost() { 276 throw new UnsupportedOperationException(Msg.code(1896)); 277 } 278 279 @Override 280 public Object getUserData(String theName) { 281 throw new UnsupportedOperationException(Msg.code(1897)); 282 } 283 284 @Override 285 public void setUserData(String theName, Object theValue) { 286 throw new UnsupportedOperationException(Msg.code(1898)); 287 } 288}