/* * 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.jcr.ext.common; import org.exoplatform.services.jcr.access.AccessControlEntry; import org.exoplatform.services.jcr.access.DynamicIdentity; import org.exoplatform.services.jcr.core.ExtendedSession; import org.exoplatform.services.jcr.core.ManageableRepository; import org.exoplatform.services.jcr.core.SessionLifecycleListener; import org.exoplatform.services.security.ConversationState; import org.exoplatform.services.security.Identity; import org.exoplatform.services.security.IdentityConstants; import org.exoplatform.services.security.MembershipEntry; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import javax.jcr.LoginException; import javax.jcr.NoSuchWorkspaceException; import javax.jcr.RepositoryException; import javax.jcr.Session; /** * Created by The eXo Platform SAS<br> * Provides JCR Session for client program. Usually it is per client thread object Session creates * with Repository.login(..) method and then can be stored in some cache if neccessary. * * @author <a href="mailto:gennady.azarenkov@exoplatform.com">Gennady Azarenkov</a> * @version $Id: SessionProvider.java 34445 2009-07-24 07:51:18Z dkatayev $ * @LevelAPI Platform */ public class SessionProvider implements SessionLifecycleListener { /** * Constant for handlers. */ public final static String SESSION_PROVIDER = "JCRsessionProvider"; /** * Sessions cache. */ private final Map<String, ExtendedSession> cache; /** * System session marker. */ private boolean isSystem; private ManageableRepository currentRepository; private String currentWorkspace; private boolean closed; private ConversationState conversationState; /** * Creates SessionProvider for certain identity. * * @param userState */ public SessionProvider(ConversationState userState) { this(false); if (userState.getAttribute(SESSION_PROVIDER) == null) userState.setAttribute(SESSION_PROVIDER, this); } /** * Creates SessionProvider for a dynamic identity. * * @param membershipEntries the expected memberships */ private SessionProvider(HashSet<MembershipEntry> membershipEntries) { this(false); Identity id = new Identity(DynamicIdentity.DYNAMIC, membershipEntries); this.conversationState = new ConversationState(id); } /** * Internal constructor. * * @param isSystem */ private SessionProvider(boolean isSystem) { this.isSystem = isSystem; this.cache = new HashMap<String, ExtendedSession>(); this.closed = false; } /** * Helper for creating System session provider. * * @return a system session provider */ public static SessionProvider createSystemProvider() { return new SessionProvider(true); } /** * Helper for creating Anonymous session provider. * * @return an anonymous session provider */ public static SessionProvider createAnonimProvider() { Identity id = new Identity(IdentityConstants.ANONIM, new HashSet<MembershipEntry>()); return new SessionProvider(new ConversationState(id)); } /** * Gives a {@link SessionProvider} for a given list of {@link AccessControlEntry}. * * @param accessList list of {@link AccessControlEntry} * @return a {@link SessionProvider} allowing to provide sessions with the * corresponding ACL. */ public static SessionProvider createProvider(List<AccessControlEntry> accessList) { if (accessList == null || accessList.isEmpty()) { return createAnonimProvider(); } else { HashSet<MembershipEntry> membershipEntries = new HashSet<MembershipEntry>(); for (AccessControlEntry ace : accessList) { membershipEntries.add(ace.getMembershipEntry()); } return new SessionProvider(membershipEntries); } } /** * Gets the session from an internal cache if a similar session has already been used * or creates a new session and puts it into the internal cache. * * @param workspaceName the workspace name * @param repository the repository instance * @return a session corresponding to the given repository and workspace * @throws LoginException if an error occurs while trying to login to the workspace * @throws NoSuchWorkspaceException if the requested workspace doesn't exist * @throws RepositoryException if any error occurs */ public synchronized Session getSession(String workspaceName, ManageableRepository repository) throws LoginException, NoSuchWorkspaceException, RepositoryException { if (closed) { throw new IllegalStateException("Session provider already closed"); } if (workspaceName == null) { throw new IllegalArgumentException("Workspace Name is null"); } ExtendedSession session = cache.get(key(repository, workspaceName)); // create and cache new session if (session == null) { if (conversationState != null) { session = (ExtendedSession) repository.getDynamicSession(workspaceName, conversationState.getIdentity() .getMemberships()); } else if (!isSystem) { session = (ExtendedSession)repository.login(workspaceName); } else { session = (ExtendedSession)repository.getSystemSession(workspaceName); } session.registerLifecycleListener(this); cache.put(key(repository, workspaceName), session); } return session; } /** * Calls logout() method for all cached sessions. * * Session will be removed from cache by the listener (this provider) via * ExtendedSession.logout(). */ public synchronized void close() { if (closed) { throw new IllegalStateException("Session provider already closed"); } closed = true; for (ExtendedSession session : (ExtendedSession[])cache.values().toArray( new ExtendedSession[cache.values().size()])) session.logout(); // the cache already empty (logout listener work, see onCloseSession()) // just to be sure cache.clear(); } /* * (non-Javadoc) * @see * org.exoplatform.services.jcr.core.SessionLifecycleListener#onCloseSession(org.exoplatform.services * .jcr.core.ExtendedSession) */ public synchronized void onCloseSession(ExtendedSession session) { this.cache.remove(key((ManageableRepository)session.getRepository(), session.getWorkspace().getName())); } /** * Key generator for sessions cache. * * @param repository the repository instance * @param workspaceName the workspace name * @return */ private String key(ManageableRepository repository, String workspaceName) { String repositoryName = repository.getConfiguration().getName(); return repositoryName + workspaceName; } /** * @return returns the current Repository */ public ManageableRepository getCurrentRepository() { return currentRepository; } /** * @return returns the current Workspace */ public String getCurrentWorkspace() { return currentWorkspace; } /** * Sets the current repository Repository. * @param currentRepository the current repository */ public void setCurrentRepository(ManageableRepository currentRepository) { this.currentRepository = currentRepository; } /** * Sets the current Workspace * @param currentWorkspace the current workspace */ public void setCurrentWorkspace(String currentWorkspace) { this.currentWorkspace = currentWorkspace; } }