diff --git a/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/tag/fn/Functions.java b/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/tag/fn/Functions.java
index 2390bb8..2a26940 100644
--- a/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/tag/fn/Functions.java
+++ b/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/tag/fn/Functions.java
@@ -29,6 +29,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -43,18 +44,26 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.nuxeo.common.utils.i18n.I18NUtils;
 import org.nuxeo.ecm.core.api.ClientException;
+import org.nuxeo.ecm.core.api.DataModel;
+import org.nuxeo.ecm.core.api.DocumentModel;
 import org.nuxeo.ecm.core.api.NuxeoGroup;
 import org.nuxeo.ecm.core.api.NuxeoPrincipal;
 import org.nuxeo.ecm.core.api.security.SecurityConstants;
+import org.nuxeo.ecm.directory.Session;
+import org.nuxeo.ecm.directory.api.DirectoryService;
 import org.nuxeo.ecm.platform.ui.web.rest.RestHelper;
 import org.nuxeo.ecm.platform.ui.web.rest.api.URLPolicyService;
 import org.nuxeo.ecm.platform.ui.web.util.BaseURL;
 import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils;
 import org.nuxeo.ecm.platform.url.DocumentViewImpl;
 import org.nuxeo.ecm.platform.url.api.DocumentView;
+import org.nuxeo.ecm.platform.usermanager.UserConfig;
 import org.nuxeo.ecm.platform.usermanager.UserManager;
 import org.nuxeo.runtime.api.Framework;
 
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
 /**
  * Util functions.
  *
@@ -239,6 +248,10 @@ public final class Functions {
         return userManager;
     }
 
+    protected static Cache<String, String>  userNamesCache = CacheBuilder.newBuilder().concurrencyLevel(
+            10).maximumSize(5000).expireAfterWrite(
+                    10, TimeUnit.MINUTES).build();
+    
     /**
      * Returns the full name of a user, or its username if user if not found.
      * <p>
@@ -252,39 +265,45 @@ public final class Functions {
             return username;
         }
 
-        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
-
         // empty user name is current user
         if (StringUtils.isBlank(username)) {
             return null;
         }
         // check cache
-        Map<String, Object> session = externalContext.getSessionMap();
-        Map<String, String> fullNames = (Map<String, String>) session.get(FULLNAMES_MAP_KEY);
-        if (fullNames != null && fullNames.containsKey(username)) {
-            return fullNames.get(username);
+        String fullName;        
+        
+        fullName = userNamesCache.getIfPresent(username);
+        if (fullName != null ) {
+            return fullName;
         }
         // compute full name
-        String fullName;
+        
+        String dname = getUserManager().getUserDirectoryName();                           
+        Session dirSession = Framework.getService(DirectoryService.class).open(dname);
         try {
-            NuxeoPrincipal principal = getUserManager().getPrincipal(username);
-            if (principal != null) {
-                fullName = principalFullName(principal);
+            DocumentModel entry = dirSession.getEntry(username, false);
+            if (entry==null) {
+                // virtual user ?
+                NuxeoPrincipal principal = getUserManager().getPrincipal(username);
+                if (principal!=null) {
+                    return principalFullName(principal);
+                } else {
+                    return username;
+                }
             } else {
-                fullName = username;
+                DataModel model = entry.getDataModel(getUserManager().getUserSchemaName());
+                String first = (String) model.getData(UserConfig.DEFAULT.firstNameKey);
+                String last = (String) model.getData(UserConfig.DEFAULT.lastNameKey);
+                fullName =  userDisplayName(username, first, last);
             }
-        } catch (ClientException e) {
-            fullName = username;
-        }
+        } finally {
+            dirSession.close();
+        }            
         // put in cache
-        if (fullNames == null) {
-            fullNames = new HashMap<String, String>();
-            session.put(FULLNAMES_MAP_KEY, fullNames);
-        }
-        fullNames.put(username, fullName);
+        userNamesCache.put(username, fullName);
         return fullName;
     }
-
+    
     /**
      * Returns the full name of a group from his id
      *
