OrganizationIntegrationService.java
/*
* Copyright (C) 2003-2007 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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.exoplatform.platform.organization.integration;
import java.util.*;
import javax.jcr.Session;
import org.picocontainer.Startable;
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.container.component.ComponentPlugin;
import org.exoplatform.container.component.ComponentRequestLifecycle;
import org.exoplatform.container.configuration.ConfigurationManager;
import org.exoplatform.container.xml.*;
import org.exoplatform.management.annotations.*;
import org.exoplatform.management.jmx.annotations.NameTemplate;
import org.exoplatform.management.jmx.annotations.Property;
import org.exoplatform.management.rest.annotations.RESTEndpoint;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.organization.*;
import org.exoplatform.services.organization.externalstore.IDMExternalStoreService;
import org.exoplatform.services.organization.idm.PicketLinkIDMCacheService;
import org.exoplatform.services.organization.impl.*;
/**
* This Service create Organization Model profiles, for User and Groups not
* created via eXo OrganizationService.
*
* @deprecated OrganizationIntegrationService is replaced by External Store API
* @author Boubaker KHANFIR
*/
@Deprecated
@Managed
@ManagedDescription("Platform Organization Model Integration Service")
@NameTemplate({ @Property(key = "name", value = "OrganizationIntegrationService"),
@Property(key = "service", value = "extensions"), @Property(key = "type", value = "platform") })
@RESTEndpoint(path = "orgsync")
public class OrganizationIntegrationService implements Startable {
private static final Log LOG =
ExoLogger.getLogger(OrganizationIntegrationService.class);
private static final Comparator<org.exoplatform.container.xml.ComponentPlugin> COMPONENT_PLUGIN_COMPARATOR =
new Comparator<org.exoplatform.container.xml.ComponentPlugin>() {
public int compare(org.exoplatform.container.xml.ComponentPlugin o1,
org.exoplatform.container.xml.ComponentPlugin o2) {
return o1.getPriority()
- o2.getPriority();
}
};
public static final Comparator<Group> GROUP_COMPARATOR =
new Comparator<Group>() {
public int compare(Group o1,
Group o2) {
if (o1.getId()
.contains(o2.getId())) {
return 1;
}
if (o2.getId()
.contains(o1.getId())) {
return -1;
}
return o2.getId()
.compareTo(o1.getId());
}
};
private Map<String, UserEventListener> userDAOListeners_;
private Map<String, GroupEventListener> groupDAOListeners_;
private Map<String, MembershipEventListener> membershipDAOListeners_;
private Map<String, UserProfileEventListener> userProfileListeners_;
private OrganizationService organizationService;
private RepositoryService repositoryService;
private PortalContainer container;
private boolean synchronizeGroups = false;
private PicketLinkIDMCacheService picketLinkIDMCacheService;
private IDMExternalStoreService externalStoreService;
private boolean enabled = true;
public OrganizationIntegrationService(OrganizationService organizationService,
IDMExternalStoreService externalStoreService,
RepositoryService repositoryService,
ConfigurationManager manager,
PortalContainer container,
InitParams initParams,
PicketLinkIDMCacheService picketLinkIDMCacheService) {
LOG.warn("OrganizationIntegrationService is depricated. It was replaced by External Store API.");
this.organizationService = organizationService;
this.repositoryService = repositoryService;
this.container = container;
this.picketLinkIDMCacheService = picketLinkIDMCacheService;
this.externalStoreService = externalStoreService;
userDAOListeners_ = new LinkedHashMap<String, UserEventListener>();
groupDAOListeners_ = new LinkedHashMap<String, GroupEventListener>();
membershipDAOListeners_ = new LinkedHashMap<String, MembershipEventListener>();
userProfileListeners_ = new LinkedHashMap<String, UserProfileEventListener>();
boolean hasExternalComponentPlugins = false;
int nbExternalComponentPlugins = 0;
try {
ExternalComponentPlugins organizationServiceExternalComponentPlugins =
manager.getConfiguration()
.getExternalComponentPlugins(OrganizationIntegrationService.class.getName());
if (organizationServiceExternalComponentPlugins != null
&& organizationServiceExternalComponentPlugins.getComponentPlugins() != null) {
nbExternalComponentPlugins = organizationServiceExternalComponentPlugins.getComponentPlugins().size();
}
Component organizationServiceComponent = manager.getComponent(OrganizationIntegrationService.class);
if (organizationServiceComponent != null && organizationServiceComponent.getComponentPlugins() != null) {
nbExternalComponentPlugins += organizationServiceComponent.getComponentPlugins().size();
}
hasExternalComponentPlugins = (nbExternalComponentPlugins > 0);
} catch (Exception e) {
LOG.error("Test if this component has ExternalComponentPlugins generated an exception", e);
}
if (!hasExternalComponentPlugins) {
try {
ExternalComponentPlugins organizationServiceExternalComponentPlugins =
manager.getConfiguration()
.getExternalComponentPlugins(OrganizationService.class.getName());
addComponentPlugin(organizationServiceExternalComponentPlugins.getComponentPlugins());
Component organizationServiceComponent = manager.getComponent(OrganizationService.class);
List<org.exoplatform.container.xml.ComponentPlugin> organizationServicePlugins =
organizationServiceComponent.getComponentPlugins();
if (organizationServicePlugins != null) {
addComponentPlugin(organizationServicePlugins);
}
} catch (Exception e) {
LOG.error("Failed to add OrganizationService plugins", e);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("This component has already " + nbExternalComponentPlugins + " ExternalComponentPlugins");
}
}
if (initParams != null) {
if (initParams.containsKey("workspace")) {
Util.WORKSPACE = initParams.getValueParam("workspace").getValue();
} else {
LOG.warn("'workspace' init param is empty, use default value: " + Util.WORKSPACE);
}
if (initParams.containsKey("synchronizeGroups")) {
synchronizeGroups = Boolean.parseBoolean(initParams.getValueParam("synchronizeGroups").getValue());
} else {
LOG.warn("'synchronizeGroups' init param is empty, use default value: false");
}
if (initParams.containsKey("homePath")) {
Util.HOME_PATH = initParams.getValueParam("homePath").getValue();
} else {
LOG.warn("'homePath' init param is empty, use default value: " + Util.HOME_PATH);
}
} else {
LOG.warn("init params not set, use default values for 'homePath'[=" + Util.HOME_PATH + "] and 'workspace[=" + Util.WORKSPACE
+ "]'");
}
}
public void start() {
enabled = !externalStoreService.isEnabled();
if (!isEnabled()) {
LOG.warn("ExternalStoreService is enabled, thus OrganizationIntegrationService will be disabled. You can remove the configuration of OrganizationIntegrationService that is deprecated.");
return;
}
Session session = null;
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
Util.init(session);
if (synchronizeGroups) {
// Search for Groups that aren't yet integrated
syncAllGroups(EventType.ADDED.toString());
// Search for Groups that are deleted from Organization Datasource
syncAllGroups(EventType.DELETED.toString());
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
} finally {
if (session != null) {
session.logout();
}
}
}
public void stop() {
}
/**
* Determines whether OrganizationIntegrationService is enabled or not
*
* @return
*/
public boolean isEnabled() {
return enabled;
}
/**
* Add a list of OrganizationService listeners into
* OrganizationIntegrationService
*
* @param plugins List of OrganizationService ComponentPlugins
*/
public void addComponentPlugin(List<org.exoplatform.container.xml.ComponentPlugin> plugins) {
if (plugins == null)
return;
Collections.sort(plugins, COMPONENT_PLUGIN_COMPARATOR);
for (org.exoplatform.container.xml.ComponentPlugin plugin : plugins) {
try {
Class<?> pluginClass = Class.forName(plugin.getType());
ComponentPlugin cplugin = (ComponentPlugin) container.createComponent(pluginClass, plugin.getInitParams());
cplugin.setName(plugin.getName());
cplugin.setDescription(plugin.getDescription());
this.addListenerPlugin(cplugin);
} catch (Exception e) {
LOG.error("Failed to instanciate component plugin " + plugin.getName() + ", type=" + plugin.getClass(), e);
}
}
}
/**
* Add a listener instance to dedicated list of one organization element.
*
* @param listener have to extends UserEventListener, GroupEventListener,
* MembershipEventListener or UserProfileEventListener.
*/
public void addListenerPlugin(ComponentPlugin listener) {
if (listener instanceof OrganizationServiceInitializer) {
return;
} else if (listener instanceof UserEventListener) {
userDAOListeners_.put(listener.getName(), (UserEventListener) listener);
} else if (listener instanceof GroupEventListener) {
groupDAOListeners_.put(listener.getName(), (GroupEventListener) listener);
} else if (listener instanceof MembershipEventListener) {
membershipDAOListeners_.put(listener.getName(), (MembershipEventListener) listener);
} else if (listener instanceof UserProfileEventListener) {
userProfileListeners_.put(listener.getName(), (UserProfileEventListener) listener);
} else {
LOG.warn("Unknown listener type : " + listener.getClass());
}
}
/**
* Apply OrganizationService listeners on all Groups
*/
@Managed
@ManagedDescription("invoke all organization model listeners. Becarefull, this could takes a lot of time.")
@Impact(ImpactType.READ)
public void syncAll() {
if (LOG.isDebugEnabled()) {
LOG.debug("All groups, users, profiles and memberships listeners invocation.");
}
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
startRequest();
LOG.info("The synchronization is started for all LDAP users and groups, eventType: ADDED,DELETED");
try {
if (LOG.isDebugEnabled()) {
LOG.debug(" Search for integrated Groups.");
}
syncAllGroups(EventType.UPDATED.toString());
if (LOG.isDebugEnabled()) {
LOG.debug(" Search for non integrated Groups.");
}
syncAllGroups(EventType.ADDED.toString());
if (LOG.isDebugEnabled()) {
LOG.debug(" Search for deleted Groups, but remain integrated.");
}
syncAllGroups(EventType.DELETED.toString());
if (LOG.isDebugEnabled()) {
LOG.debug(" Search for integrated Users.");
}
syncAllUsers(EventType.UPDATED.toString());
if (LOG.isDebugEnabled()) {
LOG.debug(" Search for non integrated Users.");
}
syncAllUsers(EventType.ADDED.toString());
if (LOG.isDebugEnabled()) {
LOG.debug(" Search for deleted Users, but remain integrated.");
}
syncAllUsers(EventType.DELETED.toString());
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
LOG.info("The synchronization is finished for all LDAP users and groups, eventType: ADDED,DELETED");
endRequest();
}
/**
* Invoke Groups listeners to all Organization Model Elements
*
* @param eventType ADDED/DELETED/UPDATED
* @throws Exception JCR or IDM operation failure
*/
@Managed
@ManagedDescription("invoke all groups listeners")
@Impact(ImpactType.READ)
public void syncAllGroups(@ManagedDescription("Scan for added or deleted groups") @ManagedName("eventType") String eventType) throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("All Groups listeners invocation, operation= " + eventType);
}
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
startRequest();
List<Group> groups = new ArrayList<Group>(organizationService.getGroupHandler().getAllGroups());
// Invoke listeners on groups, starting from parent groups to children
Collections.sort(groups, GROUP_COMPARATOR);
picketLinkIDMCacheService.invalidateAll();
EventType event = EventType.valueOf(eventType);
switch (event) {
case DELETED: {
LOG.info("The synchronization is started for all LDAP groups, eventType: DELETED");
// Invoke delete listeners on groups, starting from children groups
// to parent
Collections.reverse(groups);
// Search for deleted groups, and invoke
// GroupEventListener#preDelete and #postDelete
Session session = null;
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<String> activatedGroups = Util.getActivatedGroups(session);
for (Group group : groups) {
activatedGroups.remove(group.getId());
}
for (String groupId : activatedGroups) {
syncGroup(groupId, eventType);
}
} finally {
if (session != null) {
session.logout();
}
}
LOG.info("The synchronization is finished for all LDAP groups, eventType: DELETED");
break;
}
case UPDATED: {
LOG.info("The synchronization is started for all LDAP groups, eventType: UPDATED");
// Search for added groups that aren't yet integrated
Session session = null;
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<String> activatedGroups = Util.getActivatedGroups(session);
for (String groupId : activatedGroups) {
syncGroup(groupId, eventType);
}
} finally {
if (session != null) {
session.logout();
}
}
LOG.info("The synchronization is finished for all LDAP groups, eventType: UPDATED");
break;
}
case ADDED: {
LOG.info("The synchronization is started for all LDAP groups, eventType: ADDED");
// Search for added groups that aren't yet integrated
Session session = null;
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<String> activatedGroups = Util.getActivatedGroups(session);
for (Group group : groups) {
if (!activatedGroups.contains(group.getId())) {
syncGroup(group.getId(), eventType);
}
}
} finally {
if (session != null) {
session.logout();
}
}
LOG.info("The synchronization is finished for all LDAP groups, eventType: ADDED");
break;
}
}
endRequest();
}
/**
* Apply OrganizationService listeners on a selected group.
*
* @param groupId The group Identifier
* @param eventType ADDED/UPDATED/DELETED
*/
@Managed
@ManagedDescription("invoke a group listeners")
@Impact(ImpactType.READ)
public void syncGroup(@ManagedDescription("Group Id") @ManagedName("groupId") String groupId,
@ManagedDescription("Event type ADDED, UPDATED or DELETED") @ManagedName("eventType") String eventType) {
if (LOG.isDebugEnabled()) {
LOG.debug("\tGroup listeners invocation, operation= " + eventType + ", for group= " + groupId);
}
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
EventType event = EventType.valueOf(eventType);
// Invalidate plidmcache
picketLinkIDMCacheService.invalidateAll();
switch (event) {
case DELETED: {
{
Session session = null;
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<Group> groups = Util.getActivatedChildrenGroup(session, groupId);
Collections.sort(groups, GROUP_COMPARATOR);
Collections.reverse(groups);
for (Group group : groups) {
invokeDeleteGroupListeners(group.getId());
}
invokeDeleteGroupListeners(groupId);
} catch (Exception e) {
LOG.error("Error during recovery of activated chidren group ", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
}
break;
}
case ADDED:
case UPDATED: {
startRequest();
try {
Group group = organizationService.getGroupHandler().findGroupById(groupId);
if (group == null) {
LOG.warn("\t\t" + groupId + " group wasn't found.");
return;
}
invokeListenersToSavedGroup(group, event.equals(EventType.ADDED));
} catch (Exception e) {
LOG.error("\t\t" + "Error occurred while invoking listeners of group: " + groupId, e);
} finally {
endRequest();
}
break;
}
}
}
/**
* Apply all users OrganizationService listeners
*
* @param eventType ADDED/UPDATED/DELETED
*/
@Managed
@ManagedDescription("invoke all users listeners")
@Impact(ImpactType.READ)
public void syncAllUsers(@ManagedDescription("Event type: added/updated/deleted") @ManagedName("eventType") String eventType) {
if (LOG.isDebugEnabled()) {
LOG.debug("All users listeners invocation, eventType = " + eventType);
}
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
EventType event = EventType.valueOf(eventType);
Session session = null;
picketLinkIDMCacheService.invalidateAll();
switch (event) {
case DELETED: {
LOG.info("The synchronization is started for all LDAP users, eventType: DELETED");
if (LOG.isDebugEnabled()) {
LOG.debug("\tSearch for deleted users and invoke related listeners.");
}
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<String> activatedUsers = Util.getActivatedUsers(session);
ListAccess<User> usersListAccess = organizationService.getUserHandler().findAllUsers();
int i = 0;
int k = 0;
while (i <= usersListAccess.getSize()) {
int length = i + 10 <= usersListAccess.getSize() ? 10 : usersListAccess.getSize() - i;
User[] users = usersListAccess.load(i, length);
for (User user : users) {
activatedUsers.remove(user.getUserName());
k++;
if (k % 100 == 0) {
LOG.info(k + " users are checked for deletion");
}
}
i += 10;
}
if (k % 100 != 0) {
LOG.info(k + " users are checked for deletion");
}
for (String username : activatedUsers) {
syncUser(username, eventType);
}
} catch (Exception e) {
LOG.error("\t\tUnknown error occurred while preparing to proceed users deletion", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
LOG.info("The synchronization is finished for all LDAP users, eventType: DELETED");
break;
}
case UPDATED: {
LOG.info("The synchronization is started for all LDAP users, eventType: UPDATED");
if (LOG.isDebugEnabled()) {
LOG.debug("\tAll users update invocation: Search for already existing users in Datasource and that are already integrated.");
}
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<String> activatedUsers = Util.getActivatedUsers(session);
for (String username : activatedUsers) {
syncUser(username, eventType);
}
} catch (Exception e) {
LOG.error("\tUnknown error occurred while preparing to proceed user update", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
LOG.info("The synchronization is finished for all LDAP users, eventType: UPDATED");
break;
}
case ADDED: {
LOG.info("The synchronization is started for all LDAP users, eventType: ADDED");
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<String> activatedUsers = Util.getActivatedUsers(session);
if (LOG.isDebugEnabled()) {
LOG.debug("\tAll new users intagration: Search for already existing users in Datasource but not integrated yet.");
}
ListAccess<User> usersListAccess = organizationService.getUserHandler().findAllUsers();
int i = 0;
int k = 0;
while (i <= usersListAccess.getSize()) {
int length = i + 10 <= usersListAccess.getSize() ? 10 : usersListAccess.getSize() - i;
User[] users = usersListAccess.load(i, length);
for (User user : users) {
if (!activatedUsers.contains(user.getUserName())) {
syncUser(user.getUserName(), eventType);
}
k++;
if (k % 100 == 0) {
LOG.info(k + " users are checked for addition");
}
}
i += 10;
}
if (k % 100 != 0) {
LOG.info(k + " users are checked for addition");
}
} catch (Exception e) {
LOG.error("\tUnknown error occurred while preparing to proceed user update", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
LOG.info("The synchronization is finished for all LDAP users, eventType: ADDED");
break;
}
}
}
/**
* Apply OrganizationService listeners on selected User
*
* @param username The user name
* @param eventType ADDED/UPDATED/DELETED
*/
@SuppressWarnings("deprecation")
@Managed
@ManagedDescription("invoke a user listeners")
@Impact(ImpactType.READ)
public void syncUser(@ManagedDescription("User name") @ManagedName("username") String username,
@ManagedDescription("Event type") @ManagedName("eventType") String eventType) {
if (LOG.isDebugEnabled()) {
LOG.debug("\tUser listeners invocation, operation= " + eventType + ", for user= " + username);
}
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
EventType event = EventType.valueOf(eventType);
// Invalidate plidmcache
picketLinkIDMCacheService.invalidateAll();
switch (event) {
case DELETED: {
User user = null;
startRequest();
try {
user = organizationService.getUserHandler().findUserByName(username);
} catch (Exception e) {
LOG.warn("\t\tError occurred while verifying if user is present in Datasource. The operation will be interrupted.", e);
return;
} finally {
endRequest();
}
if (user != null) {
LOG.warn("\t\tUser exists: can't invoke delete listeners on the existant user : " + username);
return;
}
invokeUserMembershipsListeners(username, event);
invokeUserProfileListeners(username, event);
Session session = null;
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
if (Util.hasUserFolder(session, username)) {
LOG.info("Invoke user deletion: " + username);
user = new UserImpl(username);
Collection<UserEventListener> userDAOListeners = userDAOListeners_.values();
for (UserEventListener userEventListener : userDAOListeners) {
startRequest();
try {
userEventListener.preDelete(user);
} catch (Exception e) {
LOG.error("\t\tFailed to call preDelete on " + username + " User with listener : " + userEventListener.getClass(),
e);
} finally {
endRequest();
}
startRequest();
try {
userEventListener.postDelete(user);
} catch (Exception e) {
LOG.error("\t\tFailed to call postDelete on " + username + " User with listener : " + userEventListener.getClass(),
e);
} finally {
endRequest();
}
}
}
} catch (Exception e) {
LOG.error("\t\tFailed to delete " + username + " User", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
case ADDED:
case UPDATED: {
Session session = null;
startRequest();
try {
boolean isNew = event.equals(EventType.ADDED);
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
if (!isNew || !Util.hasUserFolder(session, username)) {
User user = organizationService.getUserHandler().findUserByName(username);
if (user == null) {
LOG.info("\t\tFailed to synchronize " + username + " : Doesn't exist ");
break;
}
if (user.getCreatedDate() == null) {
user.setCreatedDate(new Date());
}
LOG.info("Invoke " + username + " user synchronization ");
Collection<UserEventListener> userDAOListeners = userDAOListeners_.values();
for (UserEventListener userEventListener : userDAOListeners) {
startRequest();
try {
userEventListener.preSave(user, isNew);
} catch (Exception e) {
LOG.warn("\t\tFailed to call preSave for " + username + " User with listener : " + userEventListener.getClass(), e);
} finally {
endRequest();
}
}
for (UserEventListener userEventListener : userDAOListeners) {
try {
startRequest();
userEventListener.postSave(user, isNew);
} catch (Exception e) {
LOG.warn("\t\tFailed to call postSave for " + username + " User with listener : " + userEventListener.getClass(),
e);
} finally {
endRequest();
}
}
}
} catch (Exception e) {
LOG.warn("\t\tFailed to call listeners for " + username + " User", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
invokeUserProfileListeners(username, event);
invokeUserMembershipsListeners(username, event);
break;
}
}
}
/**
* Apply OrganizationService listeners on selected User
*
* @param username The user name
*/
@Managed
@ManagedDescription("Test if User is synhronized")
@Impact(ImpactType.READ)
public String isUserSync(@ManagedDescription("User name") @ManagedName("username") String username) throws Exception {
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
Session session = null;
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
return "" + Util.hasUserFolder(session, username);
} finally {
if (session != null) {
session.logout();
}
}
}
/**
* trigger ADD,UPDATE or DELETE membership listeners. The membership is
* identified by the username, groupId and membershipType.
*
* @param username
* @param groupId
* @param eventType
*/
@Managed
@ManagedDescription("invoke a membership listeners")
@Impact(ImpactType.READ)
public void syncMembership(@ManagedDescription("User name") @ManagedName("username") String username,
@ManagedDescription("group identifier") @ManagedName("groupId") String groupId,
@ManagedDescription("event type") @ManagedName("eventType") String eventType) {
if (LOG.isDebugEnabled()) {
LOG.debug("Memberships listeners invocation, operation= " + eventType + ", for membership=" + username + ":" + groupId);
}
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
EventType event = EventType.valueOf(eventType);
switch (event) {
case DELETED: {
Session session = null;
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<Membership> activatedMemberships = Util.getActivatedMembershipsRelatedToUser(session, username);
// Select memberships with given username and groupId
int i = 0;
while (i < activatedMemberships.size()) {
Membership membership = activatedMemberships.get(i);
if (membership.getGroupId().equals(groupId)) {
activatedMemberships.remove(i);
} else {
i++;
}
}
if (activatedMemberships.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("No integrated memberships was found for user: " + username + ", and group = " + groupId);
}
return;
}
List<Membership> memberships = null;
try {
memberships = (List<Membership>) organizationService.getMembershipHandler().findMembershipsByUserAndGroup(username,
groupId);
} catch (Exception e) {
LOG.error("\t\tError occurred while verifying if membership is present in Datasource or not. This may not cause a problem :"
+ e.getMessage());
}
if (memberships == null) {
memberships = new ArrayList<Membership>();
}
for (Membership membership : activatedMemberships) {
if (!contains(membership, memberships)) {
invokeMembershipListeners(username, groupId, membership.getMembershipType(), event);
}
}
} catch (Exception e) {
LOG.error("\t\tUnknown error occurred while preparing to proceed membership deletion", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
case ADDED:
case UPDATED: {
boolean isNew = EventType.ADDED.equals(event);
Session session = null;
startRequest();
try {
List<Membership> memberships = null;
try {
memberships = (List<Membership>) organizationService.getMembershipHandler().findMembershipsByUserAndGroup(username,
groupId);
} catch (Exception e) {
LOG.error("\t\tError occurred while verifying if membership is present in Datasource or not. This may not cause a problem :"
+ e.getMessage());
}
if (memberships == null || memberships.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("No integrated memberships was found for user: " + username + ", and group = " + groupId);
}
return;
}
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<Membership> activatedMemberships = Util.getActivatedMembershipsRelatedToUser(session, username);
// Select memberships with given username and groupId
int i = 0;
while (i < activatedMemberships.size()) {
Membership membership = activatedMemberships.get(i);
if (membership.getGroupId().equals(groupId)) {
activatedMemberships.remove(i);
} else {
i++;
}
}
if (!isNew && activatedMemberships.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("No integrated memberships was found for user: " + username + ", abd group = " + groupId);
}
return;
}
for (Membership membership : memberships) {
if (isNew) {
if (!contains(membership, activatedMemberships)) {
invokeMembershipListeners(username, groupId, membership.getMembershipType(), event);
}
} else {
if (contains(membership, activatedMemberships)) {
invokeMembershipListeners(username, groupId, membership.getMembershipType(), event);
}
}
}
} catch (Exception e) {
LOG.error("\t\tUnknown error occurred while preparing to proceed membership deletion", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
}
}
private void invokeMembershipListeners(String username, String groupId, String membershipType, EventType eventType) {
if (LOG.isDebugEnabled()) {
LOG.debug("\tMembership listeners invocation, operation= " + eventType + ", for membership= " + membershipType + ":"
+ username + ":" + groupId);
}
if (!isEnabled()) {
throw new IllegalStateException("OrganizationIntegrationService is disabled");
}
switch (eventType) {
case DELETED: {
startRequest();
try {
Membership membership = null;
try {
membership = organizationService.getMembershipHandler().findMembershipByUserGroupAndType(username,
groupId,
membershipType);
} catch (Exception e) {
LOG.warn("\t\tError occurred while verifying if membership is present in Datasource or not. This may not cause a problem :"
+ e.getMessage());
} finally {
endRequest();
}
if (membership != null) {
LOG.warn("\t\tMembership exists: can't invoke delete listeners on the existant membership : " + membership.getId());
return;
}
{
membership = new MembershipImpl();
((MembershipImpl) membership).setGroupId(groupId);
((MembershipImpl) membership).setUserName(username);
((MembershipImpl) membership).setMembershipType(membershipType);
((MembershipImpl) membership).setId(Util.computeId(membership));
}
try {
LOG.info("Invoke " + membership.getId() + " Membership deletion listeners.");
Collection<MembershipEventListener> membershipDAOListeners = membershipDAOListeners_.values();
for (MembershipEventListener membershipEventListener : membershipDAOListeners) {
startRequest();
try {
membershipEventListener.preDelete(membership);
} catch (Exception e) {
LOG.error("\t\tFailed to call preDelete on " + username + " Membership (" + membership.getId() + ") listener = "
+ membershipEventListener.getClass(), e);
} finally {
endRequest();
}
startRequest();
try {
membershipEventListener.postDelete(membership);
} catch (Exception e) {
LOG.error("\t\tFailed to call postDelete on " + username + " Membership (" + membership.getId() + ") listener = "
+ membershipEventListener.getClass(), e);
} finally {
endRequest();
}
}
} catch (Exception e) {
LOG.error("\t\tFailed to call listeners on Membership (" + membership.getId() + ")", e);
}
} catch (Exception e) {
LOG.error("\t\tUnknown error occurred while preparing to proceed membership deletion", e);
} finally {
endRequest();
}
break;
}
case ADDED:
case UPDATED: {
boolean isNew = EventType.ADDED.equals(eventType);
Session session = null;
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
Membership membership = organizationService.getMembershipHandler()
.findMembershipByUserGroupAndType(username, groupId, membershipType);
try {
if (!Util.hasGroupFolder(session, groupId)) {
syncGroup(groupId, EventType.ADDED.toString());
}
if (!Util.hasUserFolder(session, username)) {
syncUser(username, EventType.ADDED.toString());
}
if (membership != null && (!isNew || !Util.hasMembershipFolder(session, membership))) {
LOG.info("Invoke " + membership.getId() + " Membership synchronization.");
Collection<MembershipEventListener> membershipDAOListeners = membershipDAOListeners_.values();
for (MembershipEventListener membershipEventListener : membershipDAOListeners) {
startRequest();
try {
membershipEventListener.preSave(membership, isNew);
} catch (Exception e) {
LOG.error("\t\tFailed to call preSave on Membership (" + membership.getId() + ",isNew = " + isNew
+ ") listener = " + membershipEventListener.getClass(), e);
} finally {
endRequest();
}
startRequest();
try {
membershipEventListener.postSave(membership, isNew);
} catch (Exception e) {
LOG.error("\t\tFailed to call postSave on Membership (" + membership.getId() + ") listener = "
+ membershipEventListener.getClass(), e);
} finally {
endRequest();
}
}
}
} catch (Exception e) {
LOG.error("\t\tFailed to call listeners on Membership (" + membership.getId() + ")", e);
}
} catch (Exception e) {
LOG.error("\t\tFailed to call listeners on " + username + " Memberships listeners", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
}
}
private void invokeDeleteGroupListeners(String groupId) {
try {
Group group = organizationService.getGroupHandler().findGroupById(groupId);
if (group != null) {
LOG.warn("\t\tGroup exists: can't invoke delete listeners on the existant group : " + groupId);
return;
}
} catch (Exception exception) {
LOG.error("\t\tException while trying to get a group instance with id : " + groupId
+ ", it may has been already synchronized:" + exception.getMessage());
}
Session session = null;
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
if (!Util.hasGroupFolder(session, groupId)) {
if (LOG.isDebugEnabled()) {
LOG.debug("\t\tGroup doesn't exist or has been already deleted.");
}
return;
}
List<Membership> memberships = Util.getActivatedMembershipsRelatedToGroup(session, groupId);
for (Membership membership : memberships) {
// Memberships could be managed internally in eXo Datasource,
// so synchronize with the remote Datasources by removing all
// memberships of deleted group
Membership tmpMembership = organizationService.getMembershipHandler().removeMembership(membership.getId(), true);
if (tmpMembership == null) { // if the Membership doesn't exist
// in datasource, then it's not
// deleted, and so listeners
// aren't triggered, in this case
// force the listeners execution
invokeMembershipListeners(membership.getUserName(),
membership.getGroupId(),
membership.getMembershipType(),
EventType.DELETED);
}
}
} catch (Exception exception) {
LOG.error("\t\tCouldn't process deletion of Memberships related to the group : " + groupId, exception);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
GroupImpl group = new GroupImpl(groupId);
group.setId(groupId);
Collection<GroupEventListener> groupDAOListeners = groupDAOListeners_.values();
LOG.info("Invoke " + groupId + " Group deletion listeners.");
for (GroupEventListener groupEventListener : groupDAOListeners) {
try {
groupEventListener.preDelete(group);
} catch (Exception e) {
LOG.warn("\t\tFailed to call preDelete on " + group.getId() + " Group, listener = " + groupEventListener.getClass(), e);
}
try {
groupEventListener.postDelete(group);
} catch (Exception e) {
LOG.warn("\t\tFailed to call postDelete on " + group.getId() + " Group, listener = " + groupEventListener.getClass(), e);
}
}
}
private void invokeUserMembershipsListeners(String username, EventType eventType) {
if (LOG.isDebugEnabled()) {
LOG.debug("\t\tMemberships listeners invocation, operation= " + eventType + ", for user= " + username);
}
switch (eventType) {
case DELETED: {
Session session = null;
startRequest();
try {
Collection<?> userMemberships = null;
try {
userMemberships = organizationService.getMembershipHandler().removeMembershipByUser(username, true);
} catch (Exception exception) {
LOG.error("\t\t\tCouldn't process deletion of Memberships related to the user : " + username, exception);
}
if (userMemberships != null) {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
List<Membership> memberships = Util.getActivatedMembershipsRelatedToUser(session, username);
for (Membership membership : memberships) {
invokeMembershipListeners(username, membership.getGroupId(), membership.getMembershipType(), eventType);
}
} else { // Delete all related Memberships
LOG.error("\t\t\tUser " + username + " was deleted, but some memberships are always existing : " + userMemberships);
}
} catch (Exception e) {
LOG.error("\t\t\tUnknown error occurred while preparing to proceed membership deletion", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
case ADDED:
case UPDATED: {
boolean isNew = EventType.ADDED.equals(eventType);
Session session = null;
Collection<?> memberships = null;
List<Membership> activatedMemberships = null;
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
memberships = organizationService.getMembershipHandler().findMembershipsByUser(username);
activatedMemberships = Util.getActivatedMembershipsRelatedToUser(session, username);
for (Object membershipObject : memberships) {
Membership membership = (Membership) membershipObject;
boolean isAlreadyIntegrated = contains(membership, activatedMemberships);
if (isNew) {
if (!isAlreadyIntegrated) {
invokeMembershipListeners(username, membership.getGroupId(), membership.getMembershipType(), eventType);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("\t\t\t" + membership.getId() + " Membership is already integrated");
}
}
} else {
if (isAlreadyIntegrated) {
invokeMembershipListeners(username, membership.getGroupId(), membership.getMembershipType(), eventType);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("\t\t\t" + membership.getId()
+ " Membership is not yet added, add invoke listeners with parameter isNew=true");
}
invokeMembershipListeners(username, membership.getGroupId(), membership.getMembershipType(), EventType.ADDED);
}
}
}
} catch (Exception e) {
LOG.error("\t\t\tFailed to call Membership listeners for user : " + username, e);
throw new IllegalStateException(e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
}
}
private boolean contains(Membership membership, List<Membership> activatedMemberships) {
if (membership == null || activatedMemberships == null || activatedMemberships.size() == 0) {
return false;
}
for (Membership tmpMembership : activatedMemberships) {
if (tmpMembership.getId().equals(membership.getId())) {
return true;
}
}
return false;
}
private void invokeUserProfileListeners(String username, EventType eventType) {
if (LOG.isDebugEnabled()) {
LOG.debug("\t\tProfile listeners invocation, operation= " + eventType + ", for user= " + username);
}
switch (eventType) {
case ADDED:
case UPDATED: {
Session session = null;
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
boolean isNew = EventType.ADDED.equals(eventType);
UserProfile userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
if (userProfile == null) {
userProfile = organizationService.getUserProfileHandler().createUserProfileInstance(username);
organizationService.getUserProfileHandler().saveUserProfile(userProfile, isNew);
userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
}
if (!isNew || !Util.hasProfileFolder(session, username)) {
LOG.info("Invoke " + username + " user profile synchronization.");
Collection<UserProfileEventListener> userProfileListeners = userProfileListeners_.values();
for (UserProfileEventListener userProfileEventListener : userProfileListeners) {
if (userProfile.getUserInfoMap() == null) {
userProfile.setUserInfoMap(new HashMap<String, String>());
}
startRequest();
try {
userProfileEventListener.preSave(userProfile, isNew);
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call preSave on " + username + " User profile with listener : "
+ userProfileEventListener.getClass(), e);
} finally {
endRequest();
}
startRequest();
try {
userProfileEventListener.postSave(userProfile, isNew);
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call postSave on " + username + " User profile with listener : "
+ userProfileEventListener.getClass(), e);
} finally {
endRequest();
}
}
}
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call listeners on " + username + " User profile", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
case DELETED: {
Session session = null;
startRequest();
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
UserProfile userProfile = null;
try {
userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
} catch (Exception e) {
LOG.warn("\t\t\tError occurred while verifying if userProfile is present in Datasource or not. This may not cause a problem :"
+ e.getMessage());
} finally {
endRequest();
}
startRequest();
if (userProfile != null) {
organizationService.getUserProfileHandler().removeUserProfile(username, true);
} else if (Util.hasProfileFolder(session, username)) {
LOG.info("Invoke " + username + " user profile deletion listeners.");
userProfile = new UserProfileImpl(username);
userProfile.setUserInfoMap(new HashMap<String, String>());
Collection<UserProfileEventListener> userProfileListeners = userProfileListeners_.values();
for (UserProfileEventListener userProfileEventListener : userProfileListeners) {
startRequest();
try {
userProfileEventListener.preDelete(userProfile);
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call preSave on " + username + " User profile with listener : "
+ userProfileEventListener.getClass(), e);
} finally {
endRequest();
}
startRequest();
try {
userProfileEventListener.postDelete(userProfile);
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call postSave on " + username + " User profile with listener : "
+ userProfileEventListener.getClass(), e);
} finally {
endRequest();
}
}
}
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call listeners on " + username + " User profile", e);
} finally {
endRequest();
if (session != null) {
session.logout();
}
}
break;
}
}
}
private void invokeListenersToSavedGroup(Group group, boolean isNew) {
Session session = null;
try {
session = repositoryService.getCurrentRepository().getSystemSession(Util.WORKSPACE);
if (group.getParentId() != null && !group.getParentId().isEmpty()) {
try {
Group parentGroup = organizationService.getGroupHandler().findGroupById(group.getParentId());
invokeListenersToSavedGroup(parentGroup, isNew);
} catch (Exception e) {
LOG.warn("\t\tError occurred while attempting to get parent of " + group.getId()
+ " Group. Listeners will not be applied on parent " + group.getParentId(), e);
}
}
if (!isNew || !Util.hasGroupFolder(session, group.getId())) {
LOG.info("Invoke " + group.getId() + " Group save listeners.");
Collection<GroupEventListener> groupDAOListeners = groupDAOListeners_.values();
for (GroupEventListener groupEventListener : groupDAOListeners) {
try {
groupEventListener.preSave(group, isNew);
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call preSave on " + group.getId() + " Group, listener = " + groupEventListener.getClass(),
e);
}
try {
groupEventListener.postSave(group, isNew);
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call postSave on " + group.getId() + " Group, listener = " + groupEventListener.getClass(),
e);
}
}
}
} catch (Exception e) {
LOG.warn("\t\t\tFailed to call listeners for " + group.getId() + " Group.", e);
} finally {
if (session != null) {
session.logout();
}
}
}
private void endRequest() {
if (organizationService instanceof ComponentRequestLifecycle) {
try {
((ComponentRequestLifecycle) organizationService).endRequest(container);
} catch (Exception e) {
LOG.warn("Error while committing and rollbacking transaction, see below for root cause", e);
}
}
}
private void startRequest() {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).startRequest(container);
}
}
}