Skip to content

Commit

Permalink
Merge pull request #296 from ical4j/feature/refactor-transforms
Browse files Browse the repository at this point in the history
Feature/refactor transforms
  • Loading branch information
benfortuna committed Dec 18, 2018
2 parents cd29ee1 + 17c6fde commit b61d13c
Show file tree
Hide file tree
Showing 16 changed files with 175 additions and 143 deletions.
71 changes: 0 additions & 71 deletions src/main/java/net/fortuna/ical4j/model/Calendar.java
Expand Up @@ -36,7 +36,6 @@
import net.fortuna.ical4j.model.property.Method;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.Version;
import net.fortuna.ical4j.transform.rfc5545.RuleManager;
import net.fortuna.ical4j.util.Strings;
import net.fortuna.ical4j.validate.AbstractCalendarValidatorFactory;
import net.fortuna.ical4j.validate.ValidationException;
Expand All @@ -46,10 +45,8 @@

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.util.List;

/**
* $Id$ [Apr 5, 2004]
Expand Down Expand Up @@ -351,72 +348,4 @@ public final int hashCode() {
return new HashCodeBuilder().append(getProperties()).append(
getComponents()).toHashCode();
}

@SuppressWarnings("unchecked")
public void conformToRfc5545() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{

conformPropertiesToRfc5545(properties);

for(Component component : components){
CountableProperties.removeExceededPropertiesForComponent(component);

//each component
conformComponentToRfc5545(component);

//each component property
conformPropertiesToRfc5545(component.getProperties());

for(java.lang.reflect.Method m : component.getClass().getDeclaredMethods()){
if(ComponentList.class.isAssignableFrom(m.getReturnType()) &&
m.getName().startsWith("get")){
List<Component> components = (List<Component>) m.invoke(component);
for(Component c : components){
//each inner component
conformComponentToRfc5545(c);

//each inner component properties
conformPropertiesToRfc5545(c.getProperties());
}
}
}
}
}

private static void conformPropertiesToRfc5545(List<Property> properties) {
for (Property property : properties) {
RuleManager.applyTo(property);
}
}

private static void conformComponentToRfc5545(Component component){
RuleManager.applyTo(component);
}

private enum CountableProperties{
STATUS(Property.STATUS, 1);
private int maxApparitionNumber;
private String name;

CountableProperties(String name, int maxApparitionNumber){
this.maxApparitionNumber = maxApparitionNumber;
this.name = name;
}

protected void limitApparitionsNumberIn(Component component){
PropertyList<? extends Property> propertyList = component.getProperties(name);

if(propertyList.size() <= maxApparitionNumber){
return;
}
int toRemove = propertyList.size() - maxApparitionNumber;
for(int i = 0; i < toRemove; i++){
component.getProperties().remove(propertyList.get(i)); }
}

private static void removeExceededPropertiesForComponent(Component component){
for(CountableProperties cp: values()){
cp.limitApparitionsNumberIn(component);
}
}
}
}
84 changes: 84 additions & 0 deletions src/main/java/net/fortuna/ical4j/transform/Rfc5545Transformer.java
@@ -0,0 +1,84 @@
package net.fortuna.ical4j.transform;

import net.fortuna.ical4j.model.*;
import net.fortuna.ical4j.transform.rfc5545.RuleManager;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class Rfc5545Transformer implements Transformer<Calendar> {

@Override
public Calendar transform(Calendar object) {

conformPropertiesToRfc5545(object.getProperties());

for(Component component : object.getComponents()){
CountableProperties.removeExceededPropertiesForComponent(component);

//each component
conformComponentToRfc5545(component);

//each component property
conformPropertiesToRfc5545(component.getProperties());

for(java.lang.reflect.Method m : component.getClass().getDeclaredMethods()){
if(ComponentList.class.isAssignableFrom(m.getReturnType()) &&
m.getName().startsWith("get")){

try {
List<Component> components = (List<Component>) m.invoke(component);
for(Component c : components){
//each inner component
conformComponentToRfc5545(c);

//each inner component properties
conformPropertiesToRfc5545(c.getProperties());
}
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}
return object;
}

private static void conformPropertiesToRfc5545(List<Property> properties) {
for (Property property : properties) {
RuleManager.applyTo(property);
}
}

private static void conformComponentToRfc5545(Component component){
RuleManager.applyTo(component);
}

private enum CountableProperties{
STATUS(Property.STATUS, 1);
private int maxApparitionNumber;
private String name;

CountableProperties(String name, int maxApparitionNumber){
this.maxApparitionNumber = maxApparitionNumber;
this.name = name;
}

protected void limitApparitionsNumberIn(Component component){
PropertyList<? extends Property> propertyList = component.getProperties(name);

if(propertyList.size() <= maxApparitionNumber){
return;
}
int toRemove = propertyList.size() - maxApparitionNumber;
for(int i = 0; i < toRemove; i++){
component.getProperties().remove(propertyList.get(i)); }
}

private static void removeExceededPropertiesForComponent(Component component){
for(CountableProperties cp: values()){
cp.limitApparitionsNumberIn(component);
}
}
}
}
72 changes: 0 additions & 72 deletions src/test/java/net/fortuna/ical4j/model/CalendarTest.java
Expand Up @@ -31,8 +31,6 @@
*/
package net.fortuna.ical4j.model;

import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Recur.Frequency;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.component.VTimeZone;
Expand All @@ -44,14 +42,10 @@
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.text.ParseException;

import static net.fortuna.ical4j.model.WeekDay.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
* Created on 16/03/2005
Expand Down Expand Up @@ -211,70 +205,4 @@ public void testValid2() throws ParseException, IOException, URISyntaxException
copyCalendar.validate();

}

@Test
public void shouldCorrectCalendarBody() throws IOException, ParserException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {

String[] calendarNames = { "yahoo1.txt", "yahoo2.txt", "outlook1.txt", "outlook2.txt", "apple.txt" };
for (String calendarName : calendarNames) {
Calendar calendar = buildCalendar(calendarName);
calendar.conformToRfc5545();
try {
calendar.validate();
} catch (ValidationException e) {
e.printStackTrace();
fail("Validation failed for " + calendarName);
}
}
}

@Test
public void shouldCorrectMsSpecificTimeZones() throws IOException, ParserException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
String actuals[] = { "timezones/outlook1.txt", "timezones/outlook2.txt" };
String expecteds[] = { "timezones/outlook1_expected.txt", "timezones/outlook2_expected.txt" };

for (int i = 0; i < actuals.length; i++) {
Calendar actual = buildCalendar(actuals[i]);
actual.conformToRfc5545();
Calendar expected = buildCalendar(expecteds[i]);
assertEquals("on from " + expecteds[i] + " and " + actuals[i] + " failed.", expected, actual);
}
}

@Test
public void shouldCorrectDTStampByAddingUTCTimezone() {
String calendarName = "dtstamp/invalid.txt";
try {
Calendar actual = buildCalendar(calendarName);
actual.conformToRfc5545();
} catch (IllegalAccessException | InvocationTargetException | IOException | ParserException e) {
e.printStackTrace();
fail("RFC transformation failed for " + calendarName);
}
}

@Test
public void shouldSetTimezoneToUtcForNoTZdescription() {
String actualCalendar = "outlook/TZ-no-description.txt";
try {
Calendar actual = buildCalendar(actualCalendar);
actual.conformToRfc5545();
Calendar expected = buildCalendar("outlook/TZ-set-to-utc.txt");
assertEquals(expected.toString(), actual.toString());
assertEquals(expected, actual);
} catch (Exception e) {
e.printStackTrace();
fail("RFC transformation failed for " + actualCalendar);
}
}

private Calendar buildCalendar(String file) throws IOException, ParserException {
InputStream is = getClass().getResourceAsStream(file);
CalendarBuilder cb = new CalendarBuilder();
Calendar calendar = cb.build(is);
is.close();
return calendar;
}
}
@@ -0,0 +1,91 @@
package net.fortuna.ical4j.transform;

import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.validate.ValidationException;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

public class Rfc5545TransformerTest {

private Rfc5545Transformer transformer;

@Before
public void setUp() {
transformer = new Rfc5545Transformer();
}

@Test
public void shouldCorrectCalendarBody() throws IOException, ParserException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {

String[] calendarNames = { "yahoo1.txt", "yahoo2.txt", "outlook1.txt", "outlook2.txt", "apple.txt" };
for (String calendarName : calendarNames) {
Calendar calendar = buildCalendar(calendarName);
calendar = transformer.transform(calendar);
try {
calendar.validate();
} catch (ValidationException e) {
e.printStackTrace();
fail("Validation failed for " + calendarName);
}
}
}

@Test
public void shouldCorrectMsSpecificTimeZones() throws IOException, ParserException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
String actuals[] = { "timezones/outlook1.txt", "timezones/outlook2.txt" };
String expecteds[] = { "timezones/outlook1_expected.txt", "timezones/outlook2_expected.txt" };

for (int i = 0; i < actuals.length; i++) {
Calendar actual = buildCalendar(actuals[i]);
actual = transformer.transform(actual);
Calendar expected = buildCalendar(expecteds[i]);
assertEquals("on from " + expecteds[i] + " and " + actuals[i] + " failed.", expected, actual);
}
}

@Test
public void shouldCorrectDTStampByAddingUTCTimezone() {
String calendarName = "dtstamp/invalid.txt";
try {
Calendar actual = buildCalendar(calendarName);
actual = transformer.transform(actual);
} catch (RuntimeException | IOException | ParserException e) {
e.printStackTrace();
fail("RFC transformation failed for " + calendarName);
}
}

@Test
public void shouldSetTimezoneToUtcForNoTZdescription() {
String actualCalendar = "outlook/TZ-no-description.txt";
try {
Calendar actual = buildCalendar(actualCalendar);
actual = transformer.transform(actual);
Calendar expected = buildCalendar("outlook/TZ-set-to-utc.txt");
assertEquals(expected.toString(), actual.toString());
assertEquals(expected, actual);
} catch (Exception e) {
e.printStackTrace();
fail("RFC transformation failed for " + actualCalendar);
}
}

private Calendar buildCalendar(String file) throws IOException, ParserException {
InputStream is = getClass().getResourceAsStream(file);
CalendarBuilder cb = new CalendarBuilder();
Calendar calendar = cb.build(is);
is.close();
return calendar;
}
}

0 comments on commit b61d13c

Please sign in to comment.