001package ezvcard.io.scribe; 002 003import java.util.HashMap; 004import java.util.Map; 005 006import javax.xml.namespace.QName; 007 008import ezvcard.VCardVersion; 009import ezvcard.property.RawProperty; 010import ezvcard.property.VCardProperty; 011import ezvcard.property.Xml; 012 013/* 014 Copyright (c) 2012-2023, Michael Angstadt 015 All rights reserved. 016 017 Redistribution and use in source and binary forms, with or without 018 modification, are permitted provided that the following conditions are met: 019 020 1. Redistributions of source code must retain the above copyright notice, this 021 list of conditions and the following disclaimer. 022 2. Redistributions in binary form must reproduce the above copyright notice, 023 this list of conditions and the following disclaimer in the documentation 024 and/or other materials provided with the distribution. 025 026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 027 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 028 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 029 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 030 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 031 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 032 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 033 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 034 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 035 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 036 */ 037 038/** 039 * <p> 040 * Manages a collection of property scribes (aka "marshallers" or "serializers") 041 * to use when reading or writing a vCard. The same instance of this object can 042 * be re-used across multiple vCard reader/writer objects. This is useful if you 043 * have custom scribe classes defined, as it allows you to only define them once 044 * instead of each time a vCard reader/writer object is created. 045 * </p> 046 * <p> 047 * <b>Example:</b> 048 * </p> 049 * 050 * <pre class="brush:java"> 051 * //init the index 052 * ScribeIndex index = new ScribeIndex(); 053 * index.register(new CustomPropertyScribe()); 054 * index.register(new AnotherCustomPropertyScribe()); 055 * 056 * //inject the ScribeIndex into a plain-text vCard reader class and read the vCard data stream 057 * try (VCardReader vcardReader = new VCardReader(...)) { 058 * vcardReader.setScribeIndex(index); 059 * List<VCard> vcards = new ArrayList<VCard>(); 060 * VCard vcard; 061 * while ((vcards = vcardReader.readNext()) != null) { 062 * vcards.add(vcard); 063 * } 064 * } 065 * 066 * //inject the same ScribeIndex instance into a jCard writer and write the vCards 067 * try (JCardWriter jcardWriter = new JCardWriter(...)) { 068 * jcardWriter.setScribeIndex(index); 069 * for (VCard vcard : vcards) { 070 * jcardWriter.write(vcard); 071 * } 072 * } 073 * </pre> 074 * @author Michael Angstadt 075 */ 076public class ScribeIndex { 077 //define standard property scribes 078 private static final Map<String, VCardPropertyScribe<? extends VCardProperty>> standardByName = new HashMap<>(); 079 private static final Map<Class<? extends VCardProperty>, VCardPropertyScribe<? extends VCardProperty>> standardByClass = new HashMap<>(); 080 private static final Map<QName, VCardPropertyScribe<? extends VCardProperty>> standardByQName = new HashMap<>(); 081 static { 082 //2.1, RFC 2426, RFC 6350 083 registerStandard(new AddressScribe()); 084 registerStandard(new AgentScribe()); 085 registerStandard(new AnniversaryScribe()); 086 registerStandard(new BirthdayScribe()); 087 registerStandard(new CalendarRequestUriScribe()); 088 registerStandard(new CalendarUriScribe()); 089 registerStandard(new CategoriesScribe()); 090 registerStandard(new ClassificationScribe()); 091 registerStandard(new ClientPidMapScribe()); 092 registerStandard(new EmailScribe()); 093 registerStandard(new FreeBusyUrlScribe()); 094 registerStandard(new FormattedNameScribe()); 095 registerStandard(new GenderScribe()); 096 registerStandard(new GeoScribe()); 097 registerStandard(new ImppScribe()); 098 registerStandard(new KeyScribe()); 099 registerStandard(new KindScribe()); 100 registerStandard(new LabelScribe()); 101 registerStandard(new LanguageScribe()); 102 registerStandard(new LogoScribe()); 103 registerStandard(new MailerScribe()); 104 registerStandard(new MemberScribe()); 105 registerStandard(new NicknameScribe()); 106 registerStandard(new NoteScribe()); 107 registerStandard(new OrganizationScribe()); 108 registerStandard(new PhotoScribe()); 109 registerStandard(new ProductIdScribe()); 110 registerStandard(new ProfileScribe()); 111 registerStandard(new RelatedScribe()); 112 registerStandard(new RevisionScribe()); 113 registerStandard(new RoleScribe()); 114 registerStandard(new SortStringScribe()); 115 registerStandard(new SoundScribe()); 116 registerStandard(new SourceDisplayTextScribe()); 117 registerStandard(new SourceScribe()); 118 registerStandard(new StructuredNameScribe()); 119 registerStandard(new TelephoneScribe()); 120 registerStandard(new TimezoneScribe()); 121 registerStandard(new TitleScribe()); 122 registerStandard(new UidScribe()); 123 registerStandard(new UrlScribe()); 124 125 //RFC 6351 126 registerStandard(new XmlScribe()); 127 128 //RFC 6474 129 registerStandard(new BirthplaceScribe()); 130 registerStandard(new DeathdateScribe()); 131 registerStandard(new DeathplaceScribe()); 132 133 //RFC 6715 134 registerStandard(new ExpertiseScribe()); 135 registerStandard(new OrgDirectoryScribe()); 136 registerStandard(new InterestScribe()); 137 registerStandard(new HobbyScribe()); 138 } 139 140 private final Map<String, VCardPropertyScribe<? extends VCardProperty>> extendedByName = new HashMap<>(0); 141 private final Map<Class<? extends VCardProperty>, VCardPropertyScribe<? extends VCardProperty>> extendedByClass = new HashMap<>(0); 142 private final Map<QName, VCardPropertyScribe<? extends VCardProperty>> extendedByQName = new HashMap<>(0); 143 144 /** 145 * Gets a property scribe by name. 146 * @param propertyName the property name (case-insensitive, e.g. "FN") 147 * @return the property scribe or null if not found 148 */ 149 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(String propertyName) { 150 propertyName = propertyName.toUpperCase(); 151 152 VCardPropertyScribe<? extends VCardProperty> scribe = extendedByName.get(propertyName); 153 if (scribe != null) { 154 return scribe; 155 } 156 157 return standardByName.get(propertyName); 158 } 159 160 /** 161 * Determines if a scribe exists for a given property instance. 162 * @param property the property 163 * @return true if a scribe exists, false if not 164 */ 165 public boolean hasPropertyScribe(VCardProperty property) { 166 if (property instanceof RawProperty) { 167 return true; 168 } 169 170 return getPropertyScribe(property.getClass()) != null; 171 } 172 173 /** 174 * Gets a property scribe by class. 175 * @param clazz the property class 176 * @return the property scribe or null if not found 177 */ 178 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(Class<? extends VCardProperty> clazz) { 179 VCardPropertyScribe<? extends VCardProperty> scribe = extendedByClass.get(clazz); 180 if (scribe != null) { 181 return scribe; 182 } 183 184 return standardByClass.get(clazz); 185 } 186 187 /** 188 * Gets the appropriate property scribe for a given property instance. 189 * @param property the property instance 190 * @return the property scribe or null if not found 191 */ 192 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(VCardProperty property) { 193 if (property instanceof RawProperty) { 194 RawProperty raw = (RawProperty) property; 195 return new RawPropertyScribe(raw.getPropertyName()); 196 } 197 198 return getPropertyScribe(property.getClass()); 199 } 200 201 /** 202 * Gets a property scribe by XML local name and namespace. 203 * @param qname the XML local name and namespace 204 * @return the property scribe or a {@link XmlScribe} if not found 205 */ 206 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(QName qname) { 207 VCardPropertyScribe<? extends VCardProperty> scribe = extendedByQName.get(qname); 208 if (scribe != null) { 209 return scribe; 210 } 211 212 scribe = standardByQName.get(qname); 213 if (scribe != null) { 214 return scribe; 215 } 216 217 if (VCardVersion.V4_0.getXmlNamespace().equals(qname.getNamespaceURI())) { 218 return new RawPropertyScribe(qname.getLocalPart().toUpperCase()); 219 } 220 221 return getPropertyScribe(Xml.class); 222 } 223 224 /** 225 * Registers a property scribe. 226 * @param scribe the scribe to register 227 */ 228 public void register(VCardPropertyScribe<? extends VCardProperty> scribe) { 229 extendedByName.put(scribe.getPropertyName().toUpperCase(), scribe); 230 extendedByClass.put(scribe.getPropertyClass(), scribe); 231 extendedByQName.put(scribe.getQName(), scribe); 232 } 233 234 /** 235 * Unregisters a property scribe. 236 * @param scribe the scribe to unregister 237 */ 238 public void unregister(VCardPropertyScribe<? extends VCardProperty> scribe) { 239 extendedByName.remove(scribe.getPropertyName().toUpperCase()); 240 extendedByClass.remove(scribe.getPropertyClass()); 241 extendedByQName.remove(scribe.getQName()); 242 } 243 244 private static void registerStandard(VCardPropertyScribe<? extends VCardProperty> scribe) { 245 standardByName.put(scribe.getPropertyName().toUpperCase(), scribe); 246 standardByClass.put(scribe.getPropertyClass(), scribe); 247 standardByQName.put(scribe.getQName(), scribe); 248 } 249}