X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=security%2Fruntime%2Forg.argeo.security.ldap%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fsecurity%2Fldap%2Fjcr%2FJcrLdapSynchronizer.java;h=08c985c3b750577f09fe404f2a6ad6a5b39afc28;hb=bb2a2889333068de0168669adb6c11b545b9c5aa;hp=178785602d5aa7eff0ad8d5583c39210f0350fb0;hpb=2c4852dcd20d4cde88776c527ae935f242ae1e77;p=lgpl%2Fargeo-commons.git diff --git a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java index 178785602..08c985c3b 100644 --- a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java +++ b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2012 Mathieu Baudier + * Copyright (C) 2007-2012 Argeo GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.argeo.security.ldap.jcr; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -27,31 +26,15 @@ import java.util.SortedSet; import javax.jcr.Node; import javax.jcr.NodeIterator; -import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; -import javax.jcr.observation.Event; -import javax.jcr.observation.EventIterator; -import javax.jcr.observation.EventListener; import javax.jcr.query.Query; import javax.jcr.version.VersionManager; -import javax.naming.Binding; import javax.naming.Name; -import javax.naming.NamingException; import javax.naming.directory.BasicAttribute; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; -import javax.naming.directory.SearchControls; -import javax.naming.event.EventDirContext; -import javax.naming.event.NamespaceChangeListener; -import javax.naming.event.NamingEvent; -import javax.naming.event.NamingExceptionEvent; -import javax.naming.event.NamingListener; -import javax.naming.event.ObjectChangeListener; -import javax.naming.ldap.UnsolicitedNotification; -import javax.naming.ldap.UnsolicitedNotificationEvent; -import javax.naming.ldap.UnsolicitedNotificationListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -59,9 +42,10 @@ import org.argeo.ArgeoException; import org.argeo.jcr.ArgeoNames; import org.argeo.jcr.ArgeoTypes; import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.security.SecurityJcrUtils; +import org.argeo.security.SecurityUtils; +import org.argeo.security.jcr.JcrSecurityModel; import org.argeo.security.jcr.JcrUserDetails; -import org.springframework.ldap.core.ContextExecutor; +import org.argeo.security.jcr.SimpleJcrSecurityModel; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DirContextOperations; @@ -73,7 +57,7 @@ import org.springframework.security.providers.encoding.PasswordEncoder; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.ldap.UserDetailsContextMapper; -/** Guarantees that LDAP and JCR are in line. */ +/** Makes sure that LDAP and JCR are in line. */ public class JcrLdapSynchronizer implements UserDetailsContextMapper, ArgeoNames { private final static Log log = LogFactory.getLog(JcrLdapSynchronizer.class); @@ -86,28 +70,28 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, * "http://forum.springsource.org/showthread.php?55955-Persistent-search-with-spring-ldap" * >this */ - private LdapTemplate rawLdapTemplate; + // private LdapTemplate rawLdapTemplate; private String userBase; private String usernameAttribute; private String passwordAttribute; private String[] userClasses; + // private String defaultUserRole ="ROLE_USER"; - private NamingListener ldapUserListener; - private SearchControls subTreeSearchControls; + // private NamingListener ldapUserListener; + // private SearchControls subTreeSearchControls; private LdapUsernameToDnMapper usernameMapper; private PasswordEncoder passwordEncoder; private final Random random; // JCR - /** Admin session on the security workspace */ - private Session securitySession; + /** Admin session on the main workspace */ + private Session nodeSession; private Repository repository; - private String securityWorkspace = "security"; - - private JcrProfileListener jcrProfileListener; + // private JcrProfileListener jcrProfileListener; + private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel(); // Mapping private Map propertyToAttributes = new HashMap(); @@ -118,60 +102,70 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, public void init() { try { - securitySession = repository.login(securityWorkspace); - - synchronize(); - - // LDAP - subTreeSearchControls = new SearchControls(); - subTreeSearchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - // LDAP listener - ldapUserListener = new LdapUserListener(); - rawLdapTemplate.executeReadOnly(new ContextExecutor() { - public Object executeWithContext(DirContext ctx) - throws NamingException { - EventDirContext ectx = (EventDirContext) ctx.lookup(""); - ectx.addNamingListener(userBase, "(" + usernameAttribute - + "=*)", subTreeSearchControls, ldapUserListener); - return null; - } - }); + nodeSession = repository.login(); + + // TODO put this in a different thread, and poll the LDAP server + // until it is up + try { + synchronize(); + + // LDAP + // subTreeSearchControls = new SearchControls(); + // subTreeSearchControls + // .setSearchScope(SearchControls.SUBTREE_SCOPE); + // LDAP listener + // ldapUserListener = new LdapUserListener(); + // rawLdapTemplate.executeReadOnly(new ContextExecutor() { + // public Object executeWithContext(DirContext ctx) + // throws NamingException { + // EventDirContext ectx = (EventDirContext) ctx.lookup(""); + // ectx.addNamingListener(userBase, "(" + // + usernameAttribute + "=*)", + // subTreeSearchControls, ldapUserListener); + // return null; + // } + // }); + } catch (Exception e) { + log.error("Could not synchronize and listen to LDAP," + + " probably because the LDAP server is not available." + + " Restart the system as soon as possible.", e); + } // JCR - String[] nodeTypes = { ArgeoTypes.ARGEO_USER_PROFILE }; - jcrProfileListener = new JcrProfileListener(); + // String[] nodeTypes = { ArgeoTypes.ARGEO_USER_PROFILE }; + // jcrProfileListener = new JcrProfileListener(); // noLocal is used so that we are not notified when we modify JCR // from LDAP - securitySession - .getWorkspace() - .getObservationManager() - .addEventListener(jcrProfileListener, - Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/", - true, null, nodeTypes, true); + // nodeSession + // .getWorkspace() + // .getObservationManager() + // .addEventListener(jcrProfileListener, + // Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/", + // true, null, nodeTypes, true); } catch (Exception e) { - JcrUtils.logoutQuietly(securitySession); + JcrUtils.logoutQuietly(nodeSession); throw new ArgeoException("Cannot initialize LDAP/JCR synchronizer", e); } } public void destroy() { - JcrUtils.removeListenerQuietly(securitySession, jcrProfileListener); - JcrUtils.logoutQuietly(securitySession); - try { - rawLdapTemplate.executeReadOnly(new ContextExecutor() { - public Object executeWithContext(DirContext ctx) - throws NamingException { - EventDirContext ectx = (EventDirContext) ctx.lookup(""); - ectx.removeNamingListener(ldapUserListener); - return null; - } - }); - } catch (Exception e) { - // silent (LDAP server may have been shutdown already) - if (log.isTraceEnabled()) - log.trace("Cannot remove LDAP listener", e); - } + // JcrUtils.removeListenerQuietly(nodeSession, jcrProfileListener); + JcrUtils.logoutQuietly(nodeSession); + // try { + // rawLdapTemplate.executeReadOnly(new ContextExecutor() { + // public Object executeWithContext(DirContext ctx) + // throws NamingException { + // EventDirContext ectx = (EventDirContext) ctx.lookup(""); + // ectx.removeNamingListener(ldapUserListener); + // return null; + // } + // }); + // } catch (Exception e) { + // // silent (LDAP server may have been shutdown already) + // if (log.isTraceEnabled()) + // log.trace("Cannot remove LDAP listener", e); + // } } /* @@ -186,12 +180,20 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, List userPaths = (List) ldapTemplate.listBindings( userBaseName, new ContextMapper() { public Object mapFromContext(Object ctxObj) { - return mapLdapToJcr((DirContextAdapter) ctxObj); + try { + return mapLdapToJcr((DirContextAdapter) ctxObj); + } catch (Exception e) { + // do not break process because of error + log.error( + "Could not LDAP->JCR synchronize user " + + ctxObj, e); + return null; + } } }); - // disable accounts which are not in LDAP - Query query = securitySession + // create accounts which are not in LDAP + Query query = nodeSession .getWorkspace() .getQueryManager() .createQuery( @@ -201,35 +203,74 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, while (it.hasNext()) { Node userProfile = it.nextNode(); String path = userProfile.getPath(); - if (!userPaths.contains(path)) { - log.warn("Path " - + path - + " not found in LDAP, disabling user " - + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID) - .getString()); - VersionManager versionManager = securitySession - .getWorkspace().getVersionManager(); - versionManager.checkout(userProfile.getPath()); - userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, false); - securitySession.save(); - versionManager.checkin(userProfile.getPath()); + try { + if (!userPaths.contains(path)) { + String username = userProfile + .getProperty(ARGEO_USER_ID).getString(); + // GrantedAuthority[] authorities = {new + // GrantedAuthorityImpl(defaultUserRole)}; + GrantedAuthority[] authorities = {}; + JcrUserDetails userDetails = new JcrUserDetails( + userProfile, username, authorities); + String dn = createLdapUser(userDetails); + log.warn("Created ldap entry '" + dn + "' for user '" + + username + "'"); + + // if(!userProfile.getProperty(ARGEO_ENABLED).getBoolean()){ + // continue profiles; + // } + // + // log.warn("Path " + // + path + // + " not found in LDAP, disabling user " + // + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID) + // .getString()); + + // Temporary hack to repair previous behaviour + if (!userProfile.getProperty(ARGEO_ENABLED) + .getBoolean()) { + VersionManager versionManager = nodeSession + .getWorkspace().getVersionManager(); + versionManager.checkout(userProfile.getPath()); + userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, + true); + nodeSession.save(); + versionManager.checkin(userProfile.getPath()); + } + } + } catch (Exception e) { + log.error("Cannot process " + path, e); } } } catch (Exception e) { - JcrUtils.discardQuietly(securitySession); - throw new ArgeoException("Cannot synchronized LDAP and JCR", e); + JcrUtils.discardQuietly(nodeSession); + log.error("Cannot synchronize LDAP and JCR", e); + // throw new ArgeoException("Cannot synchronize LDAP and JCR", e); } } + private String createLdapUser(UserDetails user) { + DirContextAdapter ctx = new DirContextAdapter(); + mapUserToContext(user, ctx); + DistinguishedName dn = usernameMapper.buildDn(user.getUsername()); + ldapTemplate.bind(dn, ctx, null); + return dn.toString(); + } + /** Called during authentication in order to retrieve user details */ public UserDetails mapUserFromContext(final DirContextOperations ctx, final String username, GrantedAuthority[] authorities) { - log.debug("mapUserFromContext"); if (ctx == null) throw new ArgeoException("No LDAP information for user " + username); - Node userProfile = SecurityJcrUtils.createUserProfileIfNeeded(securitySession, - username); - JcrUserDetails.checkAccountStatus(userProfile); + + String ldapUsername = ctx.getStringAttribute(usernameAttribute); + if (!ldapUsername.equals(username)) + throw new ArgeoException("Logged in with username " + username + + " but LDAP user is " + ldapUsername); + + Node userProfile = jcrSecurityModel.sync(nodeSession, username, + SecurityUtils.authoritiesToStringList(authorities)); + // JcrUserDetails.checkAccountStatus(userProfile); // password SortedSet passwordAttributes = ctx @@ -258,50 +299,16 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, * @return path to user profile */ protected synchronized String mapLdapToJcr(DirContextAdapter ctx) { - Session session = securitySession; + Session session = nodeSession; try { // process String username = ctx.getStringAttribute(usernameAttribute); - Node userHome = SecurityJcrUtils.createUserHomeIfNeeded(session, username); - Node userProfile; // = userHome.getNode(ARGEO_PROFILE); - if (userHome.hasNode(ARGEO_PROFILE)) { - userProfile = userHome.getNode(ARGEO_PROFILE); - - // compatibility with legacy, will be removed - if (!userProfile.hasProperty(ARGEO_ENABLED)) { - session.getWorkspace().getVersionManager() - .checkout(userProfile.getPath()); - userProfile.setProperty(ARGEO_ENABLED, true); - userProfile.setProperty(ARGEO_ACCOUNT_NON_EXPIRED, true); - userProfile.setProperty(ARGEO_ACCOUNT_NON_LOCKED, true); - userProfile - .setProperty(ARGEO_CREDENTIALS_NON_EXPIRED, true); - session.save(); - session.getWorkspace().getVersionManager() - .checkin(userProfile.getPath()); - } - } else { - userProfile = SecurityJcrUtils.createUserProfile(securitySession, - username); - userProfile.getSession().save(); - userProfile.getSession().getWorkspace().getVersionManager() - .checkin(userProfile.getPath()); - } + Node userProfile = jcrSecurityModel.sync(session, username, null); Map modifications = new HashMap(); for (String jcrProperty : propertyToAttributes.keySet()) ldapToJcr(userProfile, jcrProperty, ctx, modifications); - // assign default values - // if (!userProfile.hasProperty(Property.JCR_DESCRIPTION) - // && !modifications.containsKey(Property.JCR_DESCRIPTION)) - // modifications.put(Property.JCR_DESCRIPTION, ""); - // if (!userProfile.hasProperty(Property.JCR_TITLE)) - // modifications.put(Property.JCR_TITLE, - // userProfile.getProperty(ARGEO_FIRST_NAME).getString() - // + " " - // + userProfile.getProperty(ARGEO_LAST_NAME) - // .getString()); int modifCount = modifications.size(); if (modifCount > 0) { session.getWorkspace().getVersionManager() @@ -338,11 +345,6 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, + jcrProperty); String value = ctx.getStringAttribute(ldapAttribute); - // if (value == null && Property.JCR_TITLE.equals(jcrProperty)) - // value = ""; - // if (value == null && - // Property.JCR_DESCRIPTION.equals(jcrProperty)) - // value = ""; String jcrValue = userProfile.hasProperty(jcrProperty) ? userProfile .getProperty(jcrProperty).getString() : null; if (value != null && jcrValue != null) { @@ -375,8 +377,9 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, final JcrUserDetails jcrUserDetails = (JcrUserDetails) user; try { - Node userProfile = securitySession.getNode( - jcrUserDetails.getHomePath()).getNode(ARGEO_PROFILE); + Node userProfile = nodeSession + .getNode(jcrUserDetails.getHomePath()).getNode( + ARGEO_PROFILE); for (String jcrProperty : propertyToAttributes.keySet()) { if (userProfile.hasProperty(jcrProperty)) { ModificationItem mi = jcrToLdap(jcrProperty, userProfile @@ -450,17 +453,13 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, } public void setRawLdapTemplate(LdapTemplate rawLdapTemplate) { - this.rawLdapTemplate = rawLdapTemplate; + // this.rawLdapTemplate = rawLdapTemplate; } public void setRepository(Repository repository) { this.repository = repository; } - public void setSecurityWorkspace(String securityWorkspace) { - this.securityWorkspace = securityWorkspace; - } - public void setUserBase(String userBase) { this.userBase = userBase; } @@ -489,125 +488,130 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper, this.passwordEncoder = passwordEncoder; } - /** Listen to LDAP */ - class LdapUserListener implements ObjectChangeListener, - NamespaceChangeListener, UnsolicitedNotificationListener { - - public void namingExceptionThrown(NamingExceptionEvent evt) { - evt.getException().printStackTrace(); - } - - public void objectChanged(NamingEvent evt) { - Binding user = evt.getNewBinding(); - // TODO find a way not to be called when JCR is the source of the - // modification - DirContextAdapter ctx = (DirContextAdapter) ldapTemplate - .lookup(user.getName()); - mapLdapToJcr(ctx); - } - - public void objectAdded(NamingEvent evt) { - Binding user = evt.getNewBinding(); - DirContextAdapter ctx = (DirContextAdapter) ldapTemplate - .lookup(user.getName()); - mapLdapToJcr(ctx); - } - - public void objectRemoved(NamingEvent evt) { - if (log.isDebugEnabled()) - log.debug(evt); - } - - public void objectRenamed(NamingEvent evt) { - if (log.isDebugEnabled()) - log.debug(evt); - } - - public void notificationReceived(UnsolicitedNotificationEvent evt) { - UnsolicitedNotification notification = evt.getNotification(); - NamingException ne = notification.getException(); - String msg = "LDAP notification " + "ID=" + notification.getID() - + ", referrals=" + notification.getReferrals(); - if (ne != null) { - if (log.isTraceEnabled()) - log.trace(msg + ", exception= " + ne, ne); - else - log.warn(msg + ", exception= " + ne); - } else if (log.isDebugEnabled()) { - log.debug("Unsollicited LDAP notification " + msg); - } - } - + public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { + this.jcrSecurityModel = jcrSecurityModel; } - /** Listen to JCR */ - class JcrProfileListener implements EventListener { - - public void onEvent(EventIterator events) { - try { - final Map> modifications = new HashMap>(); - while (events.hasNext()) { - Event event = events.nextEvent(); - try { - if (Event.PROPERTY_CHANGED == event.getType()) { - Property property = (Property) securitySession - .getItem(event.getPath()); - String propertyName = property.getName(); - Node userProfile = property.getParent(); - String username = userProfile.getProperty( - ARGEO_USER_ID).getString(); - if (propertyToAttributes.containsKey(propertyName)) { - Name name = usernameMapper.buildDn(username); - if (!modifications.containsKey(name)) - modifications.put(name, - new ArrayList()); - String value = property.getString(); - ModificationItem mi = jcrToLdap(propertyName, - value); - if (mi != null) - modifications.get(name).add(mi); - } - } else if (Event.NODE_ADDED == event.getType()) { - Node userProfile = securitySession.getNode(event - .getPath()); - String username = userProfile.getProperty( - ARGEO_USER_ID).getString(); - Name name = usernameMapper.buildDn(username); - for (String propertyName : propertyToAttributes - .keySet()) { - if (!modifications.containsKey(name)) - modifications.put(name, - new ArrayList()); - String value = userProfile.getProperty( - propertyName).getString(); - ModificationItem mi = jcrToLdap(propertyName, - value); - if (mi != null) - modifications.get(name).add(mi); - } - } - } catch (RepositoryException e) { - throw new ArgeoException("Cannot process event " - + event, e); - } - } - - for (Name name : modifications.keySet()) { - List userModifs = modifications.get(name); - int modifCount = userModifs.size(); - ldapTemplate.modifyAttributes(name, userModifs - .toArray(new ModificationItem[modifCount])); - if (log.isDebugEnabled()) - log.debug("Mapped " + modifCount + " JCR modification" - + (modifCount == 1 ? "" : "s") + " to " + name); - } - } catch (Exception e) { - // if (log.isDebugEnabled()) - // e.printStackTrace(); - throw new ArgeoException("Cannot process JCR events (" - + e.getMessage() + ")", e); - } - } + /** Listen to LDAP */ + // class LdapUserListener implements ObjectChangeListener, + // NamespaceChangeListener, UnsolicitedNotificationListener { + // + // public void namingExceptionThrown(NamingExceptionEvent evt) { + // evt.getException().printStackTrace(); + // } + // + // public void objectChanged(NamingEvent evt) { + // Binding user = evt.getNewBinding(); + // // TODO find a way not to be called when JCR is the source of the + // // modification + // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate + // .lookup(user.getName()); + // mapLdapToJcr(ctx); + // } + // + // public void objectAdded(NamingEvent evt) { + // Binding user = evt.getNewBinding(); + // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate + // .lookup(user.getName()); + // mapLdapToJcr(ctx); + // } + // + // public void objectRemoved(NamingEvent evt) { + // if (log.isDebugEnabled()) + // log.debug(evt); + // } + // + // public void objectRenamed(NamingEvent evt) { + // if (log.isDebugEnabled()) + // log.debug(evt); + // } + // + // public void notificationReceived(UnsolicitedNotificationEvent evt) { + // UnsolicitedNotification notification = evt.getNotification(); + // NamingException ne = notification.getException(); + // String msg = "LDAP notification " + "ID=" + notification.getID() + // + ", referrals=" + notification.getReferrals(); + // if (ne != null) { + // if (log.isTraceEnabled()) + // log.trace(msg + ", exception= " + ne, ne); + // else + // log.warn(msg + ", exception= " + ne); + // } else if (log.isDebugEnabled()) { + // log.debug("Unsollicited LDAP notification " + msg); + // } + // } + // + // } - } + /** Listen to JCR */ + // class JcrProfileListener implements EventListener { + // + // public void onEvent(EventIterator events) { + // try { + // final Map> modifications = new HashMap>(); + // while (events.hasNext()) { + // Event event = events.nextEvent(); + // try { + // if (Event.PROPERTY_CHANGED == event.getType()) { + // Property property = (Property) nodeSession + // .getItem(event.getPath()); + // String propertyName = property.getName(); + // Node userProfile = property.getParent(); + // String username = userProfile.getProperty( + // ARGEO_USER_ID).getString(); + // if (propertyToAttributes.containsKey(propertyName)) { + // Name name = usernameMapper.buildDn(username); + // if (!modifications.containsKey(name)) + // modifications.put(name, + // new ArrayList()); + // String value = property.getString(); + // ModificationItem mi = jcrToLdap(propertyName, + // value); + // if (mi != null) + // modifications.get(name).add(mi); + // } + // } else if (Event.NODE_ADDED == event.getType()) { + // Node userProfile = nodeSession.getNode(event + // .getPath()); + // String username = userProfile.getProperty( + // ARGEO_USER_ID).getString(); + // Name name = usernameMapper.buildDn(username); + // for (String propertyName : propertyToAttributes + // .keySet()) { + // if (!modifications.containsKey(name)) + // modifications.put(name, + // new ArrayList()); + // String value = userProfile.getProperty( + // propertyName).getString(); + // ModificationItem mi = jcrToLdap(propertyName, + // value); + // if (mi != null) + // modifications.get(name).add(mi); + // } + // } + // } catch (RepositoryException e) { + // throw new ArgeoException("Cannot process event " + // + event, e); + // } + // } + // + // for (Name name : modifications.keySet()) { + // List userModifs = modifications.get(name); + // int modifCount = userModifs.size(); + // ldapTemplate.modifyAttributes(name, userModifs + // .toArray(new ModificationItem[modifCount])); + // if (log.isDebugEnabled()) + // log.debug("Mapped " + modifCount + " JCR modification" + // + (modifCount == 1 ? "" : "s") + " to " + name); + // } + // } catch (Exception e) { + // // if (log.isDebugEnabled()) + // // e.printStackTrace(); + // throw new ArgeoException("Cannot process JCR events (" + // + e.getMessage() + ")", e); + // } + // } + // + // } }