///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition 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 General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.plugins.crm; import java.sql.Date; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.StringTokenizer; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.commons.lang.StringUtils; import org.hibernate.annotations.IndexColumn; import org.hibernate.search.annotations.DateBridge; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.Index; import org.hibernate.search.annotations.Indexed; import org.hibernate.search.annotations.IndexedEmbedded; import org.hibernate.search.annotations.Resolution; import org.hibernate.search.annotations.Store; import org.projectforge.address.AddressStatus; import org.projectforge.address.ContactStatus; import org.projectforge.address.FormOfAddress; import org.projectforge.address.InstantMessagingType; import org.projectforge.common.LabelValueBean; import org.projectforge.common.StringHelper; import org.projectforge.core.DefaultBaseDO; import org.projectforge.core.PFPersistancyBehavior; import org.projectforge.core.PropertyInfo; import org.projectforge.task.TaskDO; import org.projectforge.user.PFUserContext; /** * @author Werner Feder (werner.feder@t-online.de) * */ @Entity @Indexed @Table(name = "T_CONTACT") public class ContactDO extends DefaultBaseDO { private static final long serialVersionUID = -1177059694759828682L; private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(ContactDO.class); private TaskDO task; @PropertyInfo(i18nKey = "name") @Field(index = Index.TOKENIZED, store = Store.NO) private String name; // 255 not null @PropertyInfo(i18nKey = "firstName") @Field(index = Index.TOKENIZED, store = Store.NO) private String firstName; // 255 @PropertyInfo(i18nKey = "form") @Field(index = Index.TOKENIZED, store = Store.NO) private FormOfAddress form; @PropertyInfo(i18nKey = "title") @Field(index = Index.TOKENIZED, store = Store.NO) private String title; // 255 @PropertyInfo(i18nKey = "birthday") @Field(index = Index.UN_TOKENIZED) @DateBridge(resolution = Resolution.DAY) private Date birthday; @PropertyInfo(i18nKey = "contact.imValues") @Field(index = Index.TOKENIZED, store = Store.NO) private String socialMediaValues; @PropertyInfo(i18nKey = "contact.emailValues") @Field(index = Index.TOKENIZED, store = Store.NO) private String emailValues; @PropertyInfo(i18nKey = "contact.phoneValues") @Field(index = Index.TOKENIZED, store = Store.NO) private String phoneValues; @PropertyInfo(i18nKey = "contact.contacts") @PFPersistancyBehavior(autoUpdateCollectionEntries = true) @IndexedEmbedded(depth = 1) private Set<ContactEntryDO> contactEntries = null; private ContactStatus contactStatus = ContactStatus.ACTIVE; private AddressStatus addressStatus = AddressStatus.UPTODATE; @Field(index = Index.TOKENIZED, store = Store.NO) private String publicKey; // 7000 @Field(index = Index.TOKENIZED, store = Store.NO) private String fingerprint; // 255 private Locale communicationLanguage; @Field(index = Index.TOKENIZED, store = Store.NO) private String website; // 255 @Field(index = Index.TOKENIZED, store = Store.NO) private String organization; // 255 @Field(index = Index.TOKENIZED, store = Store.NO) private String division; // 255 @Field(index = Index.TOKENIZED, store = Store.NO) private String positionText; // 255 @Field(index = Index.TOKENIZED, store = Store.NO) private String comment; // 5000; // @FieldBridge(impl = HibernateSearchInstantMessagingBridge.class) // @Field(index = Index.TOKENIZED, store = Store.NO) // TODO: Prepared for hibernate search. private List<LabelValueBean<InstantMessagingType, String>> socialMedia = null; /** * List of instant messaging contacts in the form of a property file: {skype=hugo.mustermann\naim=12345dse}. Only for data base access, * use getter an setter of instant messaging instead. * @return */ // @Column(name = "instant_messaging", length = 4000) @Transient // TODO: Prepared for data base persistence. public String getSocialMedia4DB() { return getSocialMediaAsString(socialMedia); } public void setSocialMedia4DB(final String properties) { if (StringUtils.isBlank(properties) == true) { this.socialMedia = null; } else { final StringTokenizer tokenizer = new StringTokenizer(properties, "\n"); while (tokenizer.hasMoreTokens() == true) { final String line = tokenizer.nextToken(); if (StringUtils.isBlank(line) == true) { continue; } final int idx = line.indexOf('='); if (idx <= 0) { log.error("Wrong social media entry format in data base: " + line); continue; } String label = line.substring(0, idx); final String value = ""; if (idx < line.length()) { label = line.substring(idx); } InstantMessagingType type = null; try { type = InstantMessagingType.get(label); } catch (final Exception ex) { log.error("Ignoring unknown social media entry: " + label, ex); continue; } setSocialMedia(type, value); } } } /** * Instant messaging settings as property file. * @return */ @Transient public List<LabelValueBean<InstantMessagingType, String>> getSocialMedia() { return socialMedia; } public void setSocialMedia(final InstantMessagingType type, final String value) { if (this.socialMedia == null) { this.socialMedia = new ArrayList<LabelValueBean<InstantMessagingType, String>>(); } else { for (final LabelValueBean<InstantMessagingType, String> entry : this.socialMedia) { if (entry.getLabel() == type) { // Entry found; if (StringUtils.isBlank(value) == true) { // Remove this entry: this.socialMedia.remove(entry); } else { // Modify existing entry: entry.setValue(value); } return; } } } this.socialMedia.add(new LabelValueBean<InstantMessagingType, String>(type, value)); } /** * Used for representation in the data base and for hibernate search (lucene). */ static String getSocialMediaAsString(final List<LabelValueBean<InstantMessagingType, String>> list) { if (list == null || list.size() == 0) { return null; } final StringBuffer buf = new StringBuffer(); boolean first = true; for (final LabelValueBean<InstantMessagingType, String> lv : list) { if (StringUtils.isBlank(lv.getValue()) == true) { continue; // Do not write empty entries. } if (first == true) first = false; else buf.append("\n"); buf.append(lv.getLabel()).append("=").append(lv.getValue()); } if (first == true) { return null; // No entry was written. } return buf.toString(); } /** * Get the contact entries for this object. */ @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "contact") @IndexColumn(name = "number", base = 1) public Set<ContactEntryDO> getContactEntries() { return this.contactEntries; } /** * @param number * @return ContactEntryDO with given position number or null (iterates through the list of contacts and compares the number), if not * exist. */ public ContactEntryDO getContactEntry(final short number) { if (contactEntries == null) { return null; } for (final ContactEntryDO contact : this.contactEntries) { if (contact.getNumber() == number) { return contact; } } return null; } public ContactDO setContactEntries(final Set<ContactEntryDO> contactEntries) { this.contactEntries = contactEntries; return this; } public ContactDO addContactEntry(final ContactEntryDO contactEntry) { ensureAndGetContactEntries(); short number = 1; for (final ContactEntryDO pos : contactEntries) { if (pos.getNumber() >= number) { number = pos.getNumber(); number++; } } contactEntry.setNumber(number); contactEntry.setContact(this); this.contactEntries.add(contactEntry); return this; } public Set<ContactEntryDO> ensureAndGetContactEntries() { if (this.contactEntries == null) { setContactEntries(new LinkedHashSet<ContactEntryDO>()); } return getContactEntries(); } @Column public Date getBirthday() { return birthday; } public ContactDO setBirthday(final Date birthday) { this.birthday = birthday; return this; } @Column(name = "first_name", length = 255) public String getFirstName() { return firstName; } public ContactDO setFirstName(final String firstName) { this.firstName = firstName; return this; } @Transient public String getFullName() { return StringHelper.listToString(", ", name, firstName); } @Transient public String getFullNameWithTitleAndForm() { final StringBuffer buf = new StringBuffer(); if (getForm() != null) { buf.append(PFUserContext.getLocalizedString(getForm().getI18nKey())).append(" "); } if (getTitle() != null) { buf.append(getTitle()).append(" "); } if (getFirstName() != null) { buf.append(getFirstName()).append(" "); } if (getName() != null) { buf.append(getName()); } return buf.toString(); } @Column(length = 255, nullable = false) public String getName() { return name; } public ContactDO setName(final String name) { this.name = name; return this; } @Enumerated(EnumType.STRING) @Column(name = "form", length = 10) public FormOfAddress getForm() { return form; } public ContactDO setForm(final FormOfAddress form) { this.form = form; return this; } /** * Not used as object due to performance reasons. * @return */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "task_id") public TaskDO getTask() { return task; } public void setTask(final TaskDO task) { this.task = task; } @Transient public Integer getTaskId() { if (this.task == null) return null; return task.getId(); } @Column(length = 255) public String getTitle() { return title; } public ContactDO setTitle(final String title) { this.title = title; return this; } @Column public String getSocialMediaValues() { return socialMediaValues; } public ContactDO setSocialMediaValues(final String socialMediaValues) { this.socialMediaValues = socialMediaValues; return this; } @Column public String getEmailValues() { return emailValues; } public ContactDO setEmailValues(final String emailValues) { this.emailValues = emailValues; return this; } @Column public String getPhoneValues() { return phoneValues; } public ContactDO setPhoneValues(final String phoneValues) { this.phoneValues = phoneValues; return this; } @Enumerated(EnumType.STRING) @Column(name = "contact_status", length = 20, nullable = false) public ContactStatus getContactStatus() { return contactStatus; } public ContactDO setContactStatus(final ContactStatus contactStatus) { this.contactStatus = contactStatus; return this; } @Enumerated(EnumType.STRING) @Column(name = "address_status", length = 20, nullable = false) public AddressStatus getAddressStatus() { return addressStatus; } public ContactDO setAddressStatus(final AddressStatus addressStatus) { this.addressStatus = addressStatus; return this; } @Column(name = "public_key", length = 7000) public String getPublicKey() { return publicKey; } public ContactDO setPublicKey(final String publicKey) { this.publicKey = publicKey; return this; } @Column(length = 255) public String getFingerprint() { return fingerprint; } public ContactDO setFingerprint(final String fingerprint) { this.fingerprint = fingerprint; return this; } /** * @return The communication will take place in this language. */ @Column(name = "communication_language") public Locale getCommunicationLanguage() { return communicationLanguage; } public ContactDO setCommunicationLanguage(final Locale communicationLanguage) { this.communicationLanguage = communicationLanguage; return this; } @Column(length = 255) public String getWebsite() { return website; } public ContactDO setWebsite(final String website) { this.website = website; return this; } @Column(length = 255) public String getOrganization() { return organization; } public ContactDO setOrganization(final String organization) { this.organization = organization; return this; } @Column(name = "comment", length = 5000) public String getComment() { return comment; } public ContactDO setComment(final String comment) { this.comment = comment; return this; } @Column(length = 255) public String getPositionText() { return positionText; } public ContactDO setPositionText(final String positionText) { this.positionText = positionText; return this; } @Column(length = 255) public String getDivision() { return division; } public ContactDO setDivision(final String division) { this.division = division; return this; } }