/**
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.services.organization.idm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.naming.InvalidNameException;
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.organization.UserHandler;
import org.exoplatform.services.organization.UserProfile;
import org.exoplatform.services.organization.UserProfileEventListener;
import org.exoplatform.services.organization.UserProfileHandler;
import org.exoplatform.services.organization.UserStatus;
import org.exoplatform.services.organization.impl.UserProfileImpl;
import org.picketlink.idm.api.Attribute;
import org.picketlink.idm.api.IdentitySession;
import org.picketlink.idm.impl.api.SimpleAttribute;
/*
* @author <a href="mailto:boleslaw.dawidowicz at redhat.com">Boleslaw Dawidowicz</a>
*/
public class UserProfileDAOImpl extends AbstractDAOImpl implements UserProfileHandler {
private static UserProfile NOT_FOUND = new UserProfileImpl();
private List<UserProfileEventListener> listeners_;
public UserProfileDAOImpl(PicketLinkIDMOrganizationServiceImpl orgService, PicketLinkIDMService service) {
super(orgService, service);
listeners_ = new ArrayList<UserProfileEventListener>(3);
}
public void addUserProfileEventListener(UserProfileEventListener listener) {
if (listener == null) {
throw new IllegalArgumentException("Listener cannot be null");
}
listeners_.add(listener);
}
public void removeUserProfileEventListener(UserProfileEventListener listener) {
if (listener == null) {
throw new IllegalArgumentException("Listener cannot be null");
}
listeners_.remove(listener);
}
public final UserProfile createUserProfileInstance() {
return new UserProfileImpl();
}
public UserProfile createUserProfileInstance(String userName) {
return new UserProfileImpl(userName);
}
// void createUserProfileEntry(UserProfile up, IdentitySession session) throws Exception
// {
// UserProfileData upd = new UserProfileData();
// upd.setUserProfile(up);
// session.save(upd);
// session.flush();
// cache_.remove(up.getUserName());
// }
public void saveUserProfile(UserProfile profile, boolean broadcast) throws Exception {
// We need to check if userProfile exists, because organization API is limited and it doesn't have separate methods for
// "creation" and for "update" of user profile :/
String username = profile.getUserName();
UserHandler userHandler = this.orgService.getUserHandler();
User user = userHandler.findUserByName(username, UserStatus.ANY);
if(user == null) {
throw new InvalidNameException("User " + username + " not exists");
}
boolean isNew = true;
if (broadcast) {
UserProfile found = getProfile(profile.getUserName());
isNew = found == null;
}
if (broadcast) {
preSave(profile, isNew);
}
setProfile(profile.getUserName(), profile);
if (broadcast) {
postSave(profile, isNew);
}
}
public UserProfile removeUserProfile(String userName, boolean broadcast) throws Exception {
UserProfile profile = getProfile(userName);
if (profile != null) {
try {
if (broadcast) {
preDelete(profile);
}
removeProfile(userName, profile);
if (broadcast) {
postDelete(profile);
}
return profile;
} catch (Exception exp) {
handleException("Exception occured when removing user profile", exp);
return null;
}
}
return null;
}
public UserProfile findUserProfileByName(String userName) throws Exception {
org.picketlink.idm.api.User foundUser = null;
try {
foundUser = getIdentitySession().getPersistenceManager().findUser(userName);
} catch (IllegalArgumentException e) {
// Don't rethrow the exception to be compatible with other Org Service implementations
log.debug("Can NOT find any user with username is NULL");
} catch (Exception e) {
// TODO:
handleException("Identity operation error: ", e);
}
if (foundUser == null) {
return null;
}
UserProfile up = getProfile(userName);
//
if (up == null) {
up = NOT_FOUND;
}
// Just to avoid to return a shared object between many threads
// that would not be thread safe nor corrct
if (up == NOT_FOUND) {
// julien : integration bug fix
// Return an empty profile to avoid NPE in portal
// Should clarify what do do (maybe portal should care about returned value)
/*UserProfileImpl profile = new UserProfileImpl();
profile.setUserName(userName);
return profile;*/
//Return NULL as TCK suppose
return null;
} else {
return up;
}
}
public Collection findUserProfiles() throws Exception {
List<UserProfile> profiles = new LinkedList<UserProfile>();
UserHandler userHandler = this.orgService.getUserHandler();
//This should find enabled user
ListAccess<User> users = userHandler.findAllUsers();
int size = users.getSize();
for(User u : users.load(0, size)) {
UserProfile profile = this.getProfile(u.getUserName());
if(profile != null) {
profiles.add(profile);
}
}
return profiles;
}
private void preSave(UserProfile profile, boolean isNew) throws Exception {
for (UserProfileEventListener listener : listeners_) {
listener.preSave(profile, isNew);
}
}
private void postSave(UserProfile profile, boolean isNew) throws Exception {
for (UserProfileEventListener listener : listeners_) {
listener.postSave(profile, isNew);
}
}
private void preDelete(UserProfile profile) throws Exception {
for (UserProfileEventListener listener : listeners_) {
listener.preDelete(profile);
}
}
private void postDelete(UserProfile profile) throws Exception {
for (UserProfileEventListener listener : listeners_) {
listener.postDelete(profile);
}
}
public UserProfile getProfile(String userName) {
Object u = null;
try {
u = getIdentitySession().getPersistenceManager().findUser(userName);
} catch (IllegalArgumentException e) {
// Don't rethrow the exception to be compatible with other Org Service implementations
log.debug("Can NOT find any user with username is NULL");
} catch (Exception e) {
// TODO:
handleException("Identity operation error: ", e);
}
if (u == null) {
return null;
}
Map<String, Attribute> attrs = new HashMap();
try {
attrs = getIdentitySession().getAttributesManager().getAttributes(userName);
} catch (Exception e) {
// TODO:
handleException("Identity operation error: ", e);
}
if (attrs == null || attrs.isEmpty()) {
return null;
}
Map<String, String> filteredAttrs = new HashMap<String, String>();
for (String key : attrs.keySet()) {
// Check if attribute is part of User interface data
if (!UserDAOImpl.USER_NON_PROFILE_KEYS.contains(key)) {
Object value = attrs.get(key).getValue();
if (value != null) {
filteredAttrs.put(key, value.toString());
} else {
filteredAttrs.put(key, null);
}
}
}
if (filteredAttrs.isEmpty()) {
return null;
}
UserProfile profile = new UserProfileImpl(userName, filteredAttrs);
return profile;
}
public void setProfile(String userName, UserProfile profile) {
Map<String, String> profileAttrs = profile.getUserInfoMap();
Set<Attribute> attrs = new HashSet<Attribute>();
for (Map.Entry<String, String> entry : profileAttrs.entrySet()) {
String attrValue = entry.getValue();
// Treat empty strings as null (needed for compatibility with Oracle as Oracle always treats empty strings as null)
if ("".equals(attrValue)) {
attrValue = null;
}
attrs.add(new SimpleAttribute(entry.getKey(), attrValue));
}
Attribute[] attrArray = new Attribute[attrs.size()];
attrArray = attrs.toArray(attrArray);
try {
getIdentitySession().getAttributesManager().updateAttributes(userName, attrArray);
} catch (Exception e) {
// TODO:
handleException("Identity operation error: ", e);
}
}
public void removeProfile(String userName, UserProfile profile) {
Map<String, String> profileAttrs = profile.getUserInfoMap();
String[] attrKeys = new String[profileAttrs.keySet().size()];
attrKeys = profileAttrs.keySet().toArray(attrKeys);
try {
getIdentitySession().getAttributesManager().removeAttributes(userName, attrKeys);
} catch (Exception e) {
// TODO:
handleException("Identity operation error: ", e);
}
}
}