Skip to content

Commit b61ee2e

Browse files
authored
Merge pull request #29 from ical4j/develop
Added vcard factory to content builder
2 parents dd3a6c9 + 8edde25 commit b61ee2e

File tree

6 files changed

+176
-9
lines changed

6 files changed

+176
-9
lines changed

src/main/groovy/net/fortuna/ical4j/vcard/ContentBuilder.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class ContentBuilder extends FactoryBuilderSupport {
6868
}
6969

7070
def registerVCard() {
71+
registerFactory('vcard', new VCardFactory())
7172
registerFactory('entity', new EntityFactory())
7273
}
7374

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Copyright (c) 2012, Ben Fortuna
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
*
9+
* o Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
*
12+
* o Redistributions in binary form must reproduce the above copyright
13+
* notice, this list of conditions and the following disclaimer in the
14+
* documentation and/or other materials provided with the distribution.
15+
*
16+
* o Neither the name of Ben Fortuna nor the names of any other contributors
17+
* may be used to endorse or promote products derived from this software
18+
* without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
package net.fortuna.ical4j.vcard
33+
/**
34+
* $Id$
35+
*
36+
* Created on: 03/08/2009
37+
*
38+
* @author fortuna
39+
*
40+
*/
41+
class VCardFactory extends groovy.util.AbstractFactory {
42+
43+
Object newInstance(FactoryBuilderSupport builder, name, value, Map attributes) throws InstantiationException,
44+
IllegalAccessException {
45+
VCard card
46+
if (FactoryBuilderSupport.checkValueIsType(value, name, VCard)) {
47+
card = value
48+
} else {
49+
card = []
50+
}
51+
return card
52+
}
53+
54+
void setChild(FactoryBuilderSupport build, Object parent, Object child) {
55+
parent.add(child)
56+
}
57+
}
58+

src/main/java/net/fortuna/ical4j/vcard/EntityContainer.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.fortuna.ical4j.vcard;
22

33
import java.util.List;
4+
import java.util.function.BiFunction;
45

56
/**
67
* Provides mutator methods for {@link Entity} collections.
@@ -36,4 +37,21 @@ default EntityContainer remove(Entity entity) {
3637
default List<Entity> getEntities() {
3738
return getEntityList().getAll();
3839
}
40+
41+
/**
42+
* A functional method used to apply an entity to a container in an undefined way.
43+
* <p>
44+
* For example, a null check can be introduced as follows:
45+
* <p>
46+
* container.with((container, entity) -> if (entity != null) container.add(entity); return container;)
47+
*
48+
* @param f
49+
* @param entity
50+
* @return
51+
*/
52+
default <T extends EntityContainer> T with(BiFunction<T, List<Entity>, T> f, List<Entity> entity) {
53+
//noinspection unchecked
54+
return f.apply((T) this, entity);
55+
}
56+
3957
}

src/main/java/net/fortuna/ical4j/vcard/EntityList.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.ArrayList;
66
import java.util.Collection;
77
import java.util.List;
8+
import java.util.Objects;
89
import java.util.stream.Collectors;
910

1011
/**
@@ -48,4 +49,17 @@ public List<Entity> getAll() {
4849
public String toString() {
4950
return entities.stream().map(Entity::toString).collect(Collectors.joining(Strings.LINE_SEPARATOR));
5051
}
52+
53+
@Override
54+
public boolean equals(Object o) {
55+
if (this == o) return true;
56+
if (o == null || getClass() != o.getClass()) return false;
57+
EntityList that = (EntityList) o;
58+
return Objects.equals(entities, that.entities);
59+
}
60+
61+
@Override
62+
public int hashCode() {
63+
return Objects.hashCode(entities);
64+
}
5165
}

src/main/java/net/fortuna/ical4j/vcard/VCard.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,18 @@
3131
*/
3232
package net.fortuna.ical4j.vcard;
3333

34+
import net.fortuna.ical4j.model.ConstraintViolationException;
35+
import net.fortuna.ical4j.model.Property;
3436
import net.fortuna.ical4j.model.Prototype;
3537
import net.fortuna.ical4j.validate.ValidationException;
3638
import net.fortuna.ical4j.validate.ValidationResult;
39+
import net.fortuna.ical4j.vcard.property.Uid;
3740
import org.apache.commons.lang3.builder.EqualsBuilder;
3841
import org.apache.commons.lang3.builder.HashCodeBuilder;
3942

4043
import java.io.Serializable;
44+
import java.util.*;
45+
import java.util.function.BiFunction;
4146
import java.util.stream.Collectors;
4247

4348
/**
@@ -53,6 +58,15 @@ public class VCard implements Serializable, Prototype<VCard>, EntityContainer {
5358

5459
private EntityList entities;
5560

61+
public static final BiFunction<VCard, List<Entity>, VCard> MERGE_ENTITIES = (c, list) -> {
62+
list.forEach(entity -> {
63+
if (!c.getEntities().contains(entity)) {
64+
c.add(entity.copy());
65+
}
66+
});
67+
return c;
68+
};
69+
5670
/**
5771
* Default constructor.
5872
*/
@@ -98,6 +112,66 @@ public VCard copy() {
98112
.map(Entity::copy).collect(Collectors.toList())));
99113
}
100114

115+
/**
116+
* Merge all entities from the specified vCard with this instance.
117+
*
118+
* @param c2 the second card to merge
119+
* @return a vCard object containing all entities from both of the cards
120+
*/
121+
public VCard merge(VCard c2) {
122+
VCard copy = this.copy();
123+
copy.with(MERGE_ENTITIES, c2.getEntities());
124+
return copy;
125+
}
126+
127+
/**
128+
* Splits a vCard object into distinct vCard objects for unique identifiers (UID).
129+
*
130+
* @return an array of vCard objects
131+
*/
132+
public VCard[] split() {
133+
if (getEntities().size() <= 1) {
134+
return new VCard[]{this};
135+
}
136+
137+
final Map<Uid, VCard> cards = new HashMap<Uid, VCard>();
138+
for (final var c : getEntities()) {
139+
final Optional<Uid> uid = c.getUid();
140+
if (uid.isPresent()) {
141+
var uidCal = cards.get(uid.get());
142+
if (uidCal == null) {
143+
cards.put(uid.get(), new VCard(new EntityList(Collections.singletonList(c))));
144+
} else {
145+
uidCal.add(c);
146+
}
147+
}
148+
}
149+
return cards.values().toArray(VCard[]::new);
150+
}
151+
152+
/**
153+
* Returns a unique identifier as specified by components in the vCard object.
154+
*
155+
* @return the UID property
156+
* @throws ConstraintViolationException if zero or more than one unique identifier(s) is
157+
* found in the specified vCard
158+
*/
159+
public Uid getUid() throws ConstraintViolationException {
160+
Uid uid = null;
161+
for (final var c : entities.getAll()) {
162+
for (final var foundUid : c.getProperties(Property.UID)) {
163+
if (uid != null && !uid.equals(foundUid)) {
164+
throw new ConstraintViolationException("More than one UID found in card");
165+
}
166+
uid = (Uid) foundUid;
167+
}
168+
}
169+
if (uid == null) {
170+
throw new ConstraintViolationException("Card must specify a single unique identifier (UID)");
171+
}
172+
return uid;
173+
}
174+
101175
/**
102176
* @return a vCard-compliant string representation of the vCard object
103177
*/

src/test/groovy/net/fortuna/ical4j/vcard/ContentBuilderTest.groovy

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,21 @@ class ContentBuilderTest extends GroovyTestCase {
4242

4343
void testBuildCard() {
4444
def builder = new ContentBuilder()
45-
def entity = builder.entity {
46-
version '4.0'
47-
fn 'test'
48-
n('example') {
49-
value 'text'
45+
def card = builder.vcard {
46+
entity {
47+
version '4.0'
48+
fn 'test'
49+
n('example') {
50+
value 'text'
51+
}
52+
photo(value: 'http://example.com', parameters: [value('uri')])
5053
}
51-
photo(value: 'http://example.com', parameters: [value('uri')])
5254
}
53-
entity.validate()
55+
card.validate()
5456

55-
assert entity.getPropertyList().all.size() == 4
57+
assert card.entities[0].getPropertyList().all.size() == 4
5658

57-
println entity
59+
println card
5860
}
5961

6062
void testBuildEmail() {

0 commit comments

Comments
 (0)