/* * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Quentin Lamerand <qlamerand@nuxeo.com> */ package org.nuxeo.ecm.user.center.profile; import static org.nuxeo.ecm.core.api.security.SecurityConstants.ADD_CHILDREN; import static org.nuxeo.ecm.core.api.security.SecurityConstants.EVERYONE; import static org.nuxeo.ecm.core.api.security.SecurityConstants.READ; import static org.nuxeo.ecm.user.center.profile.UserProfileConstants.USER_PROFILE_DOCTYPE; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.DocumentRef; import org.nuxeo.ecm.core.api.IdRef; import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; import org.nuxeo.ecm.core.api.security.ACE; import org.nuxeo.ecm.core.api.security.ACL; import org.nuxeo.ecm.core.api.security.ACP; import org.nuxeo.ecm.core.work.api.WorkManager; import org.nuxeo.ecm.core.work.api.WorkManager.Scheduling; import org.nuxeo.ecm.platform.userworkspace.api.UserWorkspaceService; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.model.ComponentContext; import org.nuxeo.runtime.model.ComponentInstance; import org.nuxeo.runtime.model.DefaultComponent; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; /** * Implementation of {@code UserProfileService}. * * @see UserProfileService * @author <a href="mailto:qlamerand@nuxeo.com">Quentin Lamerand</a> * @since 5.5 */ public class UserProfileServiceImpl extends DefaultComponent implements UserProfileService { private static final Log log = LogFactory.getLog(UserProfileServiceImpl.class); protected static final Integer CACHE_CONCURRENCY_LEVEL = 10; protected static final Integer CACHE_TIMEOUT = 10; protected static final Integer CACHE_MAXIMUM_SIZE = 1000; public static final String CONFIG_EP = "config"; private ImporterConfig config; private UserWorkspaceService userWorkspaceService; protected final Cache<String, String> profileUidCache = CacheBuilder.newBuilder().concurrencyLevel( CACHE_CONCURRENCY_LEVEL).maximumSize(CACHE_MAXIMUM_SIZE).expireAfterWrite(CACHE_TIMEOUT, TimeUnit.MINUTES).build(); @Override public DocumentModel getUserProfileDocument(CoreSession session) { DocumentModel userWorkspace = getUserWorkspaceService().getCurrentUserPersonalWorkspace(session, null); if (userWorkspace == null) { return null; } String uid = profileUidCache.getIfPresent(session.getPrincipal().getName()); final IdRef ref = new IdRef(uid); if (uid != null && session.exists(ref)) { return session.getDocument(ref); } else { DocumentModel profile = new UserProfileDocumentGetter(session, userWorkspace).getOrCreate(); profileUidCache.put(session.getPrincipal().getName(), profile.getId()); return profile; } } @Override public DocumentModel getUserProfileDocument(String userName, CoreSession session) { DocumentModel userWorkspace = getUserWorkspaceService().getUserPersonalWorkspace(userName, session.getRootDocument()); if (userWorkspace == null) { return null; } String uid = profileUidCache.getIfPresent(userName); final IdRef ref = new IdRef(uid); if (uid != null && session.exists(ref)) { return session.getDocument(ref); } else { DocumentModel profile = new UserProfileDocumentGetter(session, userWorkspace).getOrCreate(); profileUidCache.put(userName, profile.getId()); return profile; } } @Override public DocumentModel getUserProfile(DocumentModel userModel, CoreSession session) { DocumentModel userProfileDoc = getUserProfileDocument(userModel.getId(), session); if (userProfileDoc == null) { return null; } userProfileDoc.detach(true); userProfileDoc.getDataModels().putAll(userModel.getDataModels()); return userProfileDoc; } private UserWorkspaceService getUserWorkspaceService() { if (userWorkspaceService == null) { userWorkspaceService = Framework.getLocalService(UserWorkspaceService.class); } return userWorkspaceService; } private class UserProfileDocumentGetter extends UnrestrictedSessionRunner { private DocumentModel userWorkspace; private DocumentRef userProfileDocRef; public UserProfileDocumentGetter(CoreSession session, DocumentModel userWorkspace) { super(session); this.userWorkspace = userWorkspace; } @Override public void run() { String query = "select * from " + USER_PROFILE_DOCTYPE + " where ecm:parentId='" + userWorkspace.getId() + "' " + " AND ecm:isProxy = 0 " + " AND ecm:isCheckedInVersion = 0 AND ecm:currentLifeCycleState != 'deleted'"; DocumentModelList children = session.query(query); if (!children.isEmpty()) { userProfileDocRef = children.get(0).getRef(); } else { DocumentModel userProfileDoc = session.createDocumentModel(userWorkspace.getPathAsString(), String.valueOf(System.currentTimeMillis()), USER_PROFILE_DOCTYPE); userProfileDoc = session.createDocument(userProfileDoc); userProfileDocRef = userProfileDoc.getRef(); ACP acp = session.getACP(userProfileDocRef); ACL acl = acp.getOrCreateACL(); acl.add(new ACE(EVERYONE, READ, true)); acp.addACL(acl); session.setACP(userProfileDocRef, acp, true); session.save(); } } public DocumentModel getOrCreate() { if (session.hasPermission(userWorkspace.getRef(), ADD_CHILDREN)) { run(); } else { runUnrestricted(); } return session.getDocument(userProfileDocRef); } } @Override public void clearCache() { profileUidCache.invalidateAll(); } @Override public ImporterConfig getImporterConfig() { return config; } @Override public void applicationStarted(ComponentContext context) { if (config == null || config.getDataFileName() == null) { return; } WorkManager wm = Framework.getService(WorkManager.class); if (wm!=null) { wm.schedule(new UserProfileImporterWork(), Scheduling.IF_NOT_RUNNING_OR_SCHEDULED, true); } } @Override public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { if (CONFIG_EP.equals(extensionPoint)) { if (config != null) { log.warn("Overriding existing user profile importer config"); } config = (ImporterConfig) contribution; } } @Override public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { if (CONFIG_EP.equals(extensionPoint)) { if (config != null && config.equals(contribution)) { config = null; } } } }