001 package biweekly.property.marshaller; 002 003 import java.util.ArrayList; 004 import java.util.Date; 005 import java.util.List; 006 007 import biweekly.ICalDataType; 008 import biweekly.io.json.JCalValue; 009 import biweekly.io.xml.XCalElement; 010 import biweekly.parameter.ICalParameters; 011 import biweekly.property.FreeBusy; 012 import biweekly.util.Duration; 013 import biweekly.util.Period; 014 015 /* 016 Copyright (c) 2013, Michael Angstadt 017 All rights reserved. 018 019 Redistribution and use in source and binary forms, with or without 020 modification, are permitted provided that the following conditions are met: 021 022 1. Redistributions of source code must retain the above copyright notice, this 023 list of conditions and the following disclaimer. 024 2. Redistributions in binary form must reproduce the above copyright notice, 025 this list of conditions and the following disclaimer in the documentation 026 and/or other materials provided with the distribution. 027 028 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 029 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 030 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 031 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 032 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 033 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 034 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 035 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 036 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 037 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 038 */ 039 040 /** 041 * Marshals {@link FreeBusy} properties. 042 * @author Michael Angstadt 043 */ 044 public class FreeBusyMarshaller extends ICalPropertyMarshaller<FreeBusy> { 045 public FreeBusyMarshaller() { 046 super(FreeBusy.class, "FREEBUSY", ICalDataType.PERIOD); 047 } 048 049 @Override 050 protected String _writeText(FreeBusy property) { 051 List<Period> values = property.getValues(); 052 053 return list(values, new ListCallback<Period>() { 054 public String asString(Period period) { 055 StringBuilder sb = new StringBuilder(); 056 057 if (period.getStartDate() != null) { 058 String date = date(period.getStartDate()).write(); 059 sb.append(date); 060 } 061 062 sb.append('/'); 063 064 if (period.getEndDate() != null) { 065 String date = date(period.getEndDate()).write(); 066 sb.append(date); 067 } else if (period.getDuration() != null) { 068 sb.append(period.getDuration()); 069 } 070 071 return sb.toString(); 072 } 073 }); 074 } 075 076 @Override 077 protected FreeBusy _parseText(String value, ICalDataType dataType, ICalParameters parameters, List<String> warnings) { 078 return parse(list(value), parameters, warnings); 079 } 080 081 @Override 082 protected void _writeXml(FreeBusy property, XCalElement element) { 083 for (Period period : property.getValues()) { 084 XCalElement periodElement = element.append(ICalDataType.PERIOD); 085 086 Date start = period.getStartDate(); 087 if (start != null) { 088 periodElement.append("start", date(start).extended(true).write()); 089 } 090 091 Date end = period.getEndDate(); 092 if (end != null) { 093 periodElement.append("end", date(end).extended(true).write()); 094 } 095 096 Duration duration = period.getDuration(); 097 if (duration != null) { 098 periodElement.append("duration", duration.toString()); 099 } 100 } 101 } 102 103 @Override 104 protected FreeBusy _parseXml(XCalElement element, ICalParameters parameters, List<String> warnings) { 105 List<XCalElement> periodElements = element.children(ICalDataType.PERIOD); 106 if (periodElements.isEmpty()) { 107 throw missingXmlElements(ICalDataType.PERIOD); 108 } 109 110 FreeBusy prop = new FreeBusy(); 111 for (XCalElement periodElement : periodElements) { 112 String startStr = periodElement.first("start"); 113 if (startStr == null) { 114 warnings.add("No start date found in time period, skipping."); 115 continue; 116 } 117 118 Date start = null; 119 try { 120 start = date(startStr).tzid(parameters.getTimezoneId(), warnings).parse(); 121 } catch (IllegalArgumentException e) { 122 warnings.add("Could not parse start date, skipping time period: " + startStr); 123 continue; 124 } 125 126 String endStr = periodElement.first("end"); 127 if (endStr != null) { 128 try { 129 Date end = date(endStr).tzid(parameters.getTimezoneId(), warnings).parse(); 130 prop.addValue(start, end); 131 } catch (IllegalArgumentException e) { 132 warnings.add("Could not parse end date, skipping time period: " + endStr); 133 } 134 continue; 135 } 136 137 String durationStr = periodElement.first("duration"); 138 if (durationStr != null) { 139 try { 140 Duration duration = Duration.parse(durationStr); 141 prop.addValue(start, duration); 142 } catch (IllegalArgumentException e) { 143 warnings.add("Could not parse duration, skipping time period: " + durationStr); 144 } 145 continue; 146 } 147 148 warnings.add("Start date has no accompanying end date or duration, skipping."); 149 } 150 return prop; 151 } 152 153 @Override 154 protected JCalValue _writeJson(FreeBusy property) { 155 List<Period> values = property.getValues(); 156 if (values.isEmpty()) { 157 return JCalValue.single(""); 158 } 159 160 List<String> valuesStr = new ArrayList<String>(); 161 for (Period period : values) { 162 StringBuilder sb = new StringBuilder(); 163 if (period.getStartDate() != null) { 164 String date = date(period.getStartDate()).extended(true).write(); 165 sb.append(date); 166 } 167 168 sb.append('/'); 169 170 if (period.getEndDate() != null) { 171 String date = date(period.getEndDate()).extended(true).write(); 172 sb.append(date); 173 } else if (period.getDuration() != null) { 174 sb.append(period.getDuration()); 175 } 176 177 valuesStr.add(sb.toString()); 178 } 179 180 return JCalValue.multi(valuesStr); 181 } 182 183 @Override 184 protected FreeBusy _parseJson(JCalValue value, ICalDataType dataType, ICalParameters parameters, List<String> warnings) { 185 return parse(value.asMulti(), parameters, warnings); 186 } 187 188 private FreeBusy parse(List<String> periods, ICalParameters parameters, List<String> warnings) { 189 FreeBusy freebusy = new FreeBusy(); 190 191 for (String period : periods) { 192 String periodSplit[] = period.split("/"); 193 194 if (periodSplit.length < 2) { 195 warnings.add("No end date or duration found, skipping time period: " + period); 196 continue; 197 } 198 199 String startStr = periodSplit[0]; 200 Date start = null; 201 try { 202 start = date(startStr).tzid(parameters.getTimezoneId(), warnings).parse(); 203 } catch (IllegalArgumentException e) { 204 warnings.add("Could not parse start date, skipping time period: " + period); 205 continue; 206 } 207 208 String endStr = periodSplit[1]; 209 try { 210 Date end = date(endStr).tzid(parameters.getTimezoneId(), warnings).parse(); 211 freebusy.addValue(start, end); 212 } catch (IllegalArgumentException e) { 213 //must be a duration 214 try { 215 Duration duration = Duration.parse(endStr); 216 freebusy.addValue(start, duration); 217 } catch (IllegalArgumentException e2) { 218 warnings.add("Could not parse end date or duration value, skipping time period: " + period); 219 continue; 220 } 221 } 222 } 223 224 return freebusy; 225 } 226 }