Commit 05134318 authored by Gabriel Guardincerri's avatar Gabriel Guardincerri Committed by gguardin

[JM-1281] Fixed an exception using a user with a not visible email and CS as a provider.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/branches@10018 b35dd754-fafc-0310-a699-88a17e54d16e
parent 6d34b403
......@@ -23,22 +23,36 @@ import org.xmpp.packet.JID;
import java.util.*;
/**
* @author Daniel Henninger
* The ClearspaceUserProvider uses the UserService and ProfileSearchService web service inside of Clearspace
* to retrieve user information and to search for users from Clearspace.
*
* @author Gabriel Guardincerri
*/
public class ClearspaceUserProvider implements UserProvider {
// The UserService webservice url prefix
protected static final String USER_URL_PREFIX = "userService/";
// The ProfileSearchService webservice url prefix
protected static final String SEARCH_URL_PREFIX = "profileSearchService/";
private ClearspaceManager manager;
// Used to know it CS is a read only user provider
private Boolean readOnly;
public ClearspaceUserProvider() {
// Gets the manager
manager = ClearspaceManager.getInstance();
loadReadOnly();
}
/**
* Loads the user using the userService/users GET service. Only loads local users.
* Throws a UserNotFoundException exception if the user could not be found.
*
* @param username the username of the user to load
* @return a user instance with the user information
* @throws UserNotFoundException if the user could not be found
*/
public User loadUser(String username) throws UserNotFoundException {
// Checks if the user is local
if (username.contains("@")) {
......@@ -52,6 +66,19 @@ public class ClearspaceUserProvider implements UserProvider {
return translate(getUserByUsername(username));
}
/**
* Creates user using the userService/users POST service. If Clearspace is a read only
* provider throws an UnsupportedOperationException. If there is already a user with
* the username throws a UserAlreadyExistsException.
*
* @param username the username of the user
* @param password the password of the user
* @param name the name of the user (optional)
* @param email the email of the user
* @return an instance of the created user
* @throws UserAlreadyExistsException If there is already a user with the username
* @throws UnsupportedOperationException If Clearspace is a read only provider
*/
public User createUser(String username, String password, String name, String email) throws UserAlreadyExistsException {
if (isReadOnly()) {
// Reject the operation since the provider is read-only
......@@ -100,6 +127,11 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Creates user using the userService/users DELETE service. If the user is not found returns.
*
* @param username the username of the user to delete
*/
public void deleteUser(String username) {
if (isReadOnly()) {
// Reject the operation since the provider is read-only
......@@ -119,6 +151,11 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Gets the user count using the userService/users/count GET service.
*
* @return the user count
*/
public int getUserCount() {
try {
String path = USER_URL_PREFIX + "users/count";
......@@ -131,11 +168,21 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Gets all users using the userService/userNames GET service.
*
* @return a list of all users
*/
public Collection<User> getUsers() {
Collection<String> usernames = getUsernames();
return new UserCollection(usernames.toArray(new String[usernames.size()]));
}
/**
* Gets all usernames using the userService/userNames GET service.
*
* @return a list of all the usernames
*/
public Collection<String> getUsernames() {
try {
String path = USER_URL_PREFIX + "userNames";
......@@ -148,6 +195,13 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Gets a bounded list of users using the userService/userNames GET service.
*
* @param startIndex the start index
* @param numResults the number of result
* @return a bounded list of users
*/
public Collection<User> getUsers(int startIndex, int numResults) {
String[] usernamesAll = getUsernames().toArray(new String[0]);
Collection<String> usernames = new ArrayList<String>();
......@@ -160,6 +214,13 @@ public class ClearspaceUserProvider implements UserProvider {
return new UserCollection(usernames.toArray(new String[usernames.size()]));
}
/**
* Updates the name of the user using the userService/update service.
*
* @param username the username of the user
* @param name the new name of the user
* @throws UserNotFoundException if there is no user with that username
*/
public void setName(String username, String name) throws UserNotFoundException {
if (isReadOnly()) {
// Reject the operation since the provider is read-only
......@@ -177,6 +238,13 @@ public class ClearspaceUserProvider implements UserProvider {
updateUser(userUpdateParams);
}
/**
* Updates the email of the user using the userService/update service.
*
* @param username the username of the user
* @param email the new email of the user
* @throws UserNotFoundException if the user could not be found
*/
public void setEmail(String username, String email) throws UserNotFoundException {
if (isReadOnly()) {
// Reject the operation since the provider is read-only
......@@ -194,6 +262,14 @@ public class ClearspaceUserProvider implements UserProvider {
updateUser(userUpdateParams);
}
/**
* Updates the creationDate of the user using the userService/update service.
*
* @param username the username of the user
* @param creationDate the new email of the user
* @throws UserNotFoundException if the user could not be found
*/
public void setCreationDate(String username, Date creationDate) throws UserNotFoundException {
if (isReadOnly()) {
// Reject the operation since the provider is read-only
......@@ -212,6 +288,13 @@ public class ClearspaceUserProvider implements UserProvider {
updateUser(userUpdateParams);
}
/**
* Updates the modificationDate of the user using the userService/update service.
*
* @param username the username of the user
* @param modificationDate the new modificationDate of the user
* @throws UserNotFoundException if the user could not be found
*/
public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException {
if (isReadOnly()) {
// Reject the operation since the provider is read-only
......@@ -230,6 +313,13 @@ public class ClearspaceUserProvider implements UserProvider {
updateUser(userUpdateParams);
}
/**
* Creates the parameters to send in a update user request based on the information of <code>username</code>
*
* @param username the username of the user
* @return the parameters to send in a update user request
* @throws UserNotFoundException if the user could not be found
*/
protected Element getUserUpdateParams(String username) throws UserNotFoundException {
// Creates the user update params element
Element userUpdateParams = DocumentHelper.createDocument().addElement("updateUser");
......@@ -246,6 +336,12 @@ public class ClearspaceUserProvider implements UserProvider {
return userUpdateParams;
}
/**
* Updates the user using the userService/users PUT service.
*
* @param userUpdateParams the request parameters
* @throws UserNotFoundException if the user could not be found
*/
protected void updateUser(Element userUpdateParams) throws UserNotFoundException {
try {
String path = USER_URL_PREFIX + "users";
......@@ -259,32 +355,44 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Clearsapce can search using three fields: username, name and email.
*
* @return a list of username, name and email
* @throws UnsupportedOperationException
*/
public Set<String> getSearchFields() throws UnsupportedOperationException {
return new LinkedHashSet<String>(Arrays.asList("Username", "Name", "Email"));
}
/**
* Search for the user using the userService/search POST method.
*
* @param fields the fields to search on.
* @param query the query string.
* @return a Collection of users that match the search.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public Collection<User> findUsers(Set<String> fields, String query) throws UnsupportedOperationException {
// Creates the XML with the data
Document groupDoc = DocumentHelper.createDocument();
Element rootE = groupDoc.addElement("searchProfile");
Element queryE = rootE.addElement("WSProfileSearchQuery");
Element keywords = queryE.addElement("keywords");
keywords.addText(query);
Element searchUsername = queryE.addElement("searchUsername");
searchUsername.addText("true");
Element searchName = queryE.addElement("searchName");
searchName.addText("true");
Element searchEmail = queryE.addElement("searchEmail");
searchEmail.addText("true");
Element searchProfile = queryE.addElement("searchProfile");
searchProfile.addText("false");
Element paramsE = DocumentHelper.createDocument().addElement("search");
Element queryE = paramsE.addElement("query");
queryE.addElement("keywords").addText(query);
queryE.addElement("searchUsername").addText("true");
queryE.addElement("searchName").addText("true");
queryE.addElement("searchEmail").addText("true");
queryE.addElement("searchProfile").addText("false");
try {
List<String> usernames = new ArrayList<String>();
String path = SEARCH_URL_PREFIX + "searchProfile";
//TODO create a service on CS to get only the username field
Element element = manager.executeRequest(GET, path);
String path = SEARCH_URL_PREFIX + "searchProfile";
Element element = manager.executeRequest(POST, path, paramsE.asXML());
List<Node> userNodes = (List<Node>) element.selectNodes("return");
for (Node userNode : userNodes) {
......@@ -299,28 +407,40 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Search for the user using the userService/searchBounded POST method.
*
* @param fields the fields to search on.
* @param query the query string.
* @param startIndex the starting index in the search result to return.
* @param numResults the number of users to return in the search result.
* @return a Collection of users that match the search.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public Collection<User> findUsers(Set<String> fields, String query, int startIndex, int numResults) throws UnsupportedOperationException {
// Creates the XML with the data
Document groupDoc = DocumentHelper.createDocument();
Element rootE = groupDoc.addElement("searchBounded");
Element queryE = rootE.addElement("WSProfileSearchQuery");
Element keywords = queryE.addElement("keywords");
keywords.addText(query);
Element searchUsername = queryE.addElement("searchUsername");
searchUsername.addText("true");
Element searchName = queryE.addElement("searchName");
searchName.addText("true");
Element searchEmail = queryE.addElement("searchEmail");
searchEmail.addText("true");
Element searchProfile = queryE.addElement("searchProfile");
searchProfile.addText("false");
Element paramsE = DocumentHelper.createDocument().addElement("searchBounded");
Element queryE = paramsE.addElement("query");
queryE.addElement("keywords").addText(query);
queryE.addElement("searchUsername").addText("true");
queryE.addElement("searchName").addText("true");
queryE.addElement("searchEmail").addText("true");
queryE.addElement("searchProfile").addText("false");
paramsE.addElement("startIndex").addText(String.valueOf(startIndex));
paramsE.addElement("numResults").addText(String.valueOf(numResults));
try {
List<String> usernames = new ArrayList<String>();
String path = SEARCH_URL_PREFIX + "searchProfile/" + startIndex + "/" + numResults;
Element element = manager.executeRequest(GET, path);
//TODO create a service on CS to get only the username field
String path = SEARCH_URL_PREFIX + "searchProfile";
Element element = manager.executeRequest(POST, path, paramsE.asXML());
List<Node> userNodes = (List<Node>) element.selectNodes("return");
for (Node userNode : userNodes) {
String username = userNode.selectSingleNode("username").getText();
......@@ -334,22 +454,44 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Returns true if Clearspace is a read only user provider.
*
* @return true if Clearspace is a read only user provider
*/
public boolean isReadOnly() {
if (readOnly == null) {
loadReadOnly();
synchronized (this) {
if (readOnly == null) {
loadReadOnly();
}
}
}
// If it is null returns the most restrictive answer.
return (readOnly == null ? false : readOnly);
}
/**
* In Clearspace name is optional.
*
* @return false
*/
public boolean isNameRequired() {
return false;
}
/**
* In Clearspace email is required
*
* @return true
*/
public boolean isEmailRequired() {
return true;
}
/**
* Tries to load the read only attribute using the userService/isReadOnly service.
*/
private void loadReadOnly() {
try {
// See if the is read only
......@@ -361,6 +503,12 @@ public class ClearspaceUserProvider implements UserProvider {
}
}
/**
* Translates a Clearspace xml user response into a Openfire User
*
* @param responseNode the Clearspace response
* @return a User instance with its information
*/
private User translate(Node responseNode) {
String username = null;
String name = null;
......@@ -376,20 +524,20 @@ public class ClearspaceUserProvider implements UserProvider {
// Gets the name if it is visible
boolean nameVisible = Boolean.valueOf(userNode.selectSingleNode("nameVisible").getText());
if (nameVisible) {
tmpNode = userNode.selectSingleNode("name");
if (tmpNode != null) {
name = tmpNode.getText();
}
// Gets the name
tmpNode = userNode.selectSingleNode("name");
if (tmpNode != null) {
name = tmpNode.getText();
}
// Gets the email if it is visible
boolean emailVisible = Boolean.valueOf(userNode.selectSingleNode("emailVisible").getText());
if (emailVisible) {
tmpNode = userNode.selectSingleNode("email");
if (tmpNode != null) {
email = tmpNode.getText();
}
// Gets the email
tmpNode = userNode.selectSingleNode("email");
if (tmpNode != null) {
email = tmpNode.getText();
}
// Gets the creation date
......@@ -405,9 +553,19 @@ public class ClearspaceUserProvider implements UserProvider {
}
// Creates the user
return new User(username, name, email, creationDate, modificationDate);
User user = new User(username, name, email, creationDate, modificationDate);
user.setNameVisible(nameVisible);
user.setEmailVisible(emailVisible);
return user;
}
/**
* Gets a user using the userService/users GET service.
*
* @param username the username of the user
* @return the user xml response
* @throws UserNotFoundException if the user could not be found
*/
private Element getUserByUsername(String username) throws UserNotFoundException {
try {
......
......@@ -139,10 +139,10 @@ class ClearspaceVCardTranslator {
/**
* Init the fields of clearspace based on they name.
*
* @param fieldsId
* @param fields the fields information
*/
protected void initClearspaceFieldsId(Element fieldsId) {
List<Element> fieldsList = fieldsId.elements("return");
protected void initClearspaceFieldsId(Element fields) {
List<Element> fieldsList = fields.elements("return");
for (Element field : fieldsList) {
String fieldName = field.elementText("name");
long fieldID = Long.valueOf(field.elementText("ID"));
......@@ -155,6 +155,16 @@ class ClearspaceVCardTranslator {
}
/**
* Translates a VCard of Openfire into profiles, user information and a avatar of Clearspace.
* Returns what can of action has been made over the the profilesElement, userElement and avatarElement/
*
* @param vCardElement the VCard information
* @param profilesElement the profile to add/modify/delete the information
* @param userElement the user to add/modify/delete the information
* @param avatarElement the avatar to add/modify/delete the information
* @return a list of actions performed over the profilesElement, userElement and avatarElement
*/
protected Action[] translateVCard(Element vCardElement, Element profilesElement, Element userElement, Element avatarElement) {
Action[] actions = new Action[3];
......@@ -171,6 +181,13 @@ class ClearspaceVCardTranslator {
return actions;
}
/**
* Updates the avatar values based on the vCard values
*
* @param avatarElement the avatar element to update
* @param vCardValues the vCard values with the information
* @return the action performed
*/
private Action updateAvatarValues(Element avatarElement, Map<VCardField, String> vCardValues) {
Action action = Action.NO_ACTION;
......@@ -201,6 +218,13 @@ class ClearspaceVCardTranslator {
return action;
}
/**
* Updates the user values based on the vCard values
*
* @param userElement the user element to update
* @param vCardValues the vCard values
* @return the action performed
*/
private Action updateUserValues(Element userElement, Map<VCardField, String> vCardValues) {
Action action = Action.NO_ACTION;
......@@ -228,9 +252,9 @@ class ClearspaceVCardTranslator {
/**
* Updates the values of the profiles with the values of the vCard
*
* @param profiles
* @param vCardValues
* @return
* @param profiles the profiles element to update
* @param vCardValues the vCard values
* @return the action performed
*/
private Action updateProfilesValues(Element profiles, Map<VCardField, String> vCardValues) {
Action action = Action.NO_ACTION;
......@@ -259,32 +283,32 @@ class ClearspaceVCardTranslator {
String oldValue;
switch (field) {
case TITLE:
if (modifyProfileValue(vCardValues, profiles, value, VCardField.TITLE)) {
if (modifyProfileValue(vCardValues, value, VCardField.TITLE)) {
action = Action.MODIFY;
}
break;
case DEPARTMENT:
if (modifyProfileValue(vCardValues, profiles, value, VCardField.ORG_ORGUNIT)) {
if (modifyProfileValue(vCardValues, value, VCardField.ORG_ORGUNIT)) {
action = Action.MODIFY;
}
break;
case ADDRESS:
if (modifyProfileValue(vCardValues, profiles, value, VCardField.ADR_WORK)) {
if (modifyProfileValue(vCardValues, value, VCardField.ADR_WORK)) {
action = Action.MODIFY;
}
break;
case HOME_ADDRESS:
if (modifyProfileValue(vCardValues, profiles, value, VCardField.ADR_HOME)) {
if (modifyProfileValue(vCardValues, value, VCardField.ADR_HOME)) {
action = Action.MODIFY;
}
break;
case TIME_ZONE:
if (modifyProfileValue(vCardValues, profiles, value, VCardField.TZ)) {
if (modifyProfileValue(vCardValues, value, VCardField.TZ)) {
action = Action.MODIFY;
}
break;
case URL:
if (modifyProfileValue(vCardValues, profiles, value, VCardField.URL)) {
if (modifyProfileValue(vCardValues, value, VCardField.URL)) {
action = Action.MODIFY;
}
break;
......@@ -454,6 +478,14 @@ class ClearspaceVCardTranslator {
return action;
}
/**
* Adds a profiles element to the profiles if it is not empty
*
* @param profiles the profiles to add a profile to
* @param field the field type to add
* @param newValue the value to add
* @return true if the field was added
*/
private boolean addProfile(Element profiles, ClearspaceField field, String newValue) {
// Don't add empty vales
if (newValue == null || "".equals(newValue.trim())) {
......@@ -470,7 +502,15 @@ class ClearspaceVCardTranslator {
return true;
}
private boolean modifyProfileValue(Map<VCardField, String> vCardValues, Element profiles, Element value, VCardField vCardField) {
/**
* Modifies the value of a profile if it is different from the original one.
*
* @param vCardValues the vCard values with the new values
* @param value the current value of the profile
* @param vCardField the vCard field
* @return true if the field was modified
*/
private boolean modifyProfileValue(Map<VCardField, String> vCardValues, Element value, VCardField vCardField) {
boolean modified = false;
String newValue = vCardValues.get(vCardField);
......@@ -486,6 +526,13 @@ class ClearspaceVCardTranslator {
return modified;
}
/**
* Adds the field type to the field value. Returns null if the value is empty.
*
* @param value the value
* @param type the type
* @return the field value with the type
*/
private String addFieldType(String value, String type) {
if (value == null || "".equals(value.trim())) {
return null;
......@@ -493,6 +540,13 @@ class ClearspaceVCardTranslator {
return value + "|" + type;
}
/**
* Returns the field type of a field. Return null if the field doesn't
* contains a type
*
* @param field the field with the type
* @return the field type
*/
private String getFieldType(String field) {
int i = field.indexOf("|");
if (i == -1) {
......@@ -502,6 +556,13 @@ class ClearspaceVCardTranslator {
}
}
/**
* Returns the field value of a field. Return the field if the field doesn't
* contains a type.
*
* @param field the field
* @return the field value
*/
private String getFieldValue(String field) {
int i = field.indexOf("|");
if (i == -1) {
......@@ -513,10 +574,10 @@ class ClearspaceVCardTranslator {
/**
* Collects the vCard values and store them into a map.
* They are stored with this constants:
* They are stored with the VCardField enum.
*
* @param vCardElement
* @return
* @param vCardElement the vCard with the information
* @return a map of the value of the vCard.
*/
private Map<VCardField, String> collectVCardValues(Element vCardElement) {
......@@ -602,10 +663,10 @@ class ClearspaceVCardTranslator {
/**
* Translates the information from Clearspace into a VCard.
*
* @param profile
* @param user
* @param avatar
* @return
* @param profile the profile
* @param user the user
* @param avatar the avatar
* @return the vCard with the information
*/
protected Element translateClearspaceInfo(Element profile, User user, Element avatar) {
......@@ -619,7 +680,12 @@ class ClearspaceVCardTranslator {
return vCard;
}
/**
* Translates the profile information to the vCard
*
* @param profiles the profile information
* @param vCard the vCard to add the information to
*/
private void translateProfileInformation(Element profiles, Element vCard) {
// Translate the profile XML
......@@ -747,15 +813,21 @@ class ClearspaceVCardTranslator {
}
}
/**
* Translates the user information to the vCard
*
* @param user the user information
* @param vCard the vCard to add the information to
*/
private void translateUserInformation(User user, Element vCard) {
// The name could be null (if in Clearspace the name is not visible in Openfire it is null)
if (user.getName() != null && !"".equals(user.getName().trim())) {
// Only set the name to the VCard if it is visible
if (user.isNameVisible()) {
vCard.addElement("FN").setText(user.getName());
vCard.addElement("N").addElement("FAMILY").setText(user.getName());
}
// Email is mandatory, but may be invisible
if (user.getEmail() != null && !"".equals(user.getName().trim())) {
// Only set the eamail to the VCard if it is visible
if (user.isEmailVisible()) {
Element email = vCard.addElement("EMAIL");
email.addElement("PREF");
email.addElement("USERID").setText(user.getEmail());
......@@ -765,6 +837,12 @@ class ClearspaceVCardTranslator {
vCard.addElement("JABBERID").setText(jid);
}
/**
* Translates the avatar information to the vCard.
*
* @param avatarResponse the avatar information
* @param vCard the vCard to add the information to
*/
private void translateAvatarInformation(Element avatarResponse, Element vCard) {
Element avatar = avatarResponse.element("return");
if (avatar != null) {
......@@ -781,6 +859,12 @@ class ClearspaceVCardTranslator {
}
}
/**
* Translates the address string of Clearspace to the vCard format.
*
* @param address the address string of Clearspae
* @param addressE the address element to add the address to
*/
private void translateAddress(String address, Element addressE) {
StringTokenizer strTokenize = new StringTokenizer(address, ",");
while (strTokenize.hasMoreTokens()) {
......@@ -819,6 +903,12 @@ class ClearspaceVCardTranslator {
}
/**
* Translates the address form the vCard format to the Clearspace string.
*
* @param addressElement the address in the vCard format
* @return the address int the Clearspace format
*/
private String translateAddress(Element addressElement) {
StringBuilder sb = new StringBuilder();
......@@ -850,8 +940,16 @@ class ClearspaceVCardTranslator {
return sb.toString();
}
private void translateAddressField(Element addressElement, String elementName, String fieldName, StringBuilder sb) {
String field = addressElement.elementTextTrim(elementName);
/**
* Translates the address field from the vCard format to the Clearspace format.
*
* @param addressElement the vCard address
* @param vCardFieldName the vCard field name
* @param fieldName the Clearspace field name
* @param sb the string builder to append the field string to
*/
private void translateAddressField(Element addressElement, String vCardFieldName, String fieldName, StringBuilder sb) {
String field = addressElement.elementTextTrim(vCardFieldName);
if (field != null && !"".equals(field)) {
sb.append(fieldName).append(":").append(field).append(",");
}
......
......@@ -47,15 +47,20 @@ import java.util.concurrent.ConcurrentHashMap;
public class User implements Cacheable, Externalizable, Result {
private static final String LOAD_PROPERTIES =
"SELECT name, propValue FROM jiveUserProp WHERE username=?";
"SELECT name, propValue FROM jiveUserProp WHERE username=?";
private static final String LOAD_PROPERTY =
"SELECT propValue FROM jiveUserProp WHERE username=? AND name=?";
"SELECT propValue FROM jiveUserProp WHERE username=? AND name=?";
private static final String DELETE_PROPERTY =
"DELETE FROM jiveUserProp WHERE username=? AND name=?";
"DELETE FROM jiveUserProp WHERE username=? AND name=?";
private static final String UPDATE_PROPERTY =
"UPDATE jiveUserProp SET propValue=? WHERE name=? AND username=?";
"UPDATE jiveUserProp SET propValue=? WHERE name=? AND username=?";
private static final String INSERT_PROPERTY =
"INSERT INTO jiveUserProp (username, name, propValue) VALUES (?, ?, ?)";
"INSERT INTO jiveUserProp (username, name, propValue) VALUES (?, ?, ?)";
// The name of the name visible property
private static final String NAME_VISIBLE_PROPERTY = "name.visible";
// The name of the email visible property
private static final String EMAIL_VISIBLE_PROPERTY = "email.visible";
private String username;
private String name;
......@@ -63,13 +68,13 @@ public class User implements Cacheable, Externalizable, Result {
private Date creationDate;
private Date modificationDate;
private Map<String,String> properties = null;
private Map<String, String> properties = null;
/**
* Returns the value of the specified property for the given username. This method is
* an optimization to avoid loading a user to get a specific property.
*
* @param username the username of the user to get a specific property value.
* @param username the username of the user to get a specific property value.
* @param propertyName the name of the property to return its value.
* @return the value of the specified property for the given username.
*/
......@@ -92,10 +97,18 @@ public class User implements Cacheable, Externalizable, Result {
Log.error(sqle);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
try {
if (pstmt != null) pstmt.close();
}
catch (Exception e) {
Log.error(e);
}
try {
if (con != null) con.close();
}
catch (Exception e) {
Log.error(e);
}
}
return propertyValue;
}
......@@ -113,15 +126,14 @@ public class User implements Cacheable, Externalizable, Result {
* Typically, User objects should not be constructed by end-users of the API.
* Instead, user objects should be retrieved using {@link UserManager#getUser(String)}.
*
* @param username the username.
* @param name the name.
* @param email the email address.
* @param creationDate the date the user was created.
* @param username the username.
* @param name the name.
* @param email the email address.
* @param creationDate the date the user was created.
* @param modificationDate the date the user was last modified.
*/
public User(String username, String name, String email, Date creationDate,
Date modificationDate)
{
Date modificationDate) {
if (username == null) {
throw new NullPointerException("Username cannot be null");
}
......@@ -132,7 +144,7 @@ public class User implements Cacheable, Externalizable, Result {
this.name = name;
if (UserManager.getUserProvider().isEmailRequired() && !StringUtils.isValidEmailAddress(email)) {
throw new IllegalArgumentException("Invalid or empty email address specified with provider that requires email address. User: "
+ username + " Email: " + email);
+ username + " Email: " + email);
}
this.email = email;
this.creationDate = creationDate;
......@@ -162,7 +174,7 @@ public class User implements Cacheable, Externalizable, Result {
AuthFactory.getAuthProvider().setPassword(username, password);
// Fire event.
Map<String,Object> params = new HashMap<String,Object>();
Map<String, Object> params = new HashMap<String, Object>();
params.put("type", "passwordModified");
UserEventDispatcher.dispatchEvent(this, UserEventDispatcher.EventType.user_modified,
params);
......@@ -194,7 +206,7 @@ public class User implements Cacheable, Externalizable, Result {
this.name = name;
// Fire event.
Map<String,Object> params = new HashMap<String,Object>();
Map<String, Object> params = new HashMap<String, Object>();
params.put("type", "nameModified");
params.put("originalValue", originalName);
UserEventDispatcher.dispatchEvent(this, UserEventDispatcher.EventType.user_modified,
......@@ -205,6 +217,24 @@ public class User implements Cacheable, Externalizable, Result {
}
}
/**
* Returns true if name is visible to everyone or not.
*
* @return true if name is visible to everyone, false if not.
*/
public boolean isNameVisible() {
return !getProperties().containsKey(NAME_VISIBLE_PROPERTY) || Boolean.valueOf(getProperties().get(NAME_VISIBLE_PROPERTY));
}
/**
* Sets if name is visible to everyone or not.
*
* @param visible true if name is visible, false if not.
*/
public void setNameVisible(boolean visible) {
getProperties().put(NAME_VISIBLE_PROPERTY, String.valueOf(visible));
}
/**
* Returns the email address of the user or <tt>null</tt> if none is defined.
*
......@@ -224,11 +254,11 @@ public class User implements Cacheable, Externalizable, Result {
}
try {
String originalEmail= this.email;
String originalEmail = this.email;
UserManager.getUserProvider().setEmail(username, email);
this.email = email;
// Fire event.
Map<String,Object> params = new HashMap<String,Object>();
Map<String, Object> params = new HashMap<String, Object>();
params.put("type", "emailModified");
params.put("originalValue", originalEmail);
UserEventDispatcher.dispatchEvent(this, UserEventDispatcher.EventType.user_modified,
......@@ -239,6 +269,24 @@ public class User implements Cacheable, Externalizable, Result {
}
}
/**
* Returns true if email is visible to everyone or not.
*
* @return true if email is visible to everyone, false if not.
*/
public boolean isEmailVisible() {
return !getProperties().containsKey(EMAIL_VISIBLE_PROPERTY) || Boolean.valueOf(getProperties().get(EMAIL_VISIBLE_PROPERTY));
}
/**
* Sets if the email is visible to everyone or not.
*
* @param visible true if the email is visible, false if not.
*/
public void setEmailVisible(boolean visible) {
getProperties().put(EMAIL_VISIBLE_PROPERTY, String.valueOf(visible));
}
public Date getCreationDate() {
return creationDate;
}
......@@ -254,7 +302,7 @@ public class User implements Cacheable, Externalizable, Result {
this.creationDate = creationDate;
// Fire event.
Map<String,Object> params = new HashMap<String,Object>();
Map<String, Object> params = new HashMap<String, Object>();
params.put("type", "creationDateModified");
params.put("originalValue", originalCreationDate);
UserEventDispatcher.dispatchEvent(this, UserEventDispatcher.EventType.user_modified,
......@@ -280,7 +328,7 @@ public class User implements Cacheable, Externalizable, Result {
this.modificationDate = modificationDate;
// Fire event.
Map<String,Object> params = new HashMap<String,Object>();
Map<String, Object> params = new HashMap<String, Object>();
params.put("type", "nameModified");
params.put("originalValue", originalModificationDate);
UserEventDispatcher.dispatchEvent(this, UserEventDispatcher.EventType.user_modified,
......@@ -298,7 +346,7 @@ public class User implements Cacheable, Externalizable, Result {
*
* @return the extended properties.
*/
public Map<String,String> getProperties() {
public Map<String, String> getProperties() {
synchronized (this) {
if (properties == null) {
properties = new ConcurrentHashMap<String, String>();
......@@ -352,9 +400,8 @@ public class User implements Cacheable, Externalizable, Result {
return true;
}
if (object != null && object instanceof User) {
return username.equals(((User)object).getUsername());
}
else {
return username.equals(((User) object).getUsername());
} else {
return false;
}
}
......@@ -365,22 +412,21 @@ public class User implements Cacheable, Externalizable, Result {
private class PropertiesMap extends AbstractMap {
public Object put(Object key, Object value) {
Map<String,Object> eventParams = new HashMap<String,Object>();
Map<String, Object> eventParams = new HashMap<String, Object>();
Object answer;
String keyString = (String) key;
synchronized (keyString.intern()) {
if (properties.containsKey(keyString)) {
String originalValue = properties.get(keyString);
answer = properties.put(keyString, (String)value);
updateProperty(keyString, (String)value);
answer = properties.put(keyString, (String) value);
updateProperty(keyString, (String) value);
// Configure event.
eventParams.put("type", "propertyModified");
eventParams.put("propertyKey", key);
eventParams.put("originalValue", originalValue);
}
else {
answer = properties.put(keyString, (String)value);
insertProperty(keyString, (String)value);
} else {
answer = properties.put(keyString, (String) value);
insertProperty(keyString, (String) value);
// Configure event.
eventParams.put("type", "propertyAdded");
eventParams.put("propertyKey", key);
......@@ -417,7 +463,7 @@ public class User implements Cacheable, Externalizable, Result {
}
public Object next() {
current = (Map.Entry)iter.next();
current = (Map.Entry) iter.next();
return current;
}
......@@ -425,15 +471,15 @@ public class User implements Cacheable, Externalizable, Result {
if (current == null) {
throw new IllegalStateException();
}
String key = (String)current.getKey();
String key = (String) current.getKey();
deleteProperty(key);
iter.remove();
// Fire event.
Map<String,Object> params = new HashMap<String,Object>();
Map<String, Object> params = new HashMap<String, Object>();
params.put("type", "propertyDeleted");
params.put("propertyKey", key);
UserEventDispatcher.dispatchEvent(User.this,
UserEventDispatcher.EventType.user_modified, params);
UserEventDispatcher.EventType.user_modified, params);
}
};
}
......@@ -456,10 +502,18 @@ public class User implements Cacheable, Externalizable, Result {
Log.error(sqle);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
try {
if (pstmt != null) pstmt.close();
}
catch (Exception e) {
Log.error(e);
}
try {
if (con != null) con.close();
}
catch (Exception e) {
Log.error(e);
}
}
}
......@@ -478,10 +532,18 @@ public class User implements Cacheable, Externalizable, Result {
Log.error(e);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
try {
if (pstmt != null) pstmt.close();
}
catch (Exception e) {
Log.error(e);
}
try {
if (con != null) con.close();
}
catch (Exception e) {
Log.error(e);
}
}
}
......@@ -500,10 +562,18 @@ public class User implements Cacheable, Externalizable, Result {
Log.error(e);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
try {
if (pstmt != null) pstmt.close();
}
catch (Exception e) {
Log.error(e);
}
try {
if (con != null) con.close();
}
catch (Exception e) {
Log.error(e);
}
}
}
......@@ -521,10 +591,18 @@ public class User implements Cacheable, Externalizable, Result {
Log.error(e);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
try {
if (pstmt != null) pstmt.close();
}
catch (Exception e) {
Log.error(e);
}
try {
if (con != null) con.close();
}
catch (Exception e) {
Log.error(e);
}
}
}
......@@ -548,13 +626,12 @@ public class User implements Cacheable, Externalizable, Result {
creationDate = new Date(ExternalizableUtil.getInstance().readLong(in));
modificationDate = new Date(ExternalizableUtil.getInstance().readLong(in));
}
/*
* (non-Javadoc)
* @see org.jivesoftware.util.resultsetmanager.Result#getUID()
*/
public String getUID()
{
return username;
}
* (non-Javadoc)
* @see org.jivesoftware.util.resultsetmanager.Result#getUID()
*/
public String getUID() {
return username;
}
}
......@@ -22,11 +22,11 @@ import java.util.concurrent.ConcurrentHashMap;
* entities (i.e. users) the {@link User} name is used. For remote entities the following logic
* is used:
* <ol>
* <li>Check if a {@link UserNameProvider} is registered for the entity's domain. If a provider
* was found then use it to get the entity's name</li>
* <li>If no provider was found then retrieve the vCard of the entity and return the name as
* defined in the vCard. <i>This is not implemented yet.</i></li>
* <li>If no vCard was found then return the string representation of the entity's JID.</li>
* <li>Check if a {@link UserNameProvider} is registered for the entity's domain. If a provider
* was found then use it to get the entity's name</li>
* <li>If no provider was found then retrieve the vCard of the entity and return the name as
* defined in the vCard. <i>This is not implemented yet.</i></li>
* <li>If no vCard was found then return the string representation of the entity's JID.</li>
* </ol>
*
* @author Gaston Dombiak
......@@ -72,7 +72,7 @@ public class UserNameManager {
* @param entity the JID of the entity to get its name.
* @return the name of the XMPP entity.
* @throws UserNotFoundException if the jid belongs to the local server but no user was
* found for that jid.
* found for that jid.
*/
public static String getUserName(JID entity) throws UserNotFoundException {
return getUserName(entity, entity.toString());
......@@ -85,19 +85,18 @@ public class UserNameManager {
* the vCard of the entity might be requested and if none was found then a string
* representation of the entity's JID will be returned.
*
* @param entity the JID of the entity to get its name.
* @param entity the JID of the entity to get its name.
* @param defaultName default name to return when no name was found.
* @return the name of the XMPP entity.
* @throws UserNotFoundException if the jid belongs to the local server but no user was
* found for that jid.
* found for that jid.
*/
public static String getUserName(JID entity, String defaultName) throws UserNotFoundException {
if (server.isLocal(entity)) {
// Contact is a local entity so search for his user name
User localUser = UserManager.getInstance().getUser(entity.getNode());
return "".equals(localUser.getName()) ? entity.getNode() : localUser.getName();
}
else {
return !localUser.isNameVisible() || "".equals(localUser.getName()) ? entity.getNode() : localUser.getName();
} else {
UserNameProvider provider = providersByDomain.get(entity.getDomain());
if (provider != null) {
return provider.getUserName(entity);
......
......@@ -40,25 +40,25 @@ import java.io.File;
import java.util.*;
import java.util.Map.Entry;
/**
/**
* Provides support for Jabber Search
* (<a href="http://www.xmpp.org/extensions/xep-0055.html">XEP-0055</a>).<p>
*
* The basic functionality is to query an information repository
* regarding the possible search fields, to send a search query,
* <p/>
* The basic functionality is to query an information repository
* regarding the possible search fields, to send a search query,
* and to receive search results. This implementation was primarily designed to use
* <a href="http://www.xmpp.org/extensions/xep-0004.html">Data Forms</a>, but
* <a href="http://www.xmpp.org/extensions/xep-0004.html">Data Forms</a>, but
* also supports non-dataform searches.
* <p/>
*
*
* @author <a href="mailto:ryan@version2software.com">Ryan Graham</a>
*/
public class SearchPlugin implements Component, Plugin, PropertyEventListener {
public static final String NAMESPACE_JABBER_IQ_SEARCH = "jabber:iq:search";
public static final String NAMESPACE_JABBER_IQ_SEARCH = "jabber:iq:search";
public static final String SERVICENAME = "plugin.search.serviceName";
public static final String SERVICEENABLED = "plugin.search.serviceEnabled";
public static final String EXCLUDEDFIELDS = "plugin.search.excludedFields";
private UserManager userManager;
private ComponentManager componentManager;
private PluginManager pluginManager;
......@@ -66,35 +66,36 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
private String serviceName;
private boolean serviceEnabled;
private Collection<String> exculudedFields;
private static String serverName;
private TreeMap<String, String> fieldLookup = new TreeMap<String, String>(new CaseInsensitiveComparator());
private Map<String, String> reverseFieldLookup = new HashMap<String, String>();
/**
* A list of field names that are valid in jabber:iq:search
*/
public final static Collection<String> validSearchRequestFields = new ArrayList<String>();
static {
validSearchRequestFields.add("first");
validSearchRequestFields.add("last");
validSearchRequestFields.add("nick");
validSearchRequestFields.add("email");
validSearchRequestFields.add("x"); // extended info
// result set management (XEP-0059)
validSearchRequestFields.add("set");
}
/**
* A list of field names that are valid in jabber:iq:search
*/
public final static Collection<String> validSearchRequestFields = new ArrayList<String>();
static {
validSearchRequestFields.add("first");
validSearchRequestFields.add("last");
validSearchRequestFields.add("nick");
validSearchRequestFields.add("email");
validSearchRequestFields.add("x"); // extended info
// result set management (XEP-0059)
validSearchRequestFields.add("set");
}
public SearchPlugin() {
serviceName = JiveGlobals.getProperty(SERVICENAME, "search");
serviceEnabled = JiveGlobals.getBooleanProperty(SERVICEENABLED, true);
exculudedFields = StringUtils.stringToCollection(JiveGlobals.getProperty(EXCLUDEDFIELDS, ""));
serverName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
userManager = UserManager.getInstance();
// Some clients, such as Miranda, are hard-coded to search specific fields,
// so we map those fields to the fields that Openfire actually supports.
fieldLookup.put("jid", "Username");
......@@ -105,34 +106,34 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
fieldLookup.put("name", "Name");
fieldLookup.put("email", "Email");
}
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#getName()
*/
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#getName()
*/
public String getName() {
return pluginManager.getName(this);
}
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#getDescription()
*/
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#getDescription()
*/
public String getDescription() {
return pluginManager.getDescription(this);
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.container.Plugin#initializePlugin(org.jivesoftware.openfire.container.PluginManager,
* java.io.File)
*/
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.container.Plugin#initializePlugin(org.jivesoftware.openfire.container.PluginManager,
* java.io.File)
*/
public void initializePlugin(PluginManager manager, File pluginDirectory) {
pluginManager = manager;
componentManager = ComponentManagerFactory.getComponentManager();
try {
componentManager.addComponent(serviceName, this);
......@@ -142,29 +143,29 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
}
PropertyEventDispatcher.addListener(this);
}
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#initialize(org.xmpp.packet.JID,
* org.xmpp.component.ComponentManager)
*/
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#initialize(org.xmpp.packet.JID,
* org.xmpp.component.ComponentManager)
*/
public void initialize(JID jid, ComponentManager componentManager) {
}
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#start()
*/
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#start()
*/
public void start() {
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.container.Plugin#destroyPlugin()
*/
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.container.Plugin#destroyPlugin()
*/
public void destroyPlugin() {
PropertyEventDispatcher.removeListener(this);
pluginManager = null;
......@@ -185,19 +186,19 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
reverseFieldLookup = null;
}
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#shutdown()
*/
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#shutdown()
*/
public void shutdown() {
}
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#processPacket(org.xmpp.packet.Packet)
*/
/*
* (non-Javadoc)
*
* @see org.xmpp.component.Component#processPacket(org.xmpp.packet.Packet)
*/
public void processPacket(Packet p) {
if (!(p instanceof IQ)) {
return;
......@@ -229,8 +230,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* that <strong>all</strong> IQ request stanza's (type 'get' or 'set') MUST
* be replied to.
*
* @param iq
* The IQ stanza that forms the request.
* @param iq The IQ stanza that forms the request.
* @return The response to the request.
*/
private IQ handleIQRequest(IQ iq) {
......@@ -284,8 +284,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
/**
* Creates a response specific to the search plugin to Disco#Info requests.
*
* @param iq
* The IQ stanza that contains the request.
* @param iq The IQ stanza that contains the request.
* @return An IQ stanza, formulated as an answer to the received request.
*/
private static IQ handleDiscoInfo(IQ iq) {
......@@ -323,15 +322,15 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
}
switch (packet.getType()) {
case get:
return processGetPacket(packet);
case get:
return processGetPacket(packet);
case set:
return processSetPacket(packet);
case set:
return processSetPacket(packet);
default:
// we can safely ignore 'error' and 'result' typed iq stanzas.
return null;
default:
// we can safely ignore 'error' and 'result' typed iq stanzas.
return null;
}
}
......@@ -340,8 +339,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* provided as an argument. The stanza tells the recipient that this service
* is currently unavailable.
*
* @param packet
* The request IQ stanza to which a result will be returned.
* @param packet The request IQ stanza to which a result will be returned.
* @return A result stanza, telling the user that this service is
* unavailable.
*/
......@@ -363,8 +361,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* Processes an IQ stanza of type 'get', which in the context of 'Jabber
* Search' is a request for available search fields.
*
* @param packet
* An IQ stanza of type 'get'
* @param packet An IQ stanza of type 'get'
* @return A result IQ stanza that contains the possbile search fields.
*/
private IQ processGetPacket(IQ packet) {
......@@ -409,7 +406,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
field.setType(FormField.TYPE_BOOLEAN);
field.addValue("1");
field.setLabel(LocaleUtils.getLocalizedString(
"advance.user.search." + searchField.toLowerCase(), "search"));
"advance.user.search." + searchField.toLowerCase(), "search"));
field.setRequired(false);
searchForm.addField(field);
}
......@@ -424,8 +421,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* Processes an IQ stanza of type 'set', which in the context of 'Jabber
* Search' is a search request.
*
* @param packet
* An IQ stanza of type 'get'
* @param packet An IQ stanza of type 'get'
* @return A result IQ stanza that contains the possbile search fields.
*/
private IQ processSetPacket(IQ packet) {
......@@ -497,8 +493,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* <li>if the stanza child element is has valid children itself.</li>
* </ul>
*
* @param iq
* The IQ object that should include a jabber:iq:search request.
* @param iq The IQ object that should include a jabber:iq:search request.
* @return ''true'' if the supplied IQ stanza is a spec compliant search
* request, ''false'' otherwise.
*/
......@@ -553,8 +548,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
/**
* Performs a search based on form data, and returns the search results.
*
* @param incomingForm
* The form containing the search data
* @param incomingForm The form containing the search data
* @return A set of users that matches the search criteria.
*/
private Set<User> performSearch(Element incomingForm) {
......@@ -593,7 +587,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* defined as a set of key->value pairs, where the key denotes a search
* field, and the value contains the value that was filled out by the user
* for that field.
*
* <p/>
* The query can be specified in one of two ways. The first way is a query
* is formed is by filling out any of the the standard search fields. The
* other search method makes use of extended data forms. Search queries that
......@@ -601,8 +595,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* of this last method get forwarded to
* {@link #extractExtendedSearchQuery(Element)}.
*
* @param incomingForm
* The form from which to extract the query
* @param incomingForm The form from which to extract the query
* @return The search query for a particular user search request.
*/
private Hashtable<String, String> extractSearchQuery(Element incomingForm) {
......@@ -637,8 +630,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* specify the search request. This 'extended' way of constructing a search
* request is documented in XEP-0055, chapter 3.
*
* @param incomingForm
* The form from which to extract the query
* @param incomingForm The form from which to extract the query
* @return The search query for a particular user search request.
* @see #extractSearchQuery(Element)
*/
......@@ -677,7 +669,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
/**
* Constructs a query that is returned as an IQ packet that contains the search results.
*
* @param users set of users that will be used to construct the search results
* @param users set of users that will be used to construct the search results
* @param packet the IQ packet sent by the client
* @return the iq packet that contains the search results
*/
......@@ -695,7 +687,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
for (String fieldName : getFilteredSearchFields()) {
field = new XFormFieldImpl(fieldName);
field.setLabel(LocaleUtils.getLocalizedString(
"advance.user.search." + fieldName.toLowerCase(), "search"));
"advance.user.search." + fieldName.toLowerCase(), "search"));
searchResults.addReportedField(field);
}
......@@ -713,11 +705,11 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
items.add(fieldUsername);
XFormFieldImpl fieldName = new XFormFieldImpl(LocaleUtils.getLocalizedString("advance.user.search.name", "search"));
fieldName.addValue(removeNull(user.getName()));
fieldName.addValue((user.isNameVisible() ? removeNull(user.getName()) : ""));
items.add(fieldName);
XFormFieldImpl fieldEmail = new XFormFieldImpl(LocaleUtils.getLocalizedString("advance.user.search.email", "search"));
fieldEmail.addValue(removeNull(user.getEmail()));
fieldEmail.addValue((user.isEmailVisible() ? removeNull(user.getEmail()) : ""));
items.add(fieldEmail);
searchResults.addItemFields(items);
......@@ -734,7 +726,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
/**
* Constructs a query that is returned as an IQ packet that contains the search results.
*
* @param users set of users that will be used to construct the search results
* @param users set of users that will be used to construct the search results
* @param packet the IQ packet sent by the client
* @return the iq packet that contains the search results
*/
......@@ -759,13 +751,13 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
if ("Name".equals(field)) {
Element element = item.addElement(reverseFieldLookup
.get(field));
element.addText(removeNull(user.getName()));
element.addText(user.isNameVisible() ? removeNull(user.getName()) : "");
}
if ("Email".equals(field)) {
Element element = item.addElement(reverseFieldLookup
.get(field));
element.addText(removeNull(user.getEmail()));
element.addText(user.isEmailVisible() ? removeNull(user.getEmail()) : "");
}
}
}
......@@ -781,7 +773,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
public String getServiceName() {
return serviceName;
}
/**
* Sets the service name of this component, which is "search" by default. If the name
* is different than the existing name the plugin will remove itself from the ComponentManager
......@@ -793,125 +785,121 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
changeServiceName(name);
JiveGlobals.setProperty(SERVICENAME, name);
}
/**
* Checks if the search service is enabled.
*
* @return true if search service is enabled.
*/
*
* @return true if search service is enabled.
*/
public boolean getServiceEnabled() {
return serviceEnabled;
}
/**
* Enables or disables the search service. When disabled, when a client tries
* to do a search they will receive an XForm informing that the service is
* unavailable.
*
* @param enabled true if group permission checking should be disabled.
*/
/**
* Enables or disables the search service. When disabled, when a client tries
* to do a search they will receive an XForm informing that the service is
* unavailable.
*
* @param enabled true if group permission checking should be disabled.
*/
public void setServiceEnabled(boolean enabled) {
serviceEnabled = enabled;
JiveGlobals.setProperty(SERVICEENABLED, enabled ? "true" : "false");
}
/**
* Returns the collection of searchable field names that does not include the fields
* listed in the EXCLUDEDFIELDS property list.
*
* @return collection of searchable field names.
* @return collection of searchable field names.
*/
public Collection<String> getFilteredSearchFields() {
Collection<String> searchFields;
// See if the installed provider supports searching. If not, workaround
// by providing our own searching.
try {
searchFields = new ArrayList<String>(userManager.getSearchFields());
}
catch (UnsupportedOperationException uoe) {
// Use a SearchPluginUserManager instead.
searchFields = getSearchPluginUserManagerSearchFields();
}
searchFields.removeAll(exculudedFields);
return searchFields;
Collection<String> searchFields;
// See if the installed provider supports searching. If not, workaround
// by providing our own searching.
try {
searchFields = new ArrayList<String>(userManager.getSearchFields());
}
catch (UnsupportedOperationException uoe) {
// Use a SearchPluginUserManager instead.
searchFields = getSearchPluginUserManagerSearchFields();
}
searchFields.removeAll(exculudedFields);
return searchFields;
}
/**
* Restricts which fields can be searched on and shown to clients. This can be used
* in the case of preventing users email addresses from being revealed as part of
* the search results.
* the search results.
*
* @param exculudedFields fields that can not be searched on or shown to the client
*/
public void setExcludedFields(Collection<String> exculudedFields) {
this.exculudedFields = exculudedFields;
JiveGlobals.setProperty(EXCLUDEDFIELDS, StringUtils.collectionToString(exculudedFields));
this.exculudedFields = exculudedFields;
JiveGlobals.setProperty(EXCLUDEDFIELDS, StringUtils.collectionToString(exculudedFields));
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#propertySet(java.lang.String,
* java.util.Map)
*/
public void propertySet(String property, Map<String, Object> params) {
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#propertySet(java.lang.String,
* java.util.Map)
*/
public void propertySet(String property, Map<String, Object> params) {
if (property.equals(SERVICEENABLED)) {
this.serviceEnabled = Boolean.parseBoolean((String)params.get("value"));
}
else if (property.equals(SERVICENAME)) {
changeServiceName((String)params.get("value"));
}
else if (property.equals(EXCLUDEDFIELDS)) {
exculudedFields = StringUtils.stringToCollection(JiveGlobals.getProperty(EXCLUDEDFIELDS, (String)params.get("value")));
this.serviceEnabled = Boolean.parseBoolean((String) params.get("value"));
} else if (property.equals(SERVICENAME)) {
changeServiceName((String) params.get("value"));
} else if (property.equals(EXCLUDEDFIELDS)) {
exculudedFields = StringUtils.stringToCollection(JiveGlobals.getProperty(EXCLUDEDFIELDS, (String) params.get("value")));
}
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#propertyDeleted(java.lang.String,
* java.util.Map)
*/
public void propertyDeleted(String property, Map<String, Object> params) {
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#propertyDeleted(java.lang.String,
* java.util.Map)
*/
public void propertyDeleted(String property, Map<String, Object> params) {
if (property.equals(SERVICEENABLED)) {
this.serviceEnabled = true;
}
else if (property.equals(SERVICENAME)) {
} else if (property.equals(SERVICENAME)) {
changeServiceName("search");
}
else if (property.equals(EXCLUDEDFIELDS)) {
exculudedFields = new ArrayList<String>();
} else if (property.equals(EXCLUDEDFIELDS)) {
exculudedFields = new ArrayList<String>();
}
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#xmlPropertySet(java.lang.String,
* java.util.Map)
*/
public void xmlPropertySet(String property, Map<String, Object> params) {
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#xmlPropertySet(java.lang.String,
* java.util.Map)
*/
public void xmlPropertySet(String property, Map<String, Object> params) {
// not used
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#xmlPropertyDeleted(java.lang.String,
* java.util.Map)
*/
public void xmlPropertyDeleted(String property, Map<String, Object> params) {
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.PropertyEventListener#xmlPropertyDeleted(java.lang.String,
* java.util.Map)
*/
public void xmlPropertyDeleted(String property, Map<String, Object> params) {
// not used
}
private void changeServiceName(String serviceName) {
if (serviceName == null) {
throw new NullPointerException("Service name cannot be null");
}
if (this.serviceName.equals(serviceName)) {
return;
}
......@@ -923,40 +911,39 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
catch (Exception e) {
componentManager.getLog().error(e);
}
try {
componentManager.addComponent(serviceName, this);
}
catch (Exception e) {
componentManager.getLog().error(e);
}
this.serviceName = serviceName;
}
/**
* Comparator that compares String objects, ignoring capitalization.
*/
/**
* Comparator that compares String objects, ignoring capitalization.
*/
private class CaseInsensitiveComparator implements Comparator<String> {
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);
}
}
/**
* Returns the trimmed argument, or an empty String object of null was
* supplied as an argument.
*
* @param s
* The String to be trimmed.
* @return String object that does not start or end with whitespace
* characters.
*/
/**
* Returns the trimmed argument, or an empty String object of null was
* supplied as an argument.
*
* @param s The String to be trimmed.
* @return String object that does not start or end with whitespace
* characters.
*/
private String removeNull(String s) {
if (s == null) {
return "";
}
return s.trim();
}
......@@ -976,7 +963,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* field name of "email" and query of "jsmith@example.com" would search for
* the user with that email address. Wildcard (*) characters are allowed as
* part of queries.
*
* <p/>
* A possible future improvement would be to have a third parameter that
* sets the maximum number of users returned and/or the number of users
* that are searched.
......@@ -1004,33 +991,30 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
catch (UserNotFoundException e) {
Log.error("Error getting user", e);
}
}
else if (field.equals("Name")) {
if (query.equalsIgnoreCase(user.getName())) {
foundUsers.add(user);
} else if (field.equals("Name")) {
if (user.isNameVisible()) {
if (query.equalsIgnoreCase(user.getName())) {
foundUsers.add(user);
}
}
}
else if (field.equals("Email")) {
if (user.getEmail() != null) {
} else if (field.equals("Email")) {
if (user.isEmailVisible() && user.getEmail() != null) {
if (query.equalsIgnoreCase(user.getEmail())) {
foundUsers.add(user);
}
}
}
}
}
else {
} else {
String prefix = query.substring(0, index);
Collection<User> users = userManager.getUsers();
for (User user : users) {
String userInfo = "";
if (field.equals("Username")) {
userInfo = user.getUsername();
}
else if (field.equals("Name")) {
} else if (field.equals("Name")) {
userInfo = user.getName();
}
else if (field.equals("Email")) {
} else if (field.equals("Email")) {
userInfo = user.getEmail() == null ? "" : user.getEmail();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment