001package ezvcard.io.json; 002 003import java.io.BufferedReader; 004import java.io.File; 005import java.io.FileNotFoundException; 006import java.io.IOException; 007import java.io.InputStream; 008import java.io.Reader; 009import java.io.StringReader; 010 011import com.fasterxml.jackson.core.JsonParser; 012 013import ezvcard.VCard; 014import ezvcard.VCardDataType; 015import ezvcard.VCardVersion; 016import ezvcard.io.CannotParseException; 017import ezvcard.io.EmbeddedVCardException; 018import ezvcard.io.ParseWarning; 019import ezvcard.io.SkipMeException; 020import ezvcard.io.StreamReader; 021import ezvcard.io.json.JCardRawReader.JCardDataStreamListener; 022import ezvcard.io.scribe.RawPropertyScribe; 023import ezvcard.io.scribe.VCardPropertyScribe; 024import ezvcard.parameter.VCardParameters; 025import ezvcard.property.VCardProperty; 026import ezvcard.util.Utf8Reader; 027 028/* 029 Copyright (c) 2012-2018, Michael Angstadt 030 All rights reserved. 031 032 Redistribution and use in source and binary forms, with or without 033 modification, are permitted provided that the following conditions are met: 034 035 1. Redistributions of source code must retain the above copyright notice, this 036 list of conditions and the following disclaimer. 037 2. Redistributions in binary form must reproduce the above copyright notice, 038 this list of conditions and the following disclaimer in the documentation 039 and/or other materials provided with the distribution. 040 041 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 042 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 043 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 044 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 045 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 046 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 047 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 048 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 049 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 050 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 051 052 The views and conclusions contained in the software and documentation are those 053 of the authors and should not be interpreted as representing official policies, 054 either expressed or implied, of the FreeBSD Project. 055 */ 056 057/** 058 * <p> 059 * Parses {@link VCard} objects from a JSON data stream (jCard format). 060 * </p> 061 * <p> 062 * <b>Example:</b> 063 * </p> 064 * 065 * <pre class="brush:java"> 066 * File file = new File("vcards.json"); 067 * JCardReader reader = null; 068 * try { 069 * reader = new JCardReader(file); 070 * VCard vcard; 071 * while ((vcard = reader.readNext()) != null) { 072 * //... 073 * } 074 * } finally { 075 * if (reader != null) reader.close(); 076 * } 077 * </pre> 078 * @author Michael Angstadt 079 * @see <a href="http://tools.ietf.org/html/rfc7095">RFC 7095</a> 080 */ 081public class JCardReader extends StreamReader { 082 private final JCardRawReader reader; 083 084 /** 085 * @param json the JSON string to read from 086 */ 087 public JCardReader(String json) { 088 this(new StringReader(json)); 089 } 090 091 /** 092 * @param in the input stream to read from 093 */ 094 public JCardReader(InputStream in) { 095 this(new Utf8Reader(in)); 096 } 097 098 /** 099 * @param file the file to read from 100 * @throws FileNotFoundException if the file doesn't exist 101 */ 102 public JCardReader(File file) throws FileNotFoundException { 103 this(new BufferedReader(new Utf8Reader(file))); 104 } 105 106 /** 107 * @param reader the reader to read from 108 */ 109 public JCardReader(Reader reader) { 110 this.reader = new JCardRawReader(reader); 111 } 112 113 /** 114 * @param parser the parser to read from 115 */ 116 public JCardReader(JsonParser parser) { 117 this.reader = new JCardRawReader(parser, true); 118 } 119 120 @Override 121 protected VCard _readNext() throws IOException { 122 if (reader.eof()) { 123 return null; 124 } 125 126 context.setVersion(VCardVersion.V4_0); 127 128 JCardDataStreamListenerImpl listener = new JCardDataStreamListenerImpl(); 129 reader.readNext(listener); 130 VCard vcard = listener.vcard; 131 if (vcard != null && !listener.versionFound) { 132 //@formatter:off 133 warnings.add(new ParseWarning.Builder() 134 .lineNumber(reader.getLineNum()) 135 .message(29) 136 .build() 137 ); 138 //@formatter:on 139 } 140 return vcard; 141 } 142 143 public void close() throws IOException { 144 reader.close(); 145 } 146 147 private class JCardDataStreamListenerImpl implements JCardDataStreamListener { 148 private VCard vcard = null; 149 private boolean versionFound = false; 150 151 public void beginVCard() { 152 vcard = new VCard(); 153 vcard.setVersion(VCardVersion.V4_0); 154 } 155 156 public void readProperty(String group, String propertyName, VCardParameters parameters, VCardDataType dataType, JCardValue value) { 157 context.getWarnings().clear(); 158 context.setLineNumber(reader.getLineNum()); 159 context.setPropertyName(propertyName); 160 161 if ("version".equalsIgnoreCase(propertyName)) { 162 //don't unmarshal "version" because we don't treat it as a property 163 versionFound = true; 164 165 VCardVersion version = VCardVersion.valueOfByStr(value.asSingle()); 166 if (version != VCardVersion.V4_0) { 167 //@formatter:off 168 warnings.add(new ParseWarning.Builder(context) 169 .message(30) 170 .build() 171 ); 172 //@formatter:on 173 } 174 return; 175 } 176 177 VCardPropertyScribe<? extends VCardProperty> scribe = index.getPropertyScribe(propertyName); 178 if (scribe == null) { 179 scribe = new RawPropertyScribe(propertyName); 180 } 181 182 VCardProperty property; 183 try { 184 property = scribe.parseJson(value, dataType, parameters, context); 185 warnings.addAll(context.getWarnings()); 186 } catch (SkipMeException e) { 187 //@formatter:off 188 warnings.add(new ParseWarning.Builder(context) 189 .message(22, e.getMessage()) 190 .build() 191 ); 192 //@formatter:on 193 return; 194 } catch (CannotParseException e) { 195 scribe = new RawPropertyScribe(propertyName); 196 property = scribe.parseJson(value, dataType, parameters, context); 197 198 //@formatter:off 199 warnings.add(new ParseWarning.Builder(context) 200 .message(e) 201 .build() 202 ); 203 //@formatter:on 204 } catch (EmbeddedVCardException e) { 205 //@formatter:off 206 warnings.add(new ParseWarning.Builder(context) 207 .message(31) 208 .build() 209 ); 210 //@formatter:on 211 return; 212 } 213 214 property.setGroup(group); 215 vcard.addProperty(property); 216 } 217 } 218}