001 package ezvcard.io.scribe;
002
003 import java.util.HashMap;
004 import java.util.Map;
005
006 import javax.xml.namespace.QName;
007
008 import ezvcard.VCardVersion;
009 import ezvcard.property.RawProperty;
010 import ezvcard.property.VCardProperty;
011 import ezvcard.property.Xml;
012
013 /*
014 Copyright (c) 2013, 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 listing of property scribes (marshallers). This is useful for
041 * injecting the scribes of any extended properties you have defined into a
042 * reader or writer object. The same object instance can be reused and injected
043 * into multiple reader/writer classes.
044 * </p>
045 * <p>
046 * <b>Example:</b>
047 *
048 * <pre class="brush:java">
049 * //init the index
050 * ScribeIndex index = new ScribeIndex();
051 * index.register(new CustomPropertyScribe());
052 * index.register(new AnotherCustomPropertyScribe());
053 *
054 * //inject into a reader class
055 * VCardReader vcardReader = new VCardReader(...);
056 * vcardReader.setScribeIndex(index);
057 * List<VCard> vcards = new ArrayList<VCard>();
058 * VCard vcards;
059 * while ((vcards = vcardReader.readNext()) != null){
060 * vcards.add(vcard);
061 * }
062 *
063 * //inject the same instance in another reader/writer class
064 * JCardWriter jcardWriter = new JCardWriter(...);
065 * jcardWriter.setScribeIndex(index);
066 * for (VCard vcard : vcards){
067 * jcardWriter.write(vcard);
068 * }
069 * jcardWriter.close();
070 * </pre>
071 *
072 * </p>
073 * @author Michael Angstadt
074 */
075 public class ScribeIndex {
076 //define standard property marshallers
077 private static final Map<String, VCardPropertyScribe<? extends VCardProperty>> standardByName = new HashMap<String, VCardPropertyScribe<? extends VCardProperty>>();
078 private static final Map<Class<? extends VCardProperty>, VCardPropertyScribe<? extends VCardProperty>> standardByClass = new HashMap<Class<? extends VCardProperty>, VCardPropertyScribe<? extends VCardProperty>>();
079 private static final Map<QName, VCardPropertyScribe<? extends VCardProperty>> standardByQName = new HashMap<QName, VCardPropertyScribe<? extends VCardProperty>>();
080 static {
081 //2.1, RFC 2426, RFC 6350
082 registerStandard(new AddressScribe());
083 registerStandard(new AgentScribe());
084 registerStandard(new AnniversaryScribe());
085 registerStandard(new BirthdayScribe());
086 registerStandard(new CalendarRequestUriScribe());
087 registerStandard(new CalendarUriScribe());
088 registerStandard(new CategoriesScribe());
089 registerStandard(new ClassificationScribe());
090 registerStandard(new ClientPidMapScribe());
091 registerStandard(new EmailScribe());
092 registerStandard(new FreeBusyUrlScribe());
093 registerStandard(new FormattedNameScribe());
094 registerStandard(new GenderScribe());
095 registerStandard(new GeoScribe());
096 registerStandard(new ImppScribe());
097 registerStandard(new KeyScribe());
098 registerStandard(new KindScribe());
099 registerStandard(new LabelScribe());
100 registerStandard(new LanguageScribe());
101 registerStandard(new LogoScribe());
102 registerStandard(new MailerScribe());
103 registerStandard(new MemberScribe());
104 registerStandard(new NicknameScribe());
105 registerStandard(new NoteScribe());
106 registerStandard(new OrganizationScribe());
107 registerStandard(new PhotoScribe());
108 registerStandard(new ProductIdScribe());
109 registerStandard(new ProfileScribe());
110 registerStandard(new RelatedScribe());
111 registerStandard(new RevisionScribe());
112 registerStandard(new RoleScribe());
113 registerStandard(new SortStringScribe());
114 registerStandard(new SoundScribe());
115 registerStandard(new SourceDisplayTextScribe());
116 registerStandard(new SourceScribe());
117 registerStandard(new StructuredNameScribe());
118 registerStandard(new TelephoneScribe());
119 registerStandard(new TimezoneScribe());
120 registerStandard(new TitleScribe());
121 registerStandard(new UidScribe());
122 registerStandard(new UrlScribe());
123
124 //RFC 6351
125 registerStandard(new XmlScribe());
126
127 //RFC 6474
128 registerStandard(new BirthplaceScribe());
129 registerStandard(new DeathdateScribe());
130 registerStandard(new DeathplaceScribe());
131
132 //RFC 6715
133 registerStandard(new ExpertiseScribe());
134 registerStandard(new OrgDirectoryScribe());
135 registerStandard(new InterestScribe());
136 registerStandard(new HobbyScribe());
137 }
138
139 private final Map<String, VCardPropertyScribe<? extends VCardProperty>> extendedByName = new HashMap<String, VCardPropertyScribe<? extends VCardProperty>>(0);
140 private final Map<Class<? extends VCardProperty>, VCardPropertyScribe<? extends VCardProperty>> extendedByClass = new HashMap<Class<? extends VCardProperty>, VCardPropertyScribe<? extends VCardProperty>>(0);
141 private final Map<QName, VCardPropertyScribe<? extends VCardProperty>> extendedByQName = new HashMap<QName, VCardPropertyScribe<? extends VCardProperty>>(0);
142
143 /**
144 * Gets a property scribe by name.
145 * @param propertyName the property name (case-insensitive, e.g. "FN")
146 * @return the property scribe or null if not found
147 */
148 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(String propertyName) {
149 propertyName = propertyName.toUpperCase();
150
151 VCardPropertyScribe<? extends VCardProperty> marshaller = extendedByName.get(propertyName);
152 if (marshaller != null) {
153 return marshaller;
154 }
155
156 return standardByName.get(propertyName);
157 }
158
159 /**
160 * Gets a property scribe by class.
161 * @param clazz the property class
162 * @return the property scribe or null if not found
163 */
164 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(Class<? extends VCardProperty> clazz) {
165 VCardPropertyScribe<? extends VCardProperty> marshaller = extendedByClass.get(clazz);
166 if (marshaller != null) {
167 return marshaller;
168 }
169
170 return standardByClass.get(clazz);
171 }
172
173 /**
174 * Gets the appropriate property scribe for a given property instance.
175 * @param property the property instance
176 * @return the property scribe or null if not found
177 */
178 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(VCardProperty property) {
179 if (property instanceof RawProperty) {
180 RawProperty raw = (RawProperty) property;
181 return new RawPropertyScribe(raw.getPropertyName());
182 }
183
184 return getPropertyScribe(property.getClass());
185 }
186
187 /**
188 * Gets a property scribe by XML local name and namespace.
189 * @param qname the XML local name and namespace
190 * @return the property scribe or a {@link XmlScribe} if not found
191 */
192 public VCardPropertyScribe<? extends VCardProperty> getPropertyScribe(QName qname) {
193 VCardPropertyScribe<? extends VCardProperty> marshaller = extendedByQName.get(qname);
194 if (marshaller != null) {
195 return marshaller;
196 }
197
198 marshaller = standardByQName.get(qname);
199 if (marshaller != null) {
200 return marshaller;
201 }
202
203 if (VCardVersion.V4_0.getXmlNamespace().equals(qname.getNamespaceURI())) {
204 return new RawPropertyScribe(qname.getLocalPart().toUpperCase());
205 }
206
207 return getPropertyScribe(Xml.class);
208 }
209
210 /**
211 * Registers a property scribe.
212 * @param scribe the scribe to register
213 */
214 public void register(VCardPropertyScribe<? extends VCardProperty> scribe) {
215 extendedByName.put(scribe.getPropertyName().toUpperCase(), scribe);
216 extendedByClass.put(scribe.getPropertyClass(), scribe);
217 extendedByQName.put(scribe.getQName(), scribe);
218 }
219
220 /**
221 * Unregisters a property scribe.
222 * @param scribe the scribe to unregister
223 */
224 public void unregister(VCardPropertyScribe<? extends VCardProperty> scribe) {
225 extendedByName.remove(scribe.getPropertyName().toUpperCase());
226 extendedByClass.remove(scribe.getPropertyClass());
227 extendedByQName.remove(scribe.getQName());
228 }
229
230 private static void registerStandard(VCardPropertyScribe<? extends VCardProperty> scribe) {
231 standardByName.put(scribe.getPropertyName().toUpperCase(), scribe);
232 standardByClass.put(scribe.getPropertyClass(), scribe);
233 standardByQName.put(scribe.getQName(), scribe);
234 }
235 }