From 3394da0cf3c1657a3a6fdbf1339d001abfa2a7e1 Mon Sep 17 00:00:00 2001 From: Mike Angstadt Date: Sun, 5 Nov 2023 10:53:40 -0500 Subject: [PATCH] Reduce cognitive complexity --- .../java/biweekly/io/json/JCalRawWriter.java | 72 +++--- .../io/scribe/property/FreeBusyScribe.java | 80 +++--- .../property/RecurrenceDatesScribe.java | 235 ++++++++---------- .../java/biweekly/io/xml/XCalDocument.java | 135 ++++++---- 4 files changed, 286 insertions(+), 236 deletions(-) diff --git a/src/main/java/biweekly/io/json/JCalRawWriter.java b/src/main/java/biweekly/io/json/JCalRawWriter.java index 34c3c2a8..90c91fde 100644 --- a/src/main/java/biweekly/io/json/JCalRawWriter.java +++ b/src/main/java/biweekly/io/json/JCalRawWriter.java @@ -230,7 +230,7 @@ public void writeProperty(String propertyName, ICalParameters parameters, ICalDa //write value for (JsonValue jsonValue : value.getValues()) { - writeValue(jsonValue); + writeJsonValue(jsonValue); } generator.writeEndArray(); @@ -238,7 +238,7 @@ public void writeProperty(String propertyName, ICalParameters parameters, ICalDa generator.setCurrentValue(null); } - private void writeValue(JsonValue jsonValue) throws IOException { + private void writeJsonValue(JsonValue jsonValue) throws IOException { if (jsonValue.isNull()) { generator.writeNull(); return; @@ -246,48 +246,60 @@ private void writeValue(JsonValue jsonValue) throws IOException { Object val = jsonValue.getValue(); if (val != null) { - if (val instanceof Byte) { - generator.writeNumber((Byte) val); - } else if (val instanceof Short) { - generator.writeNumber((Short) val); - } else if (val instanceof Integer) { - generator.writeNumber((Integer) val); - } else if (val instanceof Long) { - generator.writeNumber((Long) val); - } else if (val instanceof Float) { - generator.writeNumber((Float) val); - } else if (val instanceof Double) { - generator.writeNumber((Double) val); - } else if (val instanceof Boolean) { - generator.writeBoolean((Boolean) val); - } else { - generator.writeString(val.toString()); - } + writeValue(val); return; } List array = jsonValue.getArray(); if (array != null) { - generator.writeStartArray(); - for (JsonValue element : array) { - writeValue(element); - } - generator.writeEndArray(); + writeArray(array); return; } Map object = jsonValue.getObject(); if (object != null) { - generator.writeStartObject(); - for (Map.Entry entry : object.entrySet()) { - generator.writeFieldName(entry.getKey()); - writeValue(entry.getValue()); - } - generator.writeEndObject(); + writeObject(object); return; } } + private void writeValue(Object val) throws IOException { + if (val instanceof Byte) { + generator.writeNumber((Byte) val); + } else if (val instanceof Short) { + generator.writeNumber((Short) val); + } else if (val instanceof Integer) { + generator.writeNumber((Integer) val); + } else if (val instanceof Long) { + generator.writeNumber((Long) val); + } else if (val instanceof Float) { + generator.writeNumber((Float) val); + } else if (val instanceof Double) { + generator.writeNumber((Double) val); + } else if (val instanceof Boolean) { + generator.writeBoolean((Boolean) val); + } else { + generator.writeString(val.toString()); + } + } + + private void writeArray(List array) throws IOException { + generator.writeStartArray(); + for (JsonValue element : array) { + writeJsonValue(element); + } + generator.writeEndArray(); + } + + private void writeObject(Map object) throws IOException { + generator.writeStartObject(); + for (Map.Entry entry : object.entrySet()) { + generator.writeFieldName(entry.getKey()); + writeJsonValue(entry.getValue()); + } + generator.writeEndObject(); + } + /** * Flushes the JSON stream. * @throws IOException if there's a problem flushing the stream diff --git a/src/main/java/biweekly/io/scribe/property/FreeBusyScribe.java b/src/main/java/biweekly/io/scribe/property/FreeBusyScribe.java index 4977e4e8..2c323525 100644 --- a/src/main/java/biweekly/io/scribe/property/FreeBusyScribe.java +++ b/src/main/java/biweekly/io/scribe/property/FreeBusyScribe.java @@ -127,40 +127,20 @@ protected FreeBusy _parseXml(XCalElement element, ICalParameters parameters, Par FreeBusy property = new FreeBusy(); for (XCalElement periodElement : periodElements) { - String startStr = periodElement.first("start"); - if (startStr == null) { - throw new CannotParseException(9); - } + ICalDate start = parseStart(periodElement); - ICalDate start; - try { - start = date(startStr).parse(); - } catch (IllegalArgumentException e) { - throw new CannotParseException(10, startStr); - } - - String endStr = periodElement.first("end"); - if (endStr != null) { - try { - ICalDate end = date(endStr).parse(); - property.getValues().add(new Period(start, end)); - context.addDate(start, property, parameters); - context.addDate(end, property, parameters); - } catch (IllegalArgumentException e) { - throw new CannotParseException(11, endStr); - } + ICalDate end = parseEnd(periodElement); + if (end != null) { + property.getValues().add(new Period(start, end)); + context.addDate(start, property, parameters); + context.addDate(end, property, parameters); continue; } - String durationStr = periodElement.first("duration"); - if (durationStr != null) { - try { - Duration duration = Duration.parse(durationStr); - property.getValues().add(new Period(start, duration)); - context.addDate(start, property, parameters); - } catch (IllegalArgumentException e) { - throw new CannotParseException(12, durationStr); - } + Duration duration = parseDuration(periodElement); + if (duration != null) { + property.getValues().add(new Period(start, duration)); + context.addDate(start, property, parameters); continue; } @@ -170,6 +150,46 @@ protected FreeBusy _parseXml(XCalElement element, ICalParameters parameters, Par return property; } + private ICalDate parseStart(XCalElement periodElement) { + String startStr = periodElement.first("start"); + if (startStr == null) { + //start is required + throw new CannotParseException(9); + } + + try { + return date(startStr).parse(); + } catch (IllegalArgumentException e) { + throw new CannotParseException(10, startStr); + } + } + + private ICalDate parseEnd(XCalElement periodElement) { + String endStr = periodElement.first("end"); + if (endStr == null) { + return null; + } + + try { + return date(endStr).parse(); + } catch (IllegalArgumentException e) { + throw new CannotParseException(11, endStr); + } + } + + private Duration parseDuration(XCalElement periodElement) { + String durationStr = periodElement.first("duration"); + if (durationStr == null) { + return null; + } + + try { + return Duration.parse(durationStr); + } catch (IllegalArgumentException e) { + throw new CannotParseException(12, durationStr); + } + } + @Override protected JCalValue _writeJson(FreeBusy property, WriteContext context) { List values = property.getValues(); diff --git a/src/main/java/biweekly/io/scribe/property/RecurrenceDatesScribe.java b/src/main/java/biweekly/io/scribe/property/RecurrenceDatesScribe.java index 8d63a36a..dc34fe86 100644 --- a/src/main/java/biweekly/io/scribe/property/RecurrenceDatesScribe.java +++ b/src/main/java/biweekly/io/scribe/property/RecurrenceDatesScribe.java @@ -93,15 +93,9 @@ protected ICalDataType _dataType(RecurrenceDates property, ICalVersion version) protected String _writeText(final RecurrenceDates property, final WriteContext context) { List dates = property.getDates(); if (!dates.isEmpty()) { - boolean inObservance = isInObservance(context); List values = new ArrayList(dates.size()); for (ICalDate date : dates) { - String value; - if (inObservance) { - value = date(date).observance(true).extended(false).write(); - } else { - value = date(date, property, context).extended(false).write(); - } + String value = writeDateListDate(date, property, context, false); values.add(value); } return VObjectPropertyValues.writeList(values); @@ -112,26 +106,8 @@ protected String _writeText(final RecurrenceDates property, final WriteContext c if (!periods.isEmpty()) { List values = new ArrayList(periods.size()); for (Period period : periods) { - StringBuilder sb = new StringBuilder(); - - Date start = period.getStartDate(); - if (start != null) { - String date = date(start, property, context).extended(false).write(); - sb.append(date); - } - - sb.append('/'); - - Date end = period.getEndDate(); - Duration duration = period.getDuration(); - if (end != null) { - String date = date(end, property, context).extended(false).write(); - sb.append(date); - } else if (duration != null) { - sb.append(duration); - } - - values.add(sb.toString()); + String periodStr = writePeriod(period, property, context, false); + values.add(periodStr); } return VObjectPropertyValues.writeList(values); } @@ -149,15 +125,8 @@ protected void _writeXml(RecurrenceDates property, XCalElement element, WriteCon ICalDataType dataType = dataType(property, context.getVersion()); List dates = property.getDates(); if (!dates.isEmpty()) { - boolean inObservance = isInObservance(context); for (ICalDate date : dates) { - String dateStr; - if (inObservance) { - dateStr = date(date).observance(true).extended(true).write(); - } else { - dateStr = date(date, property, context).extended(true).write(); - } - + String dateStr = writeDateListDate(date, property, context, true); element.append(dataType, dateStr); } return; @@ -204,44 +173,13 @@ protected RecurrenceDates _parseXml(XCalElement element, ICalParameters paramete //parse periods for (XCalElement periodElement : periodElements) { - String startStr = periodElement.first("start"); - if (startStr == null) { - throw new CannotParseException(9); - } - - ICalDate start; - try { - start = date(startStr).parse(); - } catch (IllegalArgumentException e) { - throw new CannotParseException(10, startStr); - } + Period period = parsePeriod(periodElement); + property.getPeriods().add(period); - String endStr = periodElement.first("end"); - if (endStr != null) { - try { - ICalDate end = date(endStr).parse(); - property.getPeriods().add(new Period(start, end)); - context.addDate(start, property, parameters); - context.addDate(end, property, parameters); - } catch (IllegalArgumentException e) { - throw new CannotParseException(11, endStr); - } - continue; + context.addDate(period.getStartDate(), property, parameters); + if (period.getEndDate() != null) { + context.addDate(period.getEndDate(), property, parameters); } - - String durationStr = periodElement.first("duration"); - if (durationStr != null) { - try { - Duration duration = Duration.parse(durationStr); - property.getPeriods().add(new Period(start, duration)); - context.addDate(start, property, parameters); - } catch (IllegalArgumentException e) { - throw new CannotParseException(12, durationStr); - } - continue; - } - - throw new CannotParseException(13); } //parse date-times @@ -274,38 +212,14 @@ protected JCalValue _writeJson(RecurrenceDates property, WriteContext context) { List dates = property.getDates(); List periods = property.getPeriods(); if (!dates.isEmpty()) { - boolean inObservance = isInObservance(context); for (ICalDate date : dates) { - String dateStr; - if (inObservance) { - dateStr = date(date).observance(true).extended(true).write(); - } else { - dateStr = date(date, property, context).extended(true).write(); - } - + String dateStr = writeDateListDate(date, property, context, true); values.add(dateStr); } } else if (!periods.isEmpty()) { for (Period period : property.getPeriods()) { - StringBuilder sb = new StringBuilder(); - Date start = period.getStartDate(); - if (start != null) { - String dateStr = date(start, property, context).extended(true).write(); - sb.append(dateStr); - } - - sb.append('/'); - - Date end = period.getEndDate(); - Duration duration = period.getDuration(); - if (end != null) { - String dateStr = date(end, property, context).extended(true).write(); - sb.append(dateStr); - } else if (duration != null) { - sb.append(duration); - } - - values.add(sb.toString()); + String periodStr = writePeriod(period, property, context, true); + values.add(periodStr); } } @@ -326,35 +240,12 @@ private RecurrenceDates parse(List valueStrs, ICalDataType dataType, ICa if (dataType == PERIOD) { //parse as periods for (String timePeriodStr : valueStrs) { - int slash = timePeriodStr.indexOf('/'); - if (slash < 0) { - throw new CannotParseException(13); - } + Period period = parsePeriod(timePeriodStr); + property.getPeriods().add(period); - String startStr = timePeriodStr.substring(0, slash); - ICalDate start; - try { - start = date(startStr).parse(); - } catch (IllegalArgumentException e) { - throw new CannotParseException(10, startStr); - } - - String endStr = timePeriodStr.substring(slash + 1); - ICalDate end; - try { - end = date(endStr).parse(); - property.getPeriods().add(new Period(start, end)); - context.addDate(start, property, parameters); - context.addDate(end, property, parameters); - } catch (IllegalArgumentException e) { - //must be a duration - try { - Duration duration = Duration.parse(endStr); - property.getPeriods().add(new Period(start, duration)); - context.addDate(start, property, parameters); - } catch (IllegalArgumentException e2) { - throw new CannotParseException(14, endStr); - } + context.addDate(period.getStartDate(), property, parameters); + if (period.getEndDate() != null) { + context.addDate(period.getEndDate(), property, parameters); } } return property; @@ -374,4 +265,96 @@ private RecurrenceDates parse(List valueStrs, ICalDataType dataType, ICa } return property; } + + private Period parsePeriod(String str) { + int slash = str.indexOf('/'); + if (slash < 0) { + throw new CannotParseException(13); + } + + String beforeSlash = str.substring(0, slash); + ICalDate start; + try { + start = date(beforeSlash).parse(); + } catch (IllegalArgumentException e) { + throw new CannotParseException(10, beforeSlash); + } + + String afterSlash = str.substring(slash + 1); + try { + ICalDate end = date(afterSlash).parse(); + return new Period(start, end); + } catch (IllegalArgumentException e) { + //must be a duration + } + + try { + Duration duration = Duration.parse(afterSlash); + return new Period(start, duration); + } catch (IllegalArgumentException e) { + throw new CannotParseException(14, afterSlash); + } + } + + private Period parsePeriod(XCalElement element) { + String startStr = element.first("start"); + if (startStr == null) { + throw new CannotParseException(9); + } + + ICalDate start; + try { + start = date(startStr).parse(); + } catch (IllegalArgumentException e) { + throw new CannotParseException(10, startStr); + } + + String endStr = element.first("end"); + if (endStr != null) { + try { + ICalDate end = date(endStr).parse(); + return new Period(start, end); + } catch (IllegalArgumentException e) { + throw new CannotParseException(11, endStr); + } + } + + String durationStr = element.first("duration"); + if (durationStr != null) { + try { + Duration duration = Duration.parse(durationStr); + return new Period(start, duration); + } catch (IllegalArgumentException e) { + throw new CannotParseException(12, durationStr); + } + } + + throw new CannotParseException(13); + } + + private String writeDateListDate(ICalDate date, RecurrenceDates property, WriteContext context, boolean extended) { + //@formatter:off + return isInObservance(context) ? + date(date).observance(true).extended(extended).write() : + date(date, property, context).extended(extended).write(); + //@formatter:on + } + + private String writePeriod(Period period, RecurrenceDates property, WriteContext context, boolean extended) { + Date start = period.getStartDate(); + String beforeSlash = (start == null) ? "" : date(start, property, context).extended(extended).write(); + + String afterSlash; + Date end = period.getEndDate(); + Duration duration = period.getDuration(); + if (end != null) { + afterSlash = date(end, property, context).extended(extended).write(); + } else if (duration != null) { + afterSlash = duration.toString(); + } else { + afterSlash = ""; + } + + return beforeSlash + "/" + afterSlash; + } } diff --git a/src/main/java/biweekly/io/xml/XCalDocument.java b/src/main/java/biweekly/io/xml/XCalDocument.java index cf11c622..0e9bbb5d 100644 --- a/src/main/java/biweekly/io/xml/XCalDocument.java +++ b/src/main/java/biweekly/io/xml/XCalDocument.java @@ -609,34 +609,42 @@ private ICalProperty parseProperty(Element propertyElement) { private ICalParameters parseParameters(Element propertyElement) { ICalParameters parameters = new ICalParameters(); - for (Element parametersElement : getChildElements(propertyElement, PARAMETERS)) { //there should be only one element, but parse them all incase there are more - List paramElements = XmlUtils.toElementList(parametersElement.getChildNodes()); - for (Element paramElement : paramElements) { - if (!XCAL_NS.equals(paramElement.getNamespaceURI())) { - continue; - } + /* + * There should only be a single element, but parse + * them all in case there are more. + */ + for (Element parametersWrapperElement : getChildElements(propertyElement, PARAMETERS)) { + List parameterElements = XmlUtils.toElementList(parametersWrapperElement.getChildNodes()); + for (Element parameterElement : parameterElements) { + parseParameter(parameterElement, parameters); + } + } - String name = paramElement.getLocalName().toUpperCase(); - List valueElements = XmlUtils.toElementList(paramElement.getChildNodes()); - if (valueElements.isEmpty()) { - //this should never be true if the xCal follows the specs - String value = paramElement.getTextContent(); - parameters.put(name, value); - continue; - } + return parameters; + } - for (Element valueElement : valueElements) { - if (!XCAL_NS.equals(valueElement.getNamespaceURI())) { - continue; - } + private void parseParameter(Element parameterElement, ICalParameters parameters) { + if (!XCAL_NS.equals(parameterElement.getNamespaceURI())) { + return; + } - String value = valueElement.getTextContent(); - parameters.put(name, value); - } - } + String name = parameterElement.getLocalName().toUpperCase(); + List valueElements = XmlUtils.toElementList(parameterElement.getChildNodes()); + if (valueElements.isEmpty()) { + //this should never be true if the xCal is properly formed + String value = parameterElement.getTextContent(); + parameters.put(name, value); + return; } - return parameters; + for (Element valueElement : valueElements) { + if (!XCAL_NS.equals(valueElement.getNamespaceURI())) { + continue; + } + + String value = valueElement.getTextContent(); + parameters.put(name, value); + } } private List getVCalendarElements() { @@ -690,16 +698,55 @@ private Element buildComponentElement(ICalComponent component) { ICalComponentScribe componentScribe = index.getComponentScribe(component); Element componentElement = buildElement(componentScribe.getComponentName().toLowerCase()); - Element propertiesWrapperElement = buildElement(PROPERTIES); - List propertyObjs = componentScribe.getProperties(component); - if (component instanceof ICalendar && component.getProperty(Version.class) == null) { - //add a version property - propertyObjs.add(0, new Version(targetVersion)); + List properties = componentScribe.getProperties(component); + addVersionPropertyIfMissing(properties, component); + + Element propertiesWrapperElement = buildPropertiesElement(properties, component); + if (propertiesWrapperElement.hasChildNodes()) { + componentElement.appendChild(propertiesWrapperElement); + } + + List subComponents = componentScribe.getComponents(component); + addVTimezoneComponents(component, subComponents); + + Element componentsWrapperElement = buildComponentsElement(subComponents); + if (componentsWrapperElement.hasChildNodes()) { + componentElement.appendChild(componentsWrapperElement); + } + + return componentElement; + } + + private void addVersionPropertyIfMissing(List propertyObjs, ICalComponent parent) { + if (!(parent instanceof ICalendar)) { + return; + } + + if (parent.getProperty(Version.class) != null) { + return; + } + + propertyObjs.add(0, new Version(targetVersion)); + } + + private void addVTimezoneComponents(ICalComponent parent, List subComponents) { + if (!(parent instanceof ICalendar)) { + return; } - for (Object propertyObj : propertyObjs) { - context.setParent(component); //set parent here incase a scribe resets the parent - ICalProperty property = (ICalProperty) propertyObj; + Collection tzs = getTimezoneComponents(); + for (VTimezone tz : tzs) { + if (!subComponents.contains(tz)) { + subComponents.add(0, tz); + } + } + } + + private Element buildPropertiesElement(List properties, ICalComponent parent) { + Element propertiesWrapperElement = buildElement(PROPERTIES); + + for (ICalProperty property : properties) { + context.setParent(parent); //set parent here incase a scribe resets the parent //create property element Element propertyElement = buildPropertyElement(property); @@ -707,33 +754,21 @@ private Element buildComponentElement(ICalComponent component) { propertiesWrapperElement.appendChild(propertyElement); } } - if (propertiesWrapperElement.hasChildNodes()) { - componentElement.appendChild(propertiesWrapperElement); - } - List subComponents = componentScribe.getComponents(component); - if (component instanceof ICalendar) { - //add the VTIMEZONE components that were auto-generated by TimezoneOptions - Collection tzs = getTimezoneComponents(); - for (VTimezone tz : tzs) { - if (!subComponents.contains(tz)) { - subComponents.add(0, tz); - } - } - } + return propertiesWrapperElement; + } + + private Element buildComponentsElement(List subComponents) { Element componentsWrapperElement = buildElement(COMPONENTS); - for (Object subComponentObj : subComponents) { - ICalComponent subComponent = (ICalComponent) subComponentObj; + + for (ICalComponent subComponent : subComponents) { Element subComponentElement = buildComponentElement(subComponent); if (subComponentElement != null) { componentsWrapperElement.appendChild(subComponentElement); } } - if (componentsWrapperElement.hasChildNodes()) { - componentElement.appendChild(componentsWrapperElement); - } - return componentElement; + return componentsWrapperElement; } @SuppressWarnings({ "rawtypes", "unchecked" })