/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.service.contactsource; import java.util.*; import org.jitsi.util.*; import net.java.sip.communicator.service.protocol.*; /** * The <tt>ContactDetail</tt> is a detail of a <tt>SourceContact</tt> * corresponding to a specific address (phone number, email, identifier, etc.), * which defines the different possible types of communication and the preferred * <tt>ProtocolProviderService</tt>s to go through. * * <p> * Example: A <tt>ContactDetail</tt> could define two types of communication, * by declaring two supported operation sets * <tt>OperationSetBasicInstantMessaging</tt> to indicate the support of instant * messages and <tt>OperationSetBasicTelephony</tt> to indicate the support of * telephony. It may then specify a certain <tt>ProtocolProviderService</tt> to * go through only for instant messages. This would mean that for sending an * instant message to this <tt>ContactDetail</tt> one should obtain an instance * of the <tt>OperationSetBasicInstantMessaging</tt> from the specific * <tt>ProtocolProviderService</tt> and send a message through it. However when * no provider is specified for telephony operations, then one should try to * obtain all currently available telephony providers and let the user make * their choice. * * @author Yana Stamcheva * @author Lyubomir Marinov */ public class ContactDetail { /** * Defines all possible categories for a <tt>ContactDetail</tt>. */ public enum Category { /** * The standard/well-known category of a <tt>ContactDetail</tt> * representing personal details, like name, last name, nickname. */ Personal("Personal"), /** * The standard/well-known category of a <tt>ContactDetail</tt> * representing personal details, like web address. */ Web("Web"), /** * The standard/well-known category of a <tt>ContactDetail</tt> * representing organization details, like organization name and job * title. */ Organization("Organization"), /** * The standard/well-known category of a <tt>ContactDetail</tt> * representing an e-mail address. */ Email("Email"), /** * The standard/well-known category of a <tt>ContactDetail</tt> * representing a contact address for instant messaging. */ InstantMessaging("InstantMessaging"), /** * The standard/well-known category of a <tt>ContactDetail</tt> * representing a phone number. */ Phone("Phone"), /** * The standard/well-known category of a <tt>ContactDetail</tt> * representing a postal address. */ Address("Address"); /** * Current enum value. */ private final String value; /** * Creates enum whith the specified value. * * @param value the value to set. */ Category(String value) { this.value = value; } /** * Gets the value. * * @return the value */ public String value() { return value; } /** * Creates enum from its value. * * @param value the enum's value. * @return created enum. */ public static Category fromString(String value) { if (value != null) { for (Category category : Category.values()) { if (value.equalsIgnoreCase(category.value())) { return category; } } return null; } return null; } } /** * Defines all possible sub-categories for a <tt>ContactDetail</tt>. */ public enum SubCategory { /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a name. It could be an organization name or a personal * name. */ Name("Name"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a last name. */ LastName("LastName"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a nickname. */ Nickname("Nickname"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a postal code. */ HomePage("HomePage"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing an address of a contact at their home. */ Home("Home"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a mobile contact address (e.g. a cell phone number). */ Mobile("Mobile"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing an address of a contact at their work. */ Work("Work"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a fax number. */ Fax("Fax"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a different number. */ Other("Other"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing an IM network (like for example jabber). */ AIM("AIM"), ICQ("ICQ"), Jabber("XMPP"), Skype("Skype"), Yahoo("Yahoo"), GoogleTalk("GoogleTalk"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a country name. */ Country("Country"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a state name. */ State("State"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a city name. */ City("City"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a street address. */ Street("Street"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a postal code. */ PostalCode("PostalCode"), /** * The standard/well-known label of a <tt>ContactDetail</tt> * representing a job title. */ JobTitle("JobTitle"); /** * Current enum value. */ private final String value; /** * Creates enum whith the specified value. * * @param value the value to set. */ SubCategory(String value) { this.value = value; } /** * Gets the value. * * @return the value */ public String value() { return value; } /** * Creates enum from its value. * * @param value the enum's value. * @return created enum. */ public static SubCategory fromString(String value) { if (value != null) { for (SubCategory subCategory : SubCategory.values()) { if (value.equalsIgnoreCase(subCategory.value())) { return subCategory; } } return null; } return null; } } /** * The category of this <tt>ContactQuery</tt>. */ private final Category category; /** * The address of this contact detail. This should be the address through * which the contact could be reached by one of the supported * <tt>OperationSet</tt>s (e.g. by IM, call). */ protected String contactDetailValue; /** * The display name of this detail. */ private String detailDisplayName; /** * The set of labels of this <tt>ContactDetail</tt>. The labels may be * arbitrary and may include any of the standard/well-known labels defined * by the <tt>LABEL_XXX</tt> constants of the <tt>ContactDetail</tt> class. */ private final Collection<SubCategory> subCategories = new LinkedList<SubCategory>(); /** * A mapping of <tt>OperationSet</tt> classes and preferred protocol * providers for them. */ private Map<Class<? extends OperationSet>, ProtocolProviderService> preferredProviders; /** * A mapping of <tt>OperationSet</tt> classes and preferred protocol name * for them. */ private Map<Class<? extends OperationSet>, String> preferredProtocols; /** * A list of all supported <tt>OperationSet</tt> classes. */ private List<Class<? extends OperationSet>> supportedOpSets = null; /** * Creates a <tt>ContactDetail</tt> by specifying the contact address, * corresponding to this detail. * @param contactDetailValue the contact detail value corresponding to this * detail */ public ContactDetail(String contactDetailValue) { this(contactDetailValue, null, null, null); } /** * Creates a <tt>ContactDetail</tt> by specifying the contact address, * corresponding to this detail. * @param contactDetailValue the contact detail value corresponding to this * detail * @param detailDisplayName the display name of this detail */ public ContactDetail(String contactDetailValue, String detailDisplayName) { this(contactDetailValue, detailDisplayName, null, null); } /** * Initializes a new <tt>ContactDetail</tt> instance which is to represent a * specific contact address and which is to be optionally labeled with a * specific set of labels. * * @param contactDetailValue the contact detail value to be represented by * the new <tt>ContactDetail</tt> instance * @param category */ public ContactDetail( String contactDetailValue, Category category) { this(contactDetailValue, null, category, null); } /** * Initializes a new <tt>ContactDetail</tt> instance which is to represent a * specific contact address and which is to be optionally labeled with a * specific set of labels. * * @param contactDetailValue the contact detail value to be represented by * the new <tt>ContactDetail</tt> instance * @param detailDisplayName the display name of this detail * @param category */ public ContactDetail( String contactDetailValue, String detailDisplayName, Category category) { this(contactDetailValue, detailDisplayName, category, null); } /** * Initializes a new <tt>ContactDetail</tt> instance which is to represent a * specific contact address and which is to be optionally labeled with a * specific set of labels. * * @param contactDetailValue the contact detail value to be represented by * the new <tt>ContactDetail</tt> instance * @param category * @param subCategories the set of sub categories with which the new * <tt>ContactDetail</tt> instance is to be labeled. */ public ContactDetail( String contactDetailValue, Category category, SubCategory[] subCategories) { this(contactDetailValue, null, category, subCategories); } /** * Initializes a new <tt>ContactDetail</tt> instance which is to represent a * specific contact address and which is to be optionally labeled with a * specific set of labels. * * @param contactDetailValue the contact detail value to be represented by * the new <tt>ContactDetail</tt> instance * @param detailDisplayName the display name of this detail * @param category * @param subCategories the set of sub categories with which the new * <tt>ContactDetail</tt> instance is to be labeled. */ public ContactDetail( String contactDetailValue, String detailDisplayName, Category category, SubCategory[] subCategories) { // the value of the detail this.contactDetailValue = contactDetailValue; if (!StringUtils.isNullOrEmpty(detailDisplayName)) { this.detailDisplayName = detailDisplayName; } else if (category == Category.Phone) { this.detailDisplayName = ContactSourceActivator.getPhoneNumberI18nService() .formatForDisplay(contactDetailValue); } else { this.detailDisplayName = contactDetailValue; } // category & labels this.category = category; if (subCategories != null) { for (SubCategory subCategory : subCategories) { if ((subCategory != null) && !this.subCategories.contains(subCategory)) { this.subCategories.add(subCategory); } } } } /** * Sets a mapping of preferred <tt>ProtocolProviderServices</tt> for * a specific <tt>OperationSet</tt>. * @param preferredProviders a mapping of preferred * <tt>ProtocolProviderService</tt>s for specific <tt>OperationSet</tt> * classes */ public void setPreferredProviders( Map<Class<? extends OperationSet>, ProtocolProviderService> preferredProviders) { this.preferredProviders = preferredProviders; } /** * Sets a mapping of a preferred <tt>preferredProtocol</tt> for a specific * <tt>OperationSet</tt>. The preferred protocols are meant to be set by * contact source implementations that don't have a specific protocol * providers to suggest, but are able to propose just the name of the * protocol to be used for a specific operation. If both - preferred * provider and preferred protocol are set, then the preferred protocol * provider should be prioritized. * * @param preferredProtocols a mapping of preferred * <tt>ProtocolProviderService</tt>s for specific <tt>OperationSet</tt> * classes */ public void setPreferredProtocols( Map<Class<? extends OperationSet>, String> preferredProtocols) { this.preferredProtocols = preferredProtocols; // protocol added so an opset is supported, add it if missing for(Class<? extends OperationSet> opsetClass : preferredProtocols.keySet()) { if(supportedOpSets == null || !supportedOpSets.contains(opsetClass)) addSupportedOpSet(opsetClass); } } /** * Creates a <tt>ContactDetail</tt> by specifying the corresponding contact * address and a list of all <tt>supportedOpSets</tt>, indicating what are * the supporting actions with this contact detail (e.g. sending a message, * making a call, etc.) * @param supportedOpSets a list of all <tt>supportedOpSets</tt>, indicating * what are the supporting actions with this contact detail (e.g. sending a * message, making a call, etc.) */ public void setSupportedOpSets( List<Class<? extends OperationSet>> supportedOpSets) { this.supportedOpSets = supportedOpSets; } /** * Adds a supported OpSet to the list of supported OpSets. * @param supportedOpSet the OpSet to support. */ public void addSupportedOpSet(Class<? extends OperationSet> supportedOpSet) { if (this.supportedOpSets == null) { this.supportedOpSets = new ArrayList<Class<? extends OperationSet>>(2); } this.supportedOpSets.add(supportedOpSet); } /** * Gets the category, if any, of this <tt>ContactQuery</tt>. * * @return the category of this <tt>ContactQuery</tt> if it has any; * otherwise, <tt>null</tt> */ public Category getCategory() { return category; } /** * Returns the contact address corresponding to this detail. * * @return the contact address corresponding to this detail */ public String getDetail() { return contactDetailValue; } /** * Returns the display name of this detail. By default returns the detail * value. * * @return the display name of this detail */ public String getDisplayName() { return detailDisplayName; } /** * Returns the preferred <tt>ProtocolProviderService</tt> when using the * given <tt>opSetClass</tt>. * * @param opSetClass the <tt>OperationSet</tt> class corresponding to a * certain action (e.g. sending an instant message, making a call, etc.). * @return the preferred <tt>ProtocolProviderService</tt> corresponding to * the given <tt>opSetClass</tt> */ public ProtocolProviderService getPreferredProtocolProvider( Class<? extends OperationSet> opSetClass) { if (preferredProviders != null && preferredProviders.size() > 0) return preferredProviders.get(opSetClass); return null; } /** * Returns the name of the preferred protocol for the operation given by * the <tt>opSetClass</tt>. The preferred protocols are meant to be set by * contact source implementations that don't have a specific protocol * providers to suggest, but are able to propose just the name of the * protocol to be used for a specific operation. If both - preferred * provider and preferred protocol are set, then the preferred protocol * provider should be prioritized. * * @param opSetClass the <tt>OperationSet</tt> class corresponding to a * certain action (e.g. sending an instant message, making a call, etc.). * @return the name of the preferred protocol for the operation given by * the <tt>opSetClass</tt> */ public String getPreferredProtocol(Class<? extends OperationSet> opSetClass) { if (preferredProtocols != null && preferredProtocols.size() > 0) return preferredProtocols.get(opSetClass); return null; } /** * Returns a list of all supported <tt>OperationSet</tt> classes, which * would indicate what are the supported actions by this contact * (e.g. write a message, make a call, etc.) * * @return a list of all supported <tt>OperationSet</tt> classes */ public List<Class<? extends OperationSet>> getSupportedOperationSets() { return supportedOpSets; } /** * Determines whether the set of labels of this <tt>ContactDetail</tt> * contains a specific label. The labels may be arbitrary and may include * any of the standard/well-known labels defined by the <tt>LABEL_XXX</tt> * constants of the <tt>ContactDetail</tt> class. * * @param subCategory the subCategory to be determined whether * it is contained in this <tt>ContactDetail</tt> * @return <tt>true</tt> if the specified <tt>label</tt> is contained in the * set of labels of this <tt>ContactDetail</tt> */ public boolean containsSubCategory(SubCategory subCategory) { return subCategories.contains(subCategory); } /** * Gets the set of labels of this <tt>ContactDetail</tt>. The labels may be * arbitrary and may include any of the standard/well-known labels defined * by the <tt>LABEL_XXX</tt> constants of the <tt>ContactDetail</tt> class. * * @return the set of labels of this <tt>ContactDetail</tt>. If this * <tt>ContactDetail</tt> has no labels, the returned <tt>Collection</tt> is * empty. */ public Collection<SubCategory> getSubCategories() { return Collections.unmodifiableCollection(subCategories); } }