Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
it.cnr.iit.jscontact.tools.vcard.converters.ezvcard2jscontact.EZVCard2JSContact Maven / Gradle / Ivy
/*
* Copyright (C) 2020 Consiglio Nazionale delle Ricerche
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package it.cnr.iit.jscontact.tools.vcard.converters.ezvcard2jscontact;
import com.fasterxml.jackson.databind.JsonNode;
import ezvcard.VCard;
import ezvcard.VCardDataType;
import ezvcard.VCardVersion;
import ezvcard.ValidationWarnings;
import ezvcard.parameter.RelatedType;
import ezvcard.property.*;
import ezvcard.property.Organization;
import ezvcard.property.Title;
import ezvcard.util.DataUri;
import ezvcard.util.GeoUri;
import ezvcard.util.UtcOffset;
import it.cnr.iit.jscontact.tools.dto.*;
import it.cnr.iit.jscontact.tools.dto.Address;
import it.cnr.iit.jscontact.tools.dto.Calendar;
import it.cnr.iit.jscontact.tools.dto.Nickname;
import it.cnr.iit.jscontact.tools.dto.Note;
import it.cnr.iit.jscontact.tools.dto.TimeZone;
import it.cnr.iit.jscontact.tools.dto.comparators.JSCardAddressesComparator;
import it.cnr.iit.jscontact.tools.dto.comparators.VCardPropertiesAltidComparator;
import it.cnr.iit.jscontact.tools.dto.comparators.VCardPropertiesPrefComparator;
import it.cnr.iit.jscontact.tools.dto.interfaces.VCardTypeDerivedEnum;
import it.cnr.iit.jscontact.tools.dto.utils.*;
import it.cnr.iit.jscontact.tools.exceptions.CardException;
import it.cnr.iit.jscontact.tools.exceptions.InternalErrorException;
import it.cnr.iit.jscontact.tools.vcard.converters.AbstractConverter;
import it.cnr.iit.jscontact.tools.vcard.converters.config.VCard2JSContactConfig;
import it.cnr.iit.jscontact.tools.vcard.converters.config.JSContactIdsProfile;
import it.cnr.iit.jscontact.tools.vcard.extensions.property.ExtendedAddress;
import it.cnr.iit.jscontact.tools.vcard.extensions.property.ExtendedStructuredName;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility class for converting a vCard 4.0 [RFC6350] instance represented as an Ezvcard VCard object [ez-vcard] into a JSContact object [RFC9553].
*
* @see RFC6350
* @see RFC9553
* @see ez-vcard
* @author Mario Loffredo
*/
@NoArgsConstructor
@ToString
public abstract class EZVCard2JSContact extends AbstractConverter {
private static final Pattern TIMEZONE_AS_UTC_OFFSET_PATTERN = Pattern.compile("[+-](\\d{2}):?(\\d{2})");
private static final String CUSTOM_TIME_ZONE_ID_PREFIX = "TZ";
public static final String CUSTOM_TIME_ZONE_RULE_START = "1900-01-01T00:00:00";
private static final long MILLIS_IN_A_DAY = 86400000;
private VCardPropertiesAltidComparator vCardPropertiesAltidComparator;
private VCardPropertiesPrefComparator vCardPropertiesPrefComparator;
protected VCard2JSContactConfig config;
private int customTimeZoneCounter = 0;
private final Map customTimeZones = new HashMap<>();
private static final Map phoneFeatureAliases = new HashMap() {{ put ("cell", PhoneFeatureEnum.MOBILE);}};
private List getVCard2JSContactProfileIds(JSContactIdsProfile.IdType idType, Object... args) {
List ids = new ArrayList<>();
for (JSContactIdsProfile.JSContactId jsContactId : config.getIdsProfileToUse().getIds()) {
if (jsContactId.getIdType() == idType) {
switch (idType) {
case RESOURCE:
JSContactIdsProfile.ResourceId resourceId = (JSContactIdsProfile.ResourceId) jsContactId.getId();
ResourceType type = (ResourceType) args[0];
if (resourceId.getType() == type)
ids.add(resourceId.getId());
break;
case PERSONAL_INFO:
JSContactIdsProfile.PersonalInfoId piId = (JSContactIdsProfile.PersonalInfoId) jsContactId.getId();
PersonalInfoEnum piType = (PersonalInfoEnum) args[0];
if (piId.getPersonalInfoEnum() == piType)
ids.add(piId.getId());
break;
default:
ids.add((String) jsContactId.getId());
break;
}
}
}
return ids;
}
private String getJSCardId(JSContactIdsProfile.IdType idType, int index, String id, String propId, Object... args) {
if (config.isUsePropIds() && propId != null)
return propId;
if (config.getIdsProfileToUse() == null || config.getIdsProfileToUse().getIds() == null || config.getIdsProfileToUse().getIds().size() == 0)
return id;
List ids = (idType == JSContactIdsProfile.IdType.RESOURCE || idType == JSContactIdsProfile.IdType.PERSONAL_INFO) ? getVCard2JSContactProfileIds(idType,args[0]) : getVCard2JSContactProfileIds(idType);
if (ids.size() == 0)
return id;
return (ids.get(index-1) == null) ? id : ids.get(index-1);
}
private static & VCardTypeDerivedEnum> E getJSCardEnumFromVCardTypeParam(Class enumType, String vcardTypeParam, List exclude, Map aliases) {
if (vcardTypeParam == null)
return null;
String[] items = vcardTypeParam.split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
for (String item : items) {
if (exclude!=null && exclude.contains(item))
continue;
try {
return EnumUtils.getEnum(enumType, item, aliases);
} catch (IllegalArgumentException ignored) {
}
try {
return EnumUtils.getEnum(enumType, item.toLowerCase(), aliases);
} catch (IllegalArgumentException ignored) {
}
}
return null;
}
private static & VCardTypeDerivedEnum> List getJSCardEnumValues(Class enumType, String vcardTypeParam, List exclude, Map aliases) {
if (vcardTypeParam == null)
return null;
List enumValues = new ArrayList<>();
String[] typeItems = vcardTypeParam.split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
for (String typeItem : typeItems) {
try {
E enumInstance = getJSCardEnumFromVCardTypeParam(enumType, typeItem, exclude, aliases);
if (enumInstance != null)
enumValues.add(enumInstance);
} catch (Exception e) {
throw new InternalErrorException(e.getMessage());
}
}
return (enumValues.size() > 0) ? enumValues : null;
}
private static Map toJSCardContexts(String vcardTypeParam) {
List enumValues = getJSCardEnumValues(ContextEnum.class,vcardTypeParam, null, ContextEnum.getAliases());
if (enumValues == null) return null;
Map contexts = new HashMap<>();
for (ContextEnum enumValue : enumValues) {
contexts.put(Context.rfc(enumValue), Boolean.TRUE);
}
return contexts;
}
private static Map toJSCardAddressContexts(String vcardTypeParam) {
List enumValues = getJSCardEnumValues(AddressContextEnum.class,vcardTypeParam, null, AddressContextEnum.getAliases());
if (enumValues == null) return null;
Map contexts = new HashMap<>();
for (AddressContextEnum enumValue : enumValues) {
contexts.put(AddressContext.rfc(enumValue), Boolean.TRUE);
}
return contexts;
}
private static Map toJSCardPhoneFeatures(String vcardTypeParam) {
List enumValues = getJSCardEnumValues(PhoneFeatureEnum.class,vcardTypeParam, Arrays.asList("home", "work"), phoneFeatureAliases);
Map phoneTypes = new HashMap<>();
if (enumValues != null) {
for (PhoneFeatureEnum enumValue : enumValues) {
phoneTypes.put(PhoneFeature.rfc(enumValue), Boolean.TRUE);
}
}
if (phoneTypes.size() == 0)
return null;
return phoneTypes;
}
private static Integer toJSCardPref(String vcardPref) {
return (vcardPref != null) ? Integer.parseInt(vcardPref) : null;
}
private static String toJSCardAutoFulllAddress(ExtendedAddress addr) {
StringJoiner joiner = new StringJoiner(DelimiterUtils.NEWLINE_DELIMITER);
if (StringUtils.isNotEmpty(addr.getPoBox())) joiner.add(addr.getPoBox());
if (StringUtils.isNotEmpty(addr.getExtendedAddressFull())) joiner.add(addr.getExtendedAddressFull());
if (StringUtils.isNotEmpty(addr.getStreetAddressFull())) joiner.add(addr.getStreetAddressFull());
if (StringUtils.isNotEmpty(addr.getLocality())) joiner.add(addr.getLocality());
if (StringUtils.isNotEmpty(addr.getRegion())) joiner.add(addr.getRegion());
if (StringUtils.isNotEmpty(addr.getPostalCode())) joiner.add(addr.getPostalCode());
if (StringUtils.isNotEmpty(addr.getCountry())) joiner.add(addr.getCountry());
String autoFullAddress = joiner.toString();
return StringUtils.isNotEmpty(autoFullAddress) ? autoFullAddress : null;
}
private String toJSCardFulllAddress(String addressLabel, String autoFullAddress) {
String fullAddress = addressLabel;
if (fullAddress == null && config.isSetAutoFullAddress()) {
fullAddress = autoFullAddress;
}
return fullAddress;
}
private String toJSCardLabel(VCardProperty vcardProperty, List vcardExtendedProperties) {
String group = vcardProperty.getGroup();
if (group == null)
return null;
for (RawProperty rawProperty : vcardExtendedProperties) {
if (rawProperty.getPropertyName().equalsIgnoreCase(VCardPropEnum.X_ABLABEL.getValue()) && rawProperty.getGroup().equals(group))
return rawProperty.getValue();
}
return null;
}
private Resource toJSCardResource(VCardProperty property) {
String value;
if (property instanceof UriProperty)
value = getValue((UriProperty) property);
else
value = getValue((BinaryProperty) property);
String vcardType = VCardUtils.getVCardParamValue(property.getParameters(), VCardParamEnum.TYPE);
Map contexts = toJSCardContexts(vcardType);
return Resource.builder()
.propId(property.getParameter(VCardParamEnum.PROP_ID.getValue()))
.uri(value)
.contexts(contexts)
.mediaType(toJSCardMediaType(VCardUtils.getVCardParamValue(property.getParameters(), VCardParamEnum.MEDIATYPE), value))
.pref(toJSCardPref(VCardUtils.getVCardParamValue(property.getParameters(), VCardParamEnum.PREF)))
.build();
}
private void addJSCardMediaResource(VCardProperty vcardProperty, Card jsCard, MediaKind type, int index, List vcardExtendedProperties) {
Resource resource = toJSCardResource(vcardProperty);
jsCard.addMediaResource(getJSCardId(JSContactIdsProfile.IdType.RESOURCE, index, String.format("%s-%s",type.getRfcValue().name(),index), vcardProperty.getParameter(VCardParamEnum.PROP_ID.getValue()), ResourceType.valueOf(type.getRfcValue().name())),
Media.builder()
.kind(type)
.propId(resource.getPropId())
.uri(resource.getUri())
.contexts(resource.getContexts())
.mediaType(resource.getMediaType())
.pref(resource.getPref())
.label(toJSCardLabel(vcardProperty, vcardExtendedProperties))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardProperty, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.MEDIATYPE))
.build()
);
}
private Directory toJSCardDirectoryResource(VCardProperty vcardProperty, DirectoryKind type, List vcardExtendedProperties) {
String index = vcardProperty.getParameter(VCardParamEnum.INDEX.getValue());
Resource resource = toJSCardResource(vcardProperty);
return Directory.builder()
.kind(type)
.propId(resource.getPropId())
.uri(resource.getUri())
.contexts(resource.getContexts())
.mediaType(resource.getMediaType())
.pref(resource.getPref())
.listAs((index != null) ? Integer.parseInt(index) : null) //used only for Directory objects whose "kind" is "directory"
.label(toJSCardLabel(vcardProperty, vcardExtendedProperties))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardProperty, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.MEDIATYPE, VCardParamEnum.INDEX))
.build();
}
private void addJSCardDirectoryResource(VCardProperty property, Card jsCard, DirectoryKind type, int index, List vcardExtendedProperties) {
jsCard.addDirectoryResource(getJSCardId(JSContactIdsProfile.IdType.RESOURCE, index, String.format("%s-%s",type.getRfcValue().name(),index), property.getParameter(VCardParamEnum.PROP_ID.getValue()), type),
toJSCardDirectoryResource(property,type, vcardExtendedProperties));
}
private void addJSCardDirectoryResource(Card jsCard, Directory resource, int index) {
jsCard.addDirectoryResource(getJSCardId(JSContactIdsProfile.IdType.RESOURCE, index, String.format("%s-%s",resource.getKind().getRfcValue().name(),index), resource.getPropId(), ResourceType.valueOf(resource.getKind().getRfcValue().name())),
resource);
}
private void addJSCardCryptoResource(VCardProperty vcardProperty, Card jsCard, int index, List vcardExtendedProperties) {
Resource resource = toJSCardResource(vcardProperty);
jsCard.addCryptoResource(getJSCardId(JSContactIdsProfile.IdType.RESOURCE, index, String.format("KEY-%s",index), vcardProperty.getParameter(VCardParamEnum.PROP_ID.getValue()), ResourceType.KEY),
CryptoKey.builder()
.propId(resource.getPropId())
.uri(resource.getUri())
.contexts(resource.getContexts())
.mediaType(resource.getMediaType())
.pref(resource.getPref())
.label(toJSCardLabel(vcardProperty, vcardExtendedProperties))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardProperty, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.MEDIATYPE))
.build()
);
}
private void addJSCardCalendarResource(VCardProperty vcardProperty, Card jsCard, CalendarKind type, int index, List vcardExtendedProperties) {
Resource resource = toJSCardResource(vcardProperty);
jsCard.addCalendarResource(getJSCardId(JSContactIdsProfile.IdType.RESOURCE, index, String.format("%s-%s",type.getRfcValue().name(),index), vcardProperty.getParameter(VCardParamEnum.PROP_ID.getValue()), ResourceType.valueOf(type.getRfcValue().name())),
Calendar.builder()
.kind(type)
.propId(resource.getPropId())
.uri(resource.getUri())
.contexts(resource.getContexts())
.mediaType(resource.getMediaType())
.pref(resource.getPref())
.label(toJSCardLabel(vcardProperty, vcardExtendedProperties))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardProperty, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.MEDIATYPE))
.build()
);
}
private void addJSCardLinkResource(VCardProperty vcardProperty, Card jsCard, LinkKind type, int index, List vcardExtendedProperties) {
Resource resource = toJSCardResource(vcardProperty);
jsCard.addLinkResource(getJSCardId(JSContactIdsProfile.IdType.RESOURCE, index, String.format("%s-%s",(type!=null) ? type.getRfcValue().name() : "LINK",index), vcardProperty.getParameter(VCardParamEnum.PROP_ID.getValue()), (type!=null) ? ResourceType.valueOf(type.getRfcValue().name()) : ResourceType.LINK),
Link.builder()
.kind(type)
.propId(resource.getPropId())
.uri(resource.getUri())
.contexts(resource.getContexts())
.mediaType(resource.getMediaType())
.pref(resource.getPref())
.label(toJSCardLabel(vcardProperty, vcardExtendedProperties))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardProperty, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.MEDIATYPE))
.build()
);
}
private static String getValue(GeoUri geoUri) {
return (geoUri!=null) ? geoUri.toUri().toString() : null;
}
private static it.cnr.iit.jscontact.tools.dto.Address getValue(PlaceProperty property) {
if (property == null)
return null;
if (property.getText() != null && property.getGeoUri() == null)
return it.cnr.iit.jscontact.tools.dto.Address.builder()
.full(property.getText())
.build();
else if (property.getGeoUri() != null)
return it.cnr.iit.jscontact.tools.dto.Address.builder()
.coordinates(getValue(property.getGeoUri()))
.build();
else
return null;
}
@Deprecated
private static String getValue(DateOrTimeProperty property) {
if (property.getText() != null)
return property.getText();
else if (property.getPartialDate()!=null)
return property.getPartialDate().toISO8601(true);
else
return DateUtils.toString(property.getCalendar());
}
private static String getValue(Telephone property) {
if (property.getText() != null)
return property.getText();
else
return property.getUri().toString();
}
private static String getValue(Related property) {
if (property.getText() != null)
return property.getText();
else
return property.getUri();
}
private String getValue(Timezone property) {
if (property.getText()!= null)
return property.getText();
else {
String offset = property.getOffset().toString();
String sign = offset.substring(0,1);
String hours = offset.substring(1,3);
String minutes = offset.substring(3,5);
if (minutes.equals("00"))
return String.format("Etc/GMT%s%s%s",
(hours.equals("00") && minutes.equals("00")) ? StringUtils.EMPTY : (sign.equals("+") ? "-" : "+") ,
(hours.equals("00") && minutes.equals("00")) ? StringUtils.EMPTY : String.valueOf(Integer.parseInt(hours)),
(minutes.equals("00") ? StringUtils.EMPTY : ":" + minutes));
else {
String timeZoneName = String.format("%s%d", config.getCustomTimeZonesPrefix(), ++customTimeZoneCounter);
customTimeZones.put(timeZoneName, TimeZone.builder()
.tzId(String.format("%s%s%s%s",CUSTOM_TIME_ZONE_ID_PREFIX,sign,hours,minutes))
.updated(java.util.Calendar.getInstance())
.standardItem(TimeZoneRule.builder()
.offsetFrom(String.format("%s%s%s",sign,hours,minutes))
.offsetTo(String.format("%s%s%s",sign,hours,minutes))
.start(DateUtils.toCalendar(CUSTOM_TIME_ZONE_RULE_START))
.build()
)
.build()
);
return timeZoneName;
}
}
}
private static String getValue(BinaryProperty property) {
if (property.getUrl()!=null)
return property.getUrl();
else
return new DataUri(property.getContentType().getMediaType(), property.getData()).toString();
}
private static String getValue(TextProperty property) {
if (property == null)
return null;
return property.getValue();
}
private static String getValue(Impp property) {
return property.getUri().toString();
}
private void fillJSCardSpeakToAsOrGender(VCard vCard, Card jsCard) {
if (vCard.getGender() == null)
return;
if (!config.isConvertGenderToSpeakToAs()) {
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(VCardPropEnum.GENDER.getValue().toLowerCase()))
.parameters(VCardUtils.getVCardPropParams(vCard.getGender().getParameters()))
.type(VCardDataType.TEXT)
.value(String.format("%s%s", vCard.getGender().getGender(), (vCard.getGender().getText()==null) ? StringUtils.EMPTY : ";"+vCard.getGender().getText()))
.build());
return;
}
if (vCard.getExtendedProperty(VCardPropEnum.GRAMGENDER.getValue()) != null)
return;
if (vCard.getGender() != null) {
if (vCard.getGender().isMale())
jsCard.setSpeakToAs(SpeakToAs.masculine());
else if (vCard.getGender().isFemale())
jsCard.setSpeakToAs(SpeakToAs.feminine());
else if (vCard.getGender().isOther())
jsCard.setSpeakToAs(SpeakToAs.animate());
else if (vCard.getGender().isNone())
jsCard.setSpeakToAs(SpeakToAs.common());
} else {
jsCard.setSpeakToAs(SpeakToAs.builder().grammaticalGender(GrammaticalGenderType.getEnum(vCard.getExtendedProperty(VCardPropEnum.GRAMGENDER.getValue()).getValue().toLowerCase())).build());
}
}
private static boolean structuredNameWithAltidExists(List extendedStructuredNames, String altid, String language) {
if (extendedStructuredNames == null || extendedStructuredNames.isEmpty())
return false;
for (ExtendedStructuredName esn : extendedStructuredNames) {
if (language != null) {
if (esn.getAltId()!= null && esn.getAltId().equals(altid) && esn.getLanguage()!=null && esn.getLanguage().equals(language))
return true;
}
else if (esn.getAltId()!= null && esn.getAltId().equals(altid))
return true;
}
return false;
}
private boolean isFNDerivedFromN(FormattedName fn, VCard vcard) {
List fns = vcard.getFormattedNames();
if (fn.getParameter(VCardParamEnum.DERIVED.getValue()) != null && Boolean.parseBoolean(fn.getParameter(VCardParamEnum.DERIVED.getValue())) == Boolean.TRUE ) {
if (fns.size() == 1) {
if (vcard.getProperties(ExtendedStructuredName.class) != null && !vcard.getProperties(ExtendedStructuredName.class).isEmpty()) // structured name corresponding to full name exists
return true;
} else {
if (fn.getAltId()!=null && structuredNameWithAltidExists(vcard.getProperties(ExtendedStructuredName.class), fn.getAltId(), fn.getLanguage())) // structured name corresponding to full name exists
return true;
}
}
return false;
}
private boolean isFNDerivedFromUid(FormattedName fn, VCard vcard) {
if (vcard.getUid() != null && fn.getValue().equals(vcard.getUid().getValue()))
return true;
return false;
}
private void fillJSCardFullName(VCard vcard, Card jsCard) {
if (vcard.getFormattedNames() == null || vcard.getFormattedNames().isEmpty())
return;
List fns = vcard.getFormattedNames();
fns.sort(vCardPropertiesAltidComparator);
String lastAltid = null;
FormattedName candidateFn = null;
int candidatePref = 101;
for (FormattedName fn : fns) {
if (fn.getLanguage() == null) {
if (candidateFn == null) {
candidateFn = fn;
if (fn.getPref()!=null)
candidatePref = fn.getPref();
}
else if (fn.getPref()!=null && (candidatePref == 101 || fn.getPref() < candidatePref)) {
candidateFn = fn;
candidatePref = candidateFn.getPref();
} else if (candidatePref == 101 && fn.getParameters().size() < candidateFn.getParameters().size())
candidateFn = fn;
}
}
for (FormattedName fn : fns) {
if (isFNDerivedFromN(fn,vcard) || isFNDerivedFromUid(fn,vcard))
continue;
if (candidateFn != null && candidateFn.getValue().equals(fn.getValue())) {
if (jsCard.getName() == null) //no N property exists
jsCard.setName(Name.builder().full(fn.getValue()).build());
else
jsCard.getName().setFull(fn.getValue());
continue;
}
if (fn.getLanguage() == null) {
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(VCardPropEnum.FN.getValue().toLowerCase()))
.parameters(VCardUtils.getVCardPropParams(fn.getParameters()))
.type(VCardDataType.TEXT)
.value(fn.getValue())
.build());
} else {
if (fn.getAltId() == null || lastAltid == null || !fn.getAltId().equals(lastAltid)) {
if (jsCard.getName() == null) //no N property exists
jsCard.setName(Name.builder().full(fn.getValue()).build());
else
jsCard.getName().setFull(fn.getValue());
lastAltid = fn.getAltId();
} else {
jsCard.addLocalization(fn.getLanguage(), "name", mapper.convertValue(Name.builder().full(fn.getValue()).build(), JsonNode.class));
}
}
}
}
private void fillJSCardMembers(VCard vcard, Card jsCard) {
List members = vcard.getMembers();
members.sort(vCardPropertiesPrefComparator);
for (Member member : members)
jsCard.addMember(member.getValue());
}
private static Map toJSCardNameSortAs(List vcardSortAs, ExtendedStructuredName sn) {
if (vcardSortAs == null || vcardSortAs.isEmpty())
return null;
Map sortAs = new HashMap<>();
NameComponentEnum[] nameComponentEnumValues = NameComponentEnum.values();
int i = 0;
for (String vcardSortAsItem : vcardSortAs) {
String[] vcardSortAsItemSubs = vcardSortAsItem.split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
for (String vcardSortAsItemSub : vcardSortAsItemSubs)
sortAs.put(NameComponentKind.rfc(nameComponentEnumValues[i++]), vcardSortAsItemSub);
}
return sortAs;
}
private Name toJSCardName(ExtendedStructuredName vcardName) {
NameComponent[] components = null;
String[] jscomps = (vcardName.getParameter(VCardParamEnum.JSCOMPS.getValue())!=null) ? vcardName.getParameter(VCardParamEnum.JSCOMPS.getValue()).split(DelimiterUtils.SEMICOLON_ARRAY_DELIMITER) : null;
boolean isPhonetic = (vcardName.getParameter(VCardParamEnum.PHONETIC.getValue())!=null) || (vcardName.getParameter(VCardParamEnum.SCRIPT.getValue())!=null);
int indexPerKind;
if (jscomps == null || jscomps.length < 2) {
if (vcardName.getFamilyNames() != null) {
indexPerKind = 0;
for (String surname : vcardName.getFamilyNames()) {
if (vcardName.getSurname2().contains(surname))
continue;
components = Name.addComponent(components, NameComponent.builder().kind(NameComponentKind.surname()).value(surname).phonetic((isPhonetic) ? surname : null).indexPerKind(indexPerKind).build());
}
}
if (vcardName.getGiven() != null) {
indexPerKind = 0;
String[] names = vcardName.getGiven().split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
for (String name : names)
components = Name.addComponent(components, NameComponent.builder().kind(NameComponentKind.given()).value(name).phonetic((isPhonetic) ? name : null).indexPerKind(indexPerKind).build());
}
indexPerKind = 0;
for (String an : vcardName.getAdditionalNames())
components = Name.addComponent(components, NameComponent.builder().kind(NameComponentKind.given2()).value(an).phonetic((isPhonetic) ? an : null).indexPerKind(indexPerKind).build());
indexPerKind = 0;
for (String px : vcardName.getPrefixes())
components = Name.addComponent(components, NameComponent.builder().kind(NameComponentKind.title()).value(px).phonetic((isPhonetic) ? px : null).indexPerKind(indexPerKind).build());
indexPerKind = 0;
for (String sx : vcardName.getSuffixes()) {
if (vcardName.getGeneration().contains(sx))
continue;
components = Name.addComponent(components, NameComponent.builder().kind(NameComponentKind.credential()).value(sx).phonetic((isPhonetic) ? sx : null).indexPerKind(indexPerKind).build());
}
indexPerKind = 0;
for (String sx : vcardName.getSurname2())
components = Name.addComponent(components, NameComponent.builder().kind(NameComponentKind.surname2()).value(sx).phonetic((isPhonetic) ? sx : null).indexPerKind(indexPerKind).build());
indexPerKind = 0;
for (String sx : vcardName.getGeneration())
components = Name.addComponent(components, NameComponent.builder().kind(NameComponentKind.generation()).value(sx).phonetic((isPhonetic) ? sx : null).indexPerKind(indexPerKind).build());
}
else {
for (int i = 1; i < jscomps.length; i++) {
if (jscomps[i].startsWith(DelimiterUtils.SEPARATOR_ID)) {
components = Name.addComponent(components, NameComponent.separator(jscomps[i].replace(DelimiterUtils.SEPARATOR_ID + "\\",StringUtils.EMPTY).replace(DelimiterUtils.SEPARATOR_ID, StringUtils.EMPTY)));
continue;
}
String[] items = jscomps[i].split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
int index1 = Integer.parseInt(items[0]);
int index2 = (items.length == 1) ? 0 : Integer.parseInt(items[1]);
NameComponentKind kind = null;
String value = null;
switch (index1) {
case 0:
kind = NameComponentKind.surname();
value = vcardName.getFamilyNames().get(index2);
break;
case 1:
kind = NameComponentKind.given();
String[] names = vcardName.getGiven().split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
value = names[index2];
break;
case 2:
kind = NameComponentKind.given2();
value = vcardName.getAdditionalNames().get(index2);
break;
case 3:
kind = NameComponentKind.title();
value = vcardName.getPrefixes().get(index2);
break;
case 4:
kind = NameComponentKind.credential();
value = vcardName.getSuffixes().get(index2);
break;
case 5:
kind = NameComponentKind.surname2();
value = vcardName.getSurname2().get(index2);
break;
case 6:
kind = NameComponentKind.generation();
value = vcardName.getGeneration().get(index2);
break;
}
components = Name.addComponent(components, NameComponent.builder().kind(kind).value(value).phonetic((isPhonetic) ? value : null).indexPerKind(index2).build());
}
}
PhoneticSystem phoneticSystem = null;
if (vcardName.getParameter(VCardParamEnum.PHONETIC.getValue())!=null && !vcardName.getParameter(VCardParamEnum.PHONETIC.getValue()).equalsIgnoreCase(PhoneticSystemEnum.SCRIPT.getValue())) {
try {
phoneticSystem = PhoneticSystem.rfc(PhoneticSystemEnum.getEnum(vcardName.getParameter(VCardParamEnum.PHONETIC.getValue())));
} catch (IllegalArgumentException e) {
phoneticSystem = PhoneticSystem.ext(vcardName.getParameter(VCardParamEnum.PHONETIC.getValue()));
}
}
return Name.builder()
.components(components)
.sortAs(toJSCardNameSortAs(vcardName.getSortAs(), vcardName))
.defaultSeparator((ArrayUtils.isNotEmpty(jscomps) && jscomps[0].startsWith(DelimiterUtils.SEPARATOR_ID)) ? jscomps[0].replace(DelimiterUtils.SEPARATOR_ID + "\\",StringUtils.EMPTY).replace(DelimiterUtils.SEPARATOR_ID,StringUtils.EMPTY) : null)
.isOrdered((jscomps!=null) ? Boolean.TRUE : null)
.phoneticSystem(phoneticSystem)
.phoneticScript(vcardName.getParameter(VCardParamEnum.SCRIPT.getValue()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardName, VCardParamEnum.LANGUAGE, VCardParamEnum.SORT_AS, VCardParamEnum.ALTID, VCardParamEnum.JSCOMPS))
.build();
}
private String getFullNamePerLanguage(VCard vcard, String language) {
if (vcard.getFormattedNames() == null)
return null;
for (FormattedName fn : vcard.getFormattedNames()) {
if (isFNDerivedFromN(fn, vcard)|| isFNDerivedFromUid(fn,vcard))
continue;
if (fn.getLanguage()!= null && fn.getLanguage().equals(language))
return fn.getValue();
}
return null;
}
private Name getNamePlusPhonetic(Name name, Name phoneticName) {
name.setPhoneticSystem(phoneticName.getPhoneticSystem());
name.setPhoneticScript(phoneticName.getPhoneticScript());
for (int i = 0; i < name.getComponents().length; i++) {
for (int j=0; j < phoneticName.getComponents().length; j++) {
if (name.getComponents()[i].getKind().equals(phoneticName.getComponents()[j].getKind()) &&
name.getComponents()[i].getIndexPerKind() == phoneticName.getComponents()[j].getIndexPerKind())
name.getComponents()[i].setPhonetic(phoneticName.getComponents()[j].getPhonetic());
}
}
return name;
}
private void fillJSCardNames(VCard vcard, Card jsCard) {
if (vcard.getProperties(ExtendedStructuredName.class) == null || vcard.getProperties(ExtendedStructuredName.class).isEmpty())
return;
List vcardNames = vcard.getProperties(ExtendedStructuredName.class);
vcardNames.sort(vCardPropertiesAltidComparator);
if (jsCard.getName() == null) // no full name exists
jsCard.setName(toJSCardName(vcardNames.get(0))); //the first N property is the name, all the others name are localizations or phonetic
else {
// full name already been set,
String fullName = jsCard.getName().getFull();
Name name = toJSCardName(vcardNames.get(0));
name.setFull(fullName);
jsCard.setName(name);
}
if (vcardNames.size() == 2) {
boolean isPhonetic = (vcardNames.get(1).getParameter(VCardParamEnum.PHONETIC.getValue())!=null) || (vcardNames.get(1).getParameter(VCardParamEnum.SCRIPT.getValue())!=null);
if (isPhonetic) { // this is a phonetic
jsCard.setName(getNamePlusPhonetic(jsCard.getName(), toJSCardName(vcardNames.get(1))));
}
}
if (jsCard.getLanguage() == null && vcardNames.get(0).getLanguage() != null)
jsCard.setLanguage(vcardNames.get(0).getLanguage());
for (int i = 1; i < vcardNames.size(); i++) {
String language = vcardNames.get(i).getLanguage();
Name name = toJSCardName(vcardNames.get(i));
if (name.getPhoneticSystem() != null || name.getPhoneticScript() != null) {
if (name.getPhoneticSystem()!= null)
jsCard.addLocalization(language, "name/phoneticSystem", JsonNodeUtils.textNode(name.getPhoneticSystem().toJson()));
if (name.getPhoneticScript()!= null)
jsCard.addLocalization(language, "name/phoneticScript", JsonNodeUtils.textNode(name.getPhoneticScript()));
if (name.getComponents() != null) {
int j = 0;
for (NameComponent component : name.getComponents()) {
if (component.getValue().equals(component.getPhonetic()))
jsCard.addLocalization(language, "name/components/" + j++ + "/phonetic", JsonNodeUtils.textNode(component.getPhonetic()));
}
}
}
else if (jsCard.getLocalization(language, "name") == null)
jsCard.addLocalization(language, "name", mapper.convertValue(name, JsonNode.class));
else {
name.setFull(getFullNamePerLanguage(vcard, language));
jsCard.addLocalization(language, "name", mapper.convertValue(name, JsonNode.class));
}
}
}
private Nickname toJSCardNickName(String name, ezvcard.property.Nickname vcardNickname, VCard vcard) {
return Nickname.builder()
.name(name)
.pref(vcardNickname.getPref())
.contexts(toJSCardContexts(vcardNickname.getType()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardNickname, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.ALTID))
.build();
}
private void fillJSCardNickNames(VCard vcard, Card jsCard) {
if (vcard.getNicknames() == null || vcard.getNicknames().isEmpty())
return;
List vcardNickNames = vcard.getNicknames();
vcardNickNames.sort(vCardPropertiesAltidComparator);
int i = 1;
String lastAltid = null;
String lastMapId = null;
for (ezvcard.property.Nickname vcardNickName : vcardNickNames) {
for (String name : vcardNickName.getValues()) {
if (vcardNickName.getAltId() == null || lastAltid == null || !vcardNickName.getAltId().equals(lastAltid)) {
String propId = vcardNickName.getParameter(VCardParamEnum.PROP_ID.getValue());
String id = getJSCardId(JSContactIdsProfile.IdType.NICKNAME, i, "NICK-" + (i++), propId);
jsCard.addNickName(id, toJSCardNickName(name, vcardNickName, vcard));
lastAltid = vcardNickName.getAltId();
lastMapId = id;
}
else {
jsCard.addLocalization(vcardNickName.getLanguage(), "nicknames/" + lastMapId, mapper.convertValue(toJSCardNickName(name, vcardNickName, vcard), JsonNode.class));
}
}
}
}
private static it.cnr.iit.jscontact.tools.dto.Address findJSCardAddressByGroup(List addresses, String group) {
if (group == null)
return null;
for (Address address : addresses) {
if (address.getGroup()!=null && address.getGroup().equalsIgnoreCase(group))
return address;
}
return null;
}
private String toJSCardTimezoneName(String vcardTzParam) {
if (vcardTzParam == null)
return null;
Matcher m = TIMEZONE_AS_UTC_OFFSET_PATTERN.matcher(vcardTzParam);
if (m.find())
return getValue(new Timezone(UtcOffset.parse(vcardTzParam.replace(":", StringUtils.EMPTY))));
else
return vcardTzParam;
}
private Address toJSCardAddress(ExtendedAddress vcardAddr) {
List streetDetailPairs = new ArrayList<>();
String[] jscomps = (vcardAddr.getParameter(VCardParamEnum.JSCOMPS.getValue())!=null) ? vcardAddr.getParameter(VCardParamEnum.JSCOMPS.getValue()).split(DelimiterUtils.SEMICOLON_ARRAY_DELIMITER) : null;
boolean isPhonetic = (vcardAddr.getParameter(VCardParamEnum.PHONETIC.getValue())!=null) || (vcardAddr.getParameter(VCardParamEnum.SCRIPT.getValue())!=null);
if (jscomps == null || jscomps.length < 2) {
if (StringUtils.isNotEmpty(vcardAddr.getPoBox()))
streetDetailPairs.add(AddressComponent.postOfficeBox(vcardAddr.getPoBox()));
if (StringUtils.isNotEmpty(vcardAddr.getLocality()))
streetDetailPairs.add(AddressComponent.locality(vcardAddr.getLocality(), (isPhonetic) ? vcardAddr.getLocality() : null));
if (StringUtils.isNotEmpty(vcardAddr.getRegion()))
streetDetailPairs.add(AddressComponent.region(vcardAddr.getRegion(), (isPhonetic) ? vcardAddr.getRegion() : null));
if (StringUtils.isNotEmpty(vcardAddr.getPostalCode()))
streetDetailPairs.add(AddressComponent.postcode(vcardAddr.getPostalCode()));
if (StringUtils.isNotEmpty(vcardAddr.getCountry()))
streetDetailPairs.add(AddressComponent.country(vcardAddr.getCountry(), (isPhonetic) ? vcardAddr.getCountry() : null));
if (StringUtils.isNotEmpty(vcardAddr.getRoom()))
streetDetailPairs.add(AddressComponent.room(vcardAddr.getRoom()));
if (!vcardAddr.isExtended() && StringUtils.isNotEmpty(vcardAddr.getExtendedAddress()))
streetDetailPairs.add(AddressComponent.apartment(vcardAddr.getExtendedAddress()));
if (StringUtils.isNotEmpty(vcardAddr.getApartment()))
streetDetailPairs.add(AddressComponent.apartment(vcardAddr.getApartment()));
if (StringUtils.isNotEmpty(vcardAddr.getFloor()))
streetDetailPairs.add(AddressComponent.floor(vcardAddr.getFloor()));
if (!vcardAddr.isExtended() && StringUtils.isNotEmpty(vcardAddr.getStreetAddressFull()))
streetDetailPairs.add(AddressComponent.name(vcardAddr.getStreetAddressFull(), (isPhonetic) ? vcardAddr.getStreetAddressFull() : null));
if (StringUtils.isNotEmpty(vcardAddr.getStreetNumber()))
streetDetailPairs.add(AddressComponent.number(vcardAddr.getStreetNumber()));
if (StringUtils.isNotEmpty(vcardAddr.getStreetName()))
streetDetailPairs.add(AddressComponent.name(vcardAddr.getStreetName(), (isPhonetic) ? vcardAddr.getStreetName() : null));
if (StringUtils.isNotEmpty(vcardAddr.getBuilding()))
streetDetailPairs.add(AddressComponent.building(vcardAddr.getBuilding(), (isPhonetic) ? vcardAddr.getBuilding() : null));
if (StringUtils.isNotEmpty(vcardAddr.getBlock()))
streetDetailPairs.add(AddressComponent.block(vcardAddr.getBlock(), (isPhonetic) ? vcardAddr.getBlock() : null));
if (StringUtils.isNotEmpty(vcardAddr.getSubDistrict()))
streetDetailPairs.add(AddressComponent.subdistrict(vcardAddr.getSubDistrict(), (isPhonetic) ? vcardAddr.getSubDistrict() : null));
if (StringUtils.isNotEmpty(vcardAddr.getDistrict()))
streetDetailPairs.add(AddressComponent.district(vcardAddr.getDistrict(), (isPhonetic) ? vcardAddr.getDistrict() : null));
if (StringUtils.isNotEmpty(vcardAddr.getLandmark()))
streetDetailPairs.add(AddressComponent.landmark(vcardAddr.getLandmark(), (isPhonetic) ? vcardAddr.getLandmark() : null));
if (StringUtils.isNotEmpty(vcardAddr.getDirection()))
streetDetailPairs.add(AddressComponent.direction(vcardAddr.getDirection()));
} else {
for (int i = 1; i < jscomps.length; i++) {
if (jscomps[i].startsWith(DelimiterUtils.SEPARATOR_ID)) {
streetDetailPairs.add(AddressComponent.separator(jscomps[i].replace(DelimiterUtils.SEPARATOR_ID + "\\",StringUtils.EMPTY).replace(DelimiterUtils.SEPARATOR_ID, StringUtils.EMPTY)));
continue;
}
String[] items = jscomps[i].split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
int index1 = Integer.parseInt(items[0]);
int index2 = (items.length == 1) ? 0 : Integer.parseInt(items[1]);
switch (index1) {
case 0:
streetDetailPairs.add(AddressComponent.postOfficeBox(vcardAddr.getPoBoxes().get(index2)));
break;
case 1:
if (!vcardAddr.isExtended())
streetDetailPairs.add(AddressComponent.apartment(vcardAddr.getExtendedAddress()));
break;
case 2:
if (!vcardAddr.isExtended())
streetDetailPairs.add(AddressComponent.name(vcardAddr.getStreetAddresses().get(index2), (isPhonetic) ? vcardAddr.getStreetAddresses().get(index2) : null));
break;
case 3:
streetDetailPairs.add(AddressComponent.locality(vcardAddr.getLocalities().get(index2), (isPhonetic) ? vcardAddr.getLocalities().get(index2) : null));
break;
case 4:
streetDetailPairs.add(AddressComponent.region(vcardAddr.getRegions().get(index2), (isPhonetic) ? vcardAddr.getRegions().get(index2) : null));
break;
case 5:
streetDetailPairs.add(AddressComponent.postcode(vcardAddr.getPostalCodes().get(index2)));
break;
case 6:
streetDetailPairs.add(AddressComponent.country(vcardAddr.getCountries().get(index2), (isPhonetic) ? vcardAddr.getCountries().get(index2) : null));
break;
case 7:
streetDetailPairs.add(AddressComponent.room(vcardAddr.getRooms().get(index2)));
break;
case 8:
streetDetailPairs.add(AddressComponent.apartment(vcardAddr.getApartments().get(index2)));
break;
case 9:
streetDetailPairs.add(AddressComponent.floor(vcardAddr.getFloors().get(index2)));
break;
case 10:
streetDetailPairs.add(AddressComponent.number(vcardAddr.getStreetNumbers().get(index2)));
break;
case 11:
streetDetailPairs.add(AddressComponent.name(vcardAddr.getStreetNames().get(index2), (isPhonetic) ? vcardAddr.getStreetNames().get(index2) : null));
break;
case 12:
streetDetailPairs.add(AddressComponent.building(vcardAddr.getBuildings().get(index2), (isPhonetic) ? vcardAddr.getBuildings().get(index2) : null));
break;
case 13:
streetDetailPairs.add(AddressComponent.block(vcardAddr.getBlocks().get(index2), (isPhonetic) ? vcardAddr.getBlocks().get(index2) : null));
break;
case 14:
streetDetailPairs.add(AddressComponent.subdistrict(vcardAddr.getSubDistricts().get(index2), (isPhonetic) ? vcardAddr.getSubDistricts().get(index2) : null));
break;
case 15:
streetDetailPairs.add(AddressComponent.district(vcardAddr.getDistricts().get(index2), (isPhonetic) ? vcardAddr.getDistricts().get(index2) : null));
break;
case 16:
streetDetailPairs.add(AddressComponent.landmark(vcardAddr.getLandmarks().get(index2), (isPhonetic) ? vcardAddr.getLandmarks().get(index2) : null));
break;
case 17:
streetDetailPairs.add(AddressComponent.direction(vcardAddr.getDirections().get(index2)));
break;
}
}
}
String autoFullAddress = toJSCardAutoFulllAddress(vcardAddr);
String vcardTypeParam = VCardUtils.getVCardParamValue(vcardAddr.getParameters(), VCardParamEnum.TYPE);
PhoneticSystem phoneticSystem = null;
if (vcardAddr.getParameter(VCardParamEnum.PHONETIC.getValue())!=null && !vcardAddr.getParameter(VCardParamEnum.PHONETIC.getValue()).equalsIgnoreCase(PhoneticSystemEnum.SCRIPT.getValue())) {
try {
phoneticSystem = PhoneticSystem.rfc(PhoneticSystemEnum.getEnum(vcardAddr.getParameter(VCardParamEnum.PHONETIC.getValue())));
} catch (IllegalArgumentException e) {
phoneticSystem = PhoneticSystem.ext(vcardAddr.getParameter(VCardParamEnum.PHONETIC.getValue()));
}
}
return it.cnr.iit.jscontact.tools.dto.Address.builder()
.hash(autoFullAddress)
.propId(vcardAddr.getParameter(VCardParamEnum.PROP_ID.getValue()))
.contexts(toJSCardAddressContexts(vcardTypeParam))
.full(toJSCardFulllAddress(vcardAddr.getLabel(), autoFullAddress))
.pref(vcardAddr.getPref())
.coordinates(getValue(vcardAddr.getGeo()))
.timeZone(toJSCardTimezoneName(vcardAddr.getTimezone()))
.countryCode((VCardParamEnum.CC.getValue()!=null) ? vcardAddr.getParameter(VCardParamEnum.CC.getValue()) : vcardAddr.getParameter(VCardParamEnum.ISO_3166_1_ALPHA_2.getValue()))
.components((streetDetailPairs.size() > 0) ? streetDetailPairs.toArray(new AddressComponent[0]) : null)
.altid(vcardAddr.getAltId())
.group(vcardAddr.getGroup())
.language(vcardAddr.getLanguage())
.defaultSeparator((ArrayUtils.isNotEmpty(jscomps) && jscomps[0].startsWith(DelimiterUtils.SEPARATOR_ID)) ? jscomps[0].replace(DelimiterUtils.SEPARATOR_ID + "\\",StringUtils.EMPTY).replace(DelimiterUtils.SEPARATOR_ID,StringUtils.EMPTY) : null)
.isOrdered((jscomps!=null) ? Boolean.TRUE : null)
.propId(vcardAddr.getParameter(VCardParamEnum.PROP_ID.getValue()))
.phoneticSystem(phoneticSystem)
.phoneticScript(vcardAddr.getParameter(VCardParamEnum.SCRIPT.getValue()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardAddr, VCardParamEnum.PROP_ID, VCardParamEnum.LANGUAGE, VCardParamEnum.LABEL, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.CC, VCardParamEnum.TZ, VCardParamEnum.GEO, VCardParamEnum.DERIVED, VCardParamEnum.ALTID, VCardParamEnum.JSCOMPS))
.build();
}
private Address getAddressPlusPhonetic(Address address, Address phoneticAddress) {
address.setPhoneticSystem(phoneticAddress.getPhoneticSystem());
address.setPhoneticScript(phoneticAddress.getPhoneticScript());
for (int i = 0; i < address.getComponents().length; i++) {
for (int j = 0; j < phoneticAddress.getComponents().length; j++) {
if (address.getComponents()[i].getKind().equals(phoneticAddress.getComponents()[j].getKind()))
address.getComponents()[i].setPhonetic(phoneticAddress.getComponents()[j].getPhonetic());
}
}
return address;
}
private void fillJSCardAddresses(VCard vcard, Card jsCard) {
if (vcard.getProperties(ExtendedAddress.class) == null || vcard.getProperties(ExtendedAddress.class).isEmpty())
return;
List addresses = new ArrayList<>();
String tz;
String geo;
for (ExtendedAddress addr : vcard.getProperties(ExtendedAddress.class))
addresses.add(toJSCardAddress(addr));
if (vcard.getTimezone() != null) {
tz = getValue(vcard.getTimezone());
it.cnr.iit.jscontact.tools.dto.Address address = findJSCardAddressByGroup(addresses, vcard.getTimezone().getGroup());
if (address != null) {
address.setTimeZone(tz);
} else {
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(VCardPropEnum.TZ.getValue().toLowerCase()))
.parameters(VCardUtils.getVCardPropParams(vcard.getTimezone().getParameters()))
.type(vcard.getTimezone().getParameters().getValue())
.value(tz)
.build());
}
}
if (vcard.getGeo() != null) {
geo = getValue(vcard.getGeo().getGeoUri());
it.cnr.iit.jscontact.tools.dto.Address address = findJSCardAddressByGroup(addresses, vcard.getGeo().getGroup());
if (address != null) {
address.setCoordinates(geo);
} else {
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(VCardPropEnum.GEO.getValue().toLowerCase()))
.parameters(VCardUtils.getVCardPropParams(vcard.getGeo().getParameters()))
.type(vcard.getGeo().getParameters().getValue())
.value(geo)
.build());
}
}
addresses.sort(JSCardAddressesComparator.builder().defaultLanguage(jsCard.getLanguage()).build()); //sort based on altid
int i = 1;
String lastAltid = null;
String lastMapId = null;
for (Address address : addresses) {
if (address.getAltid() == null && jsCard.getLanguage() == null && address.getLanguage() != null)
jsCard.setLanguage(address.getLanguage());
if (address.getAltid() == null || !address.getAltid().equals(lastAltid)) {
String id = getJSCardId(JSContactIdsProfile.IdType.ADDRESS, i, "ADR-" + (i++), address.getPropId() );
jsCard.addAddress(id, address);
lastAltid = address.getAltid();
lastMapId = id;
} else {
if (address.getPhoneticSystem()!= null || address.getPhoneticScript() != null) {
if (address.getLanguage()==null) {
jsCard.getAddresses().replace(lastMapId, getAddressPlusPhonetic(jsCard.getAddresses().get(lastMapId), address));
} else {
if (address.getPhoneticSystem() != null)
jsCard.addLocalization(address.getLanguage(), "addresses/" + lastMapId + "/phoneticSystem", JsonNodeUtils.textNode(address.getPhoneticSystem().toJson()));
if (address.getPhoneticScript() != null)
jsCard.addLocalization(address.getLanguage(), "addresses/" + lastMapId + "/phoneticScript", JsonNodeUtils.textNode(address.getPhoneticScript()));
if (address.getComponents() != null) {
for (AddressComponent component : address.getComponents()) {
if (component.getValue().equals(component.getPhonetic()))
jsCard.addLocalization(address.getLanguage(), "addresses/" + lastMapId + "/components/" + i + "/phonetic", JsonNodeUtils.textNode(component.getPhonetic()));
}
}
}
}
else
jsCard.addLocalization(address.getLanguage(), "addresses/" + lastMapId, mapper.convertValue(address, JsonNode.class));
}
}
}
private static AnniversaryDate toJSCardAnniversaryDate(T date) {
try {
if (date.getDate() != null) {
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.setTime(date.getDate());
if (!DateUtils.hasTime(calendar)) { // date doesn't have time
PartialDate pd = PartialDate.builder().year(calendar.get(java.util.Calendar.YEAR))
.month(calendar.get(java.util.Calendar.MONTH)+1)
.day(calendar.get(java.util.Calendar.DAY_OF_MONTH))
.calendarScale((date.getCalscale()!=null) ? date.getCalscale().getValue() : null)
.build();
return AnniversaryDate.builder().partialDate(pd).build();
}
else
return AnniversaryDate.builder().date(Timestamp.builder().utc(date.getCalendar()).build()).build();
}
if (date.getPartialDate() != null) {
PartialDate pd = PartialDate.builder().year(date.getPartialDate().getYear())
.month(date.getPartialDate().getMonth())
.day(date.getPartialDate().getDate())
.calendarScale((date.getCalscale()!=null) ? date.getCalscale().getValue() : null)
.build();
return AnniversaryDate.builder().partialDate(pd).build();
}
if (date.getText() != null)
return null;
} catch (Exception e) {
throw new InternalErrorException(e.getMessage());
}
return null;
}
private void fillJSCardAnniversaries(VCard vcard, Card jsCard) {
int i = 1;
if (vcard.getBirthday() != null) {
it.cnr.iit.jscontact.tools.dto.Anniversary anniversary = it.cnr.iit.jscontact.tools.dto.Anniversary.builder()
.kind(AnniversaryKind.birth())
.date(toJSCardAnniversaryDate(vcard.getBirthday()))
.place(getValue(vcard.getBirthplace()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcard.getBirthday(), VCardParamEnum.PROP_ID, VCardParamEnum.CALSCALE))
.build();
jsCard.addAnniversary(getJSCardId(JSContactIdsProfile.IdType.ANNIVERSARY, i, "ANNIVERSARY-" + (i++), vcard.getBirthday().getParameter(VCardParamEnum.PROP_ID.getValue())), anniversary);
}
if (vcard.getDeathdate() != null) {
it.cnr.iit.jscontact.tools.dto.Anniversary anniversary = it.cnr.iit.jscontact.tools.dto.Anniversary.builder()
.kind(AnniversaryKind.death())
.date(toJSCardAnniversaryDate(vcard.getDeathdate()))
.place(getValue(vcard.getDeathplace()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcard.getDeathdate(), VCardParamEnum.PROP_ID, VCardParamEnum.CALSCALE))
.build();
jsCard.addAnniversary(getJSCardId(JSContactIdsProfile.IdType.ANNIVERSARY, i, "ANNIVERSARY-" + (i++), vcard.getDeathdate().getParameter(VCardParamEnum.PROP_ID.getValue())), anniversary);
}
if (vcard.getAnniversary() != null) {
it.cnr.iit.jscontact.tools.dto.Anniversary anniversary = it.cnr.iit.jscontact.tools.dto.Anniversary.builder()
.kind(AnniversaryKind.wedding())
.date(toJSCardAnniversaryDate(vcard.getAnniversary()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcard.getAnniversary(), VCardParamEnum.PROP_ID, VCardParamEnum.CALSCALE))
.build();
jsCard.addAnniversary(getJSCardId(JSContactIdsProfile.IdType.ANNIVERSARY, i, "ANNIVERSARY-" + (i++), vcard.getAnniversary().getParameter(VCardParamEnum.PROP_ID.getValue())), anniversary);
}
}
private static PersonalInfoLevelType toJSCardLevel(String vcardLevelParam) throws CardException {
try {
return PersonalInfoLevelType.builder().rfcValue(PersonalInfoLevelEnum.getEnum(vcardLevelParam)).build();
} catch (IllegalArgumentException e) {
throw new CardException("Unknown LEVEL value " + vcardLevelParam);
}
}
private void fillJSCardPersonalInfos(VCard vcard, Card jsCard) throws CardException {
int j = 0;
int i = 1;
for (Hobby hobby : vcard.getHobbies()) {
jsCard.addPersonalInfo(getJSCardId(JSContactIdsProfile.IdType.PERSONAL_INFO, j++, "HOBBY-" + (i++), hobby.getParameter(VCardParamEnum.PROP_ID.getValue()), PersonalInfoEnum.HOBBY),
PersonalInfo.builder()
.kind(PersonalInfoKind.builder().rfcValue(PersonalInfoEnum.HOBBY).build())
.value(getValue(hobby))
.level((hobby.getLevel() != null) ? toJSCardLevel(hobby.getLevel().getValue()) : null)
.listAs(hobby.getIndex())
.label(toJSCardLabel(hobby, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(hobby, VCardParamEnum.PROP_ID, VCardParamEnum.LEVEL, VCardParamEnum.INDEX))
.build()
);
}
i = 1;
for (Interest interest : vcard.getInterests()) {
jsCard.addPersonalInfo(getJSCardId(JSContactIdsProfile.IdType.PERSONAL_INFO, j++, "INTEREST-" + (i++), interest.getParameter(VCardParamEnum.PROP_ID.getValue()), PersonalInfoEnum.INTEREST),
PersonalInfo.builder()
.kind(PersonalInfoKind.builder().rfcValue(PersonalInfoEnum.INTEREST).build())
.value(getValue(interest))
.level((interest.getLevel() != null) ? toJSCardLevel(interest.getLevel().getValue()) : null)
.listAs(interest.getIndex())
.label(toJSCardLabel(interest, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(interest, VCardParamEnum.PROP_ID, VCardParamEnum.LEVEL, VCardParamEnum.INDEX))
.build()
);
}
i = 1;
for (Expertise expertise : vcard.getExpertise()) {
jsCard.addPersonalInfo(getJSCardId(JSContactIdsProfile.IdType.PERSONAL_INFO, j++, "EXPERTISE-" + (i++), expertise.getParameter(VCardParamEnum.PROP_ID.getValue()), PersonalInfoEnum.INTEREST),
PersonalInfo.builder()
.propId(expertise.getParameter(VCardParamEnum.PROP_ID.getValue()))
.kind(PersonalInfoKind.builder().rfcValue(PersonalInfoEnum.EXPERTISE).build())
.value(getValue(expertise))
.level((expertise.getLevel() != null) ? toJSCardLevel(expertise.getLevel().getValue()) : null)
.listAs(expertise.getIndex())
.label(toJSCardLabel(expertise, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(expertise, VCardParamEnum.PROP_ID, VCardParamEnum.LEVEL, VCardParamEnum.INDEX))
.build()
);
}
}
private void fillJSCardPreferredLanguages(VCard vcard, Card jsCard) {
int i = 1;
for (Language lang : vcard.getLanguages()) {
String vcardType = VCardUtils.getVCardParamValue(lang.getParameters(), VCardParamEnum.TYPE);
jsCard.addLanguagePref(getJSCardId(JSContactIdsProfile.IdType.LANGUAGE, i,"LANG-" + (i++), lang.getParameter(VCardParamEnum.PROP_ID.getValue())),
LanguagePref.builder()
.contexts(toJSCardContexts(vcardType))
.pref(lang.getPref())
.language(getValue(lang))
.vCardParams(VCardUtils.getVCardParamsOtherThan(lang, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF))
.build()
);
}
}
private static String getResourceExt(String resource) {
int index = resource.lastIndexOf('.');
return (index > 0) ? resource.substring(index + 1) : null;
}
private String toJSCardMediaType(String mediaTypeParamValue, String resource) {
if (mediaTypeParamValue != null)
return mediaTypeParamValue;
if (config.isSetAutoMediaType()) {
String ext = getResourceExt(resource);
return (ext != null) ? MimeTypeUtils.lookupMimeType(ext) : null;
}
return null;
}
private void fillJSCardPhones(VCard vcard, Card jsCard) {
int i = 1;
for (Telephone tel : vcard.getTelephoneNumbers()) {
String vcardType = VCardUtils.getVCardParamValue(tel.getParameters(), VCardParamEnum.TYPE);
Map contexts = toJSCardContexts(vcardType);
Map phoneFeatures = toJSCardPhoneFeatures(vcardType);
jsCard.addPhone(getJSCardId(JSContactIdsProfile.IdType.PHONE, i,"PHONE-" + (i++), tel.getParameter(VCardParamEnum.PROP_ID.getValue())), Phone.builder()
.number(getValue(tel))
.features(phoneFeatures)
.contexts(contexts)
.pref(tel.getPref())
.label(toJSCardLabel(tel, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(tel, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF))
.build()
);
}
}
private void fillJSCardEmails(VCard vcard, Card jsCard) {
int i = 1;
for (Email email : vcard.getEmails()) {
String emailAddress = getValue(email);
if (StringUtils.isNotEmpty(emailAddress)) {
String vcardType = VCardUtils.getVCardParamValue(email.getParameters(), VCardParamEnum.TYPE);
jsCard.addEmailAddress(getJSCardId(JSContactIdsProfile.IdType.EMAIL, i, "EMAIL-" + (i++), email.getParameter(VCardParamEnum.PROP_ID.getValue())), EmailAddress.builder()
.address(emailAddress)
.contexts(toJSCardContexts(vcardType))
.pref(email.getPref())
.label(toJSCardLabel(email, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(email, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF))
.build()
);
}
}
}
private void fillJSCardOnlineServices(VCard vcard, Card jsCard) {
String vcardType;
Map contexts;
int i = 1;
for (Impp impp : vcard.getImpps()) {
vcardType = VCardUtils.getVCardParamValue(impp.getParameters(), VCardParamEnum.TYPE);
contexts = toJSCardContexts(vcardType);
jsCard.addOnlineService(getJSCardId(JSContactIdsProfile.IdType.ONLINE_SERVICE, i,"OS-" + (i++), impp.getParameter(VCardParamEnum.PROP_ID.getValue())), OnlineService.builder()
.uri(getValue(impp))
.vCardName(VCardPropEnum.IMPP.getValue().toLowerCase())
.contexts(contexts)
.pref(impp.getPref())
.user(VCardUtils.getVCardParamValue(impp.getParameters(), VCardParamEnum.USERNAME))
.service(VCardUtils.getVCardParamValue(impp.getParameters(), VCardParamEnum.SERVICE_TYPE))
.label(toJSCardLabel(impp, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(impp, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.SERVICE_TYPE, VCardParamEnum.USERNAME))
.build()
);
}
}
private void fillJSCardMedia(VCard vcard, Card jsCard) {
int i = 1;
for (Photo photo : vcard.getPhotos())
addJSCardMediaResource(photo, jsCard, MediaKind.photo(), i++, vcard.getExtendedProperties());
i = 1;
for (Sound sound : vcard.getSounds())
addJSCardMediaResource(sound, jsCard, MediaKind.sound(), i++, vcard.getExtendedProperties());
i = 1;
for (Logo logo : vcard.getLogos())
addJSCardMediaResource(logo, jsCard, MediaKind.logo(), i++, vcard.getExtendedProperties());
}
private void fillJSCardCryptoKeys(VCard vcard, Card jsCard) {
int i = 1;
for (Key key : vcard.getKeys())
addJSCardCryptoResource(key, jsCard, i++, vcard.getExtendedProperties());
}
private void fillJSCardDirectories(VCard vcard, Card jsCard) {
int i = 1;
for (Source source : vcard.getSources())
addJSCardDirectoryResource(source, jsCard, DirectoryKind.entry(), i++, vcard.getExtendedProperties());
i = 1;
for (OrgDirectory od : vcard.getOrgDirectories())
addJSCardDirectoryResource(jsCard, toJSCardDirectoryResource(od, DirectoryKind.directory(), vcard.getExtendedProperties()), i++);
}
private void fillJSCardCalendars(VCard vcard, Card jsCard) {
int i = 1;
for (CalendarUri calendarUri : vcard.getCalendarUris())
addJSCardCalendarResource(calendarUri, jsCard, CalendarKind.calendar(), i++, vcard.getExtendedProperties());
i = 1;
for (FreeBusyUrl fburl : vcard.getFbUrls())
addJSCardCalendarResource(fburl, jsCard, CalendarKind.freeBusy(), i++, vcard.getExtendedProperties());
}
private void fillJSCardLinks(VCard vcard, Card jsCard) {
int i = 1;
for (Url url : vcard.getUrls())
addJSCardLinkResource(url, jsCard, null, i++, vcard.getExtendedProperties());
List contactUris = VCardUtils.getRawProperties(vcard, "CONTACT-URI");
i = 1;
for (RawProperty contactUri : contactUris) {
UriProperty uriProperty = new UriProperty(getValue(contactUri));
uriProperty.setParameters(contactUri.getParameters());
addJSCardLinkResource(uriProperty, jsCard, LinkKind.contact(), i++, vcard.getExtendedProperties());
}
}
private void fillJSCardSchedulingAddresses(VCard vcard, Card jsCard) {
int i = 1;
for (CalendarRequestUri calendarRequestUri : vcard.getCalendarRequestUris()) {
String vcardType = VCardUtils.getVCardParamValue(calendarRequestUri.getParameters(), VCardParamEnum.TYPE);
Map contexts = toJSCardContexts(vcardType);
jsCard.addSchedulingAddress(getJSCardId(JSContactIdsProfile.IdType.SCHEDULING, i, "SCHEDULING-" + (i++), calendarRequestUri.getParameter(VCardParamEnum.PROP_ID.getValue())),
SchedulingAddress.builder()
.propId(calendarRequestUri.getParameter(VCardParamEnum.PROP_ID.getValue()))
.uri(calendarRequestUri.getValue())
.contexts(contexts)
.pref(calendarRequestUri.getPref())
.label(toJSCardLabel(calendarRequestUri, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(calendarRequestUri, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF))
.build());
}
}
private static String findJSCardOrganizationIdByGroup(Map jscardOrganizations, String vcardTitleGroup) {
if (vcardTitleGroup == null)
return null;
if (jscardOrganizations == null || jscardOrganizations.isEmpty())
return null;
for (Map.Entry entry : jscardOrganizations.entrySet()) {
if (entry.getValue().getGroup()!=null && entry.getValue().getGroup().equals(vcardTitleGroup))
return entry.getKey();
}
return null;
}
private it.cnr.iit.jscontact.tools.dto.Title toJSCardTitle(Title vcardTitle, VCard vcard, Card jsCard) {
return it.cnr.iit.jscontact.tools.dto.Title.builder()
.name(vcardTitle.getValue())
.kind(TitleKind.title())
.organizationId(findJSCardOrganizationIdByGroup(jsCard.getOrganizations(), vcardTitle.getGroup()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardTitle, VCardParamEnum.PROP_ID, VCardParamEnum.ALTID, VCardParamEnum.LANGUAGE))
.build();
}
private it.cnr.iit.jscontact.tools.dto.Title toJSCardTitle(Role vcardRole, VCard vcard, Card jsCard) {
return it.cnr.iit.jscontact.tools.dto.Title.builder()
.name(vcardRole.getValue())
.kind(TitleKind.role())
.organizationId(findJSCardOrganizationIdByGroup(jsCard.getOrganizations(), vcardRole.getGroup()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardRole, VCardParamEnum.PROP_ID, VCardParamEnum.ALTID, VCardParamEnum.LANGUAGE))
.build();
}
private void fillJSCardTitlesfromVCardTitles(VCard vcard, Card jsCard) {
if (vcard.getTitles() == null || vcard.getTitles().isEmpty())
return;
List titles = vcard.getTitles();
titles.sort(vCardPropertiesAltidComparator);
int i = 1;
String lastAltid = null;
String lastMapId = null;
for (Title vcardTitle : titles) {
if (vcardTitle.getAltId() == null || lastAltid == null || !vcardTitle.getAltId().equals(lastAltid)) {
String propId = vcardTitle.getParameter(VCardParamEnum.PROP_ID.getValue());
String id = getJSCardId(JSContactIdsProfile.IdType.TITLE, i, "TITLE-" + (i ++), propId);
jsCard.addTitle(id, toJSCardTitle(vcardTitle, vcard, jsCard));
lastAltid = vcardTitle.getAltId();
lastMapId = id;
} else {
jsCard.addLocalization(vcardTitle.getLanguage(), "titles/" + lastMapId, mapper.convertValue(toJSCardTitle(vcardTitle, vcard, jsCard), JsonNode.class));
}
}
}
private void fillJSCardTitlesfromVCardRoles(VCard vcard, Card jsCard) {
if (vcard.getRoles() == null || vcard.getRoles().isEmpty())
return;
List roles = vcard.getRoles();
roles.sort(vCardPropertiesAltidComparator);
int i = (jsCard.getTitles() != null) ? jsCard.getTitles().size() + 1 : 1;
String lastAltid = null;
String lastMapId = null;
for (Role vcardRole : roles) {
if (vcardRole.getAltId() == null || lastAltid == null || !vcardRole.getAltId().equals(lastAltid)) {
String propId = vcardRole.getParameter(VCardParamEnum.PROP_ID.getValue());
String id = getJSCardId(JSContactIdsProfile.IdType.TITLE, i, "TITLE-" + (i ++), propId);
jsCard.addTitle(id, toJSCardTitle(vcardRole, vcard, jsCard));
lastAltid = vcardRole.getAltId();
lastMapId = id;
} else {
jsCard.addLocalization(vcardRole.getLanguage(), "titles/" + lastMapId, mapper.convertValue(toJSCardTitle(vcardRole, vcard, jsCard), JsonNode.class));
}
}
}
private it.cnr.iit.jscontact.tools.dto.Organization toJSCardOrganization(Organization vcardOrg, VCard vcard) {
List unitNameList;
List unitSortAsList = null;
String name;
String orgSortAs = null;
if (vcardOrg.getValues().size() > 1 ) {
name = vcardOrg.getValues().get(0);
unitNameList = vcardOrg.getValues().subList(1,vcardOrg.getValues().size());
if (vcardOrg.getSortAs()!=null && !vcardOrg.getSortAs().isEmpty()) {
orgSortAs = vcardOrg.getSortAs().get(0);
unitSortAsList = vcardOrg.getSortAs().subList(1,vcardOrg.getSortAs().size());
}
} else { // ezvcard put all the organization components separated by semicolon into vcardOrg.getValues().get(0) !!
String[] nameSubItems = vcardOrg.getValues().get(0).split(DelimiterUtils.SEMICOLON_ARRAY_DELIMITER);
name = nameSubItems[0];
unitNameList = Arrays.asList(nameSubItems).subList(1,nameSubItems.length);
if (vcardOrg.getSortAs()!=null && !vcardOrg.getSortAs().isEmpty()) {
String[] sortAsSubItems = vcardOrg.getSortAs().get(0).split(DelimiterUtils.COMMA_ARRAY_DELIMITER);
orgSortAs = sortAsSubItems[0];
unitSortAsList = Arrays.asList(sortAsSubItems).subList(1,sortAsSubItems.length);
}
}
OrgUnit[] orgUnits = null;
if (unitNameList!=null && unitNameList.size()>0) {
orgUnits = new OrgUnit[unitNameList.size()];
for (int i=0; i < unitNameList.size(); i++) {
String sortAs = (unitSortAsList!=null && unitSortAsList.size()>0) ? unitSortAsList.get(i) : null;
orgUnits[i] = OrgUnit.builder().name(unitNameList.get(i)).sortAs(sortAs).build();
}
}
return it.cnr.iit.jscontact.tools.dto.Organization.builder()
.name((!name.isEmpty()) ? name : null)
.units(orgUnits)
.contexts(toJSCardContexts(vcardOrg.getType()))
.sortAs(orgSortAs)
.group(vcardOrg.getGroup())
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardOrg, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.SORT_AS, VCardParamEnum.ALTID, VCardParamEnum.GROUP))
.build();
}
private void fillJSCardOrganizations(VCard vcard, Card jsCard) {
if (vcard.getOrganizations() == null || vcard.getOrganizations().isEmpty())
return;
List vcardOrgs = vcard.getOrganizations();
vcardOrgs.sort(vCardPropertiesAltidComparator);
int i = 1;
String lastAltid = null;
String lastMapId = null;
for (ezvcard.property.Organization vcardOrg : vcardOrgs) {
if (vcardOrg.getAltId() == null || lastAltid == null || !vcardOrg.getAltId().equals(lastAltid)) {
String propId = vcardOrg.getParameter(VCardParamEnum.PROP_ID.getValue());
String id = getJSCardId(JSContactIdsProfile.IdType.ORGANIZATION, i, "ORG-" + (i++), propId);
jsCard.addOrganization(id, toJSCardOrganization(vcardOrg, vcard));
lastAltid = vcardOrg.getAltId();
lastMapId = id;
} else {
jsCard.addLocalization(vcardOrg.getLanguage(), "organizations/" + lastMapId, mapper.convertValue(toJSCardOrganization(vcardOrg, vcard), JsonNode.class));
}
}
}
private Note toJSCardNote(ezvcard.property.Note vcardNote, VCard vcard) {
String authorUri = vcardNote.getParameter(VCardParamEnum.AUTHOR.getValue());
String authorName = vcardNote.getParameter(VCardParamEnum.AUTHOR_NAME.getValue());
String created = vcardNote.getParameter(VCardParamEnum.CREATED.getValue());
return Note.builder()
.note(vcardNote.getValue())
.author((authorName != null || authorUri != null) ? Author.builder().name(authorName).uri(authorUri).build() : null)
.created((created != null) ? DateUtils.toCalendar(created) : null)
.vCardParams(VCardUtils.getVCardParamsOtherThan(vcardNote, VCardParamEnum.PROP_ID, VCardParamEnum.ALTID, VCardParamEnum.AUTHOR, VCardParamEnum.AUTHOR_NAME, VCardParamEnum.CREATED))
.build();
}
private void fillJSCardNotes(VCard vcard, Card jsCard) {
if (vcard.getNotes() == null || vcard.getNotes().isEmpty())
return;
List vcardNotes = vcard.getNotes();
vcardNotes.sort(vCardPropertiesAltidComparator);
int i = 1;
String lastAltid = null;
String lastMapId = null;
for (ezvcard.property.Note vcardNote : vcardNotes) {
if (vcardNote.getAltId() == null || lastAltid == null || !vcardNote.getAltId().equals(lastAltid)) {
String propId = vcardNote.getParameter(VCardParamEnum.PROP_ID.getValue());
String id = getJSCardId(JSContactIdsProfile.IdType.NOTE, i, "NOTE-" + (i++), propId);
jsCard.addNote(id, toJSCardNote(vcardNote, vcard));
lastAltid = vcardNote.getAltId();
lastMapId = id;
} else {
jsCard.addLocalization(vcardNote.getLanguage(), "notes/" + lastMapId, mapper.convertValue(toJSCardNote(vcardNote, vcard), JsonNode.class));
}
}
}
private void fillJSCardKeywords(VCard vcard, Card jsCard) {
List categoriesList = vcard.getCategoriesList();
categoriesList.sort(vCardPropertiesPrefComparator);
for (Categories categories : categoriesList)
jsCard.addKeywords(categories.getValues().toArray(new String[0]));
}
private static void fillJSCardRelations(VCard vcard, Card jsCard) {
for (Related related : vcard.getRelations()) {
if (related.getTypes().isEmpty())
jsCard.addRelation(getValue(related), null);
else {
for (RelatedType type : related.getTypes())
jsCard.addRelation(getValue(related), RelationType.rfcRelation(RelationEnum.getEnum(type.getValue())));
}
}
}
//Fill JSContact properties mapping the VCard properties defined in RFC9554
private void fillJSCardPropsFromVCardJSContactExtensions(VCard vcard, Card jsCard) {
int i = 1;
String lastAltid = null;
String lastMapid = null;
for (RawProperty extension : vcard.getExtendedProperties()) {
String language = extension.getParameter(VCardParamEnum.LANGUAGE.getValue());
String vcardPref = extension.getParameter(VCardParamEnum.PREF.getValue());
Integer pref;
try {
pref = Integer.parseInt(vcardPref);
} catch (Exception e) {
pref = null;
}
String vcardType = extension.getParameter(VCardParamEnum.TYPE.getValue());
Map contexts = toJSCardContexts(vcardType);
String jsonPointer = fakeExtensionsMapping.get(extension.getPropertyName().toLowerCase());
if (jsonPointer == null)
continue; //vcard extension already handled elsewhere
if (extension.getPropertyName().equalsIgnoreCase(VCardPropEnum.LANGUAGE.getValue()))
continue; // has already been set
else if (extension.getPropertyName().equalsIgnoreCase(VCardPropEnum.CREATED.getValue()))
jsCard.setCreated(DateUtils.toCalendar(extension.getValue()));
else if (extension.getPropertyName().equalsIgnoreCase(VCardPropEnum.GRAMGENDER.getValue())) {
GrammaticalGenderType gender = GrammaticalGenderType.getEnum(extension.getValue().toLowerCase());
if (language == null ||
(jsCard.getLanguage() != null && jsCard.getLanguage().equalsIgnoreCase(language)) ||
(config.getDefaultLanguage() !=null && config.getDefaultLanguage().equalsIgnoreCase(language))
) {
if (jsCard.getSpeakToAs() != null)
jsCard.getSpeakToAs().setGrammaticalGender(gender);
else
jsCard.setSpeakToAs(SpeakToAs.builder().grammaticalGender(gender).build());
} else {
jsCard.addLocalization(language, jsonPointer, JsonNodeUtils.textNode(gender.getValue()));
}
}
else if (extension.getPropertyName().equalsIgnoreCase(VCardPropEnum.PRONOUNS.getValue())) {
Pronouns pronouns = Pronouns.builder()
.pronouns(extension.getValue())
.contexts(contexts)
.pref(pref)
.vCardParams(VCardUtils.getVCardParamsOtherThan(extension, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.ALTID, VCardParamEnum.LANGUAGE))
.build();
String altid = extension.getParameter(VCardParamEnum.ALTID.getValue());
if (altid == null || lastAltid == null || !altid.equals(lastAltid)) {
String propId = extension.getParameter(VCardParamEnum.PROP_ID.getValue());
String id = getJSCardId(JSContactIdsProfile.IdType.PRONOUNS, i, "PRONOUNS-" + (i++), propId);
lastAltid = altid;
lastMapid = (propId!=null) ? propId : id;
if (language == null ||
(jsCard.getLanguage() != null && jsCard.getLanguage().equalsIgnoreCase(language)) ||
(config.getDefaultLanguage() != null && config.getDefaultLanguage().equalsIgnoreCase(language))
) {
if (jsCard.getSpeakToAs() != null) {
jsCard.getSpeakToAs().addPronouns(id, pronouns);
} else {
jsCard.setSpeakToAs(SpeakToAs.builder().pronouns(new HashMap() {{
put(id, pronouns);
}}).build());
}
}
} else {
jsonPointer = String.format("%s/%s", jsonPointer, lastMapid);
jsCard.addLocalization(language, jsonPointer, mapper.convertValue(pronouns, JsonNode.class));
}
}
else if (extension.getPropertyName().equalsIgnoreCase(VCardPropEnum.SOCIALPROFILE.getValue())) {
i = (jsCard.getOnlineServices() != null) ? jsCard.getOnlineServices().size() + 1 : 1;
vcardType = VCardUtils.getVCardParamValue(extension.getParameters(), VCardParamEnum.TYPE);
contexts = toJSCardContexts(vcardType);
OnlineService ol = OnlineService.builder()
.user((extension.getDataType() == VCardDataType.TEXT) ? extension.getValue() : null)
.uri((extension.getDataType() == null || extension.getDataType() == VCardDataType.URI) ? extension.getValue() : null)
.service(extension.getParameter(VCardParamEnum.SERVICE_TYPE.getValue()))
.contexts(contexts)
.pref(toJSCardPref(extension.getParameter(VCardParamEnum.PREF.getValue())))
.label(toJSCardLabel(extension, vcard.getExtendedProperties()))
.vCardParams(VCardUtils.getVCardParamsOtherThan(extension, VCardParamEnum.PROP_ID, VCardParamEnum.TYPE, VCardParamEnum.PREF, VCardParamEnum.SERVICE_TYPE, VCardParamEnum.USERNAME))
.build();
if ((extension.getDataType() == null || extension.getDataType() == VCardDataType.URI) && extension.getParameter(VCardParamEnum.USERNAME.getValue()) != null)
ol.setUser(extension.getParameter(VCardParamEnum.USERNAME.getValue()));
jsCard.addOnlineService(getJSCardId(JSContactIdsProfile.IdType.ONLINE_SERVICE, i,"OS-" + (i++), extension.getParameter(VCardParamEnum.PROP_ID.getValue())), ol);
}
}
}
private void fillJSCardPropsFromVCardExtensions(VCard vcard, Card jsCard) {
for (RawProperty extension : vcard.getExtendedProperties()) {
if (!fakeExtensionsMapping.containsKey(extension.getPropertyName()) &&
!fakeExtensionsMapping.containsKey(extension.getPropertyName().toLowerCase())) {
Map parameters = new HashMap<>();
if (extension.getGroup()!=null)
parameters.put(VCardParamEnum.GROUP.toString().toLowerCase(),extension.getGroup());
parameters.putAll(VCardUtils.getVCardPropParams(extension.getParameters()));
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(extension.getPropertyName().toLowerCase()))
.parameters(parameters)
.type(extension.getDataType())
.value(extension.getValue())
.build());
}
}
}
private void fillJSPropsFromJSCardExtensionsInVCard(VCard vcard, Card jsCard) throws CardException {
String path = null;
Object value;
String extensionName;
try {
for (RawProperty extension : vcard.getExtendedProperties()) {
if (extension.getPropertyName().equalsIgnoreCase(VCardPropEnum.JSPROP.getValue())) {
path = extension.getParameter(VCardParamEnum.JSPTR.getValue());
value = JSPropUtils.toJSContactObject(extension.getValue());
if (!path.contains(DelimiterUtils.SLASH_DELIMITER)) {
jsCard.addExtension(path, value);
} else {
String[] pathItems = path.split(DelimiterUtils.SLASH_DELIMITER);
extensionName = pathItems[pathItems.length-1];
List list = Arrays.asList(pathItems);
jsCard.addExtension(list.subList(0, pathItems.length-1),extensionName.replaceAll(DelimiterUtils.SLASH_DELIMITER_IN_JSON_POINTER,DelimiterUtils.SLASH_DELIMITER), value);
}
}
}
} catch(Exception e) {
throw new CardException(String.format("Unable to convert JSPROP property with path: %s", path));
}
}
private static void fillVCardUnmatchedProps(VCard vcard, Card jsCard) {
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(VCardPropEnum.VERSION.getValue().toLowerCase()))
.type(VCardDataType.TEXT)
.value(vcard.getVersion().getVersion())
.build());
if (vcard.getClientPidMaps()!=null) {
for (ClientPidMap pidmap : vcard.getClientPidMaps())
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(VCardPropEnum.CLIENTPIDMAP.getValue().toLowerCase()))
.parameters(VCardUtils.getVCardPropParams(pidmap.getParameters()))
.type(VCardDataType.TEXT)
.value(String.format("%d,%s",pidmap.getPid(), pidmap.getUri()))
.build());
}
if (vcard.getXmls()!=null) {
for (Xml xml : vcard.getXmls())
jsCard.addVCardProp(VCardProp.builder()
.name(V_Extension.toV_Extension(VCardPropEnum.XML.getValue().toLowerCase()))
.parameters(VCardUtils.getVCardPropParams(xml.getParameters()))
.type(VCardDataType.TEXT)
.value(xml.getValue().getTextContent())
.build());
}
}
private static java.util.Calendar toJSCardUpdated(Revision rev) {
if (rev == null)
return null;
return rev.getCalendar();
}
private static KindType toJSCardKind(ezvcard.property.Kind kind) {
if (kind == null)
return null;
try {
return KindType.builder().rfcValue(KindEnum.getEnum(getValue(kind))).build();
} catch (IllegalArgumentException e) {
return KindType.builder().extValue(V_Extension.toV_Extension(getValue(kind))).build();
}
}
private Card convert(VCard vCard) throws CardException {
Card jsCard;
String uid;
if (vCard.getUid()!=null)
uid = vCard.getUid().getValue();
else
uid = UuidUtils.getRandomV4UuidPrefixedByNamespace();
jsCard = Card.builder().uid(uid).build();
jsCard.setKind(toJSCardKind(vCard.getKind()));
jsCard.setProdId(getValue(vCard.getProductId()));
jsCard.setUpdated(toJSCardUpdated(vCard.getRevision()));
RawProperty language = vCard.getExtendedProperty(VCardPropEnum.LANGUAGE.getValue());
jsCard.setLanguage((language!=null) ? language.getValue() : config.getDefaultLanguage());
vCardPropertiesAltidComparator = VCardPropertiesAltidComparator.builder().defaultLanguage(jsCard.getLanguage()).build();
vCardPropertiesPrefComparator = VCardPropertiesPrefComparator.builder().build();
fillJSCardSpeakToAsOrGender(vCard, jsCard);
fillJSCardMembers(vCard, jsCard);
fillJSCardFullName(vCard, jsCard);
fillJSCardNames(vCard, jsCard);
fillJSCardNickNames(vCard, jsCard);
fillJSCardAddresses(vCard, jsCard);
fillJSCardAnniversaries(vCard, jsCard);
fillJSCardPersonalInfos(vCard, jsCard);
fillJSCardPreferredLanguages(vCard, jsCard);
fillJSCardPhones(vCard, jsCard);
fillJSCardEmails(vCard, jsCard);
fillJSCardSchedulingAddresses(vCard,jsCard);
fillJSCardOnlineServices(vCard, jsCard);
fillJSCardCalendars(vCard, jsCard);
fillJSCardCryptoKeys(vCard, jsCard);
fillJSCardLinks(vCard, jsCard);
fillJSCardMedia(vCard, jsCard);
fillJSCardDirectories(vCard, jsCard);
fillJSCardOrganizations(vCard, jsCard);
fillJSCardTitlesfromVCardTitles(vCard, jsCard);
fillJSCardTitlesfromVCardRoles(vCard, jsCard);
fillJSCardKeywords(vCard, jsCard);
fillJSCardNotes(vCard, jsCard);
fillJSCardRelations(vCard, jsCard);
fillJSCardPropsFromVCardJSContactExtensions(vCard, jsCard);
if (customTimeZones.size() > 0)
jsCard.setCustomTimeZones(customTimeZones);
fillVCardUnmatchedProps(vCard, jsCard);
fillJSCardPropsFromVCardExtensions(vCard, jsCard);
fillJSPropsFromJSCardExtensionsInVCard(vCard, jsCard);
return jsCard;
}
private boolean warningIsAboutNonPrintableCharacters(String warning) {
if (warning.contains("Parameter values may contain printable characters, with the exception of: [ \\n \\r \" ]"))
return true;
return false;
}
/**
* Converts a list of vCard v4.0 instances [RFC6350] into a list of Card objects.
* JSContact is defined in [RFC9553].
* JSContact extensions to vCard are defined in [RFC9554]
* Conversion rules are defined in [RFC9555].
*
* @param vCards a list of instances of the ez-vcard library VCard class [ez-vcard]
* @return a list of Card objects
* @throws CardException if one of the vCard instances is not v4.0 compliant
* @see RFC9553
* @see RFC9554
* @see RFC9555
* @see ez-vcard
*/
public List convert(VCard... vCards) throws CardException {
List jsCards = new ArrayList<>();
for (VCard vCard : vCards) {
if (config.isValidateCard()) {
ValidationWarnings warnings = vCard.validate(VCardVersion.V4_0);
if (!warnings.isEmpty() && !warningIsAboutNonPrintableCharacters(warnings.toString()))
throw new CardException(warnings.toString());
}
jsCards.add(convert(vCard));
}
return jsCards;
}
}