001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.web.jcr; 017 018import java.util.Collections; 019import java.util.Enumeration; 020import java.util.HashMap; 021import java.util.Iterator; 022import java.util.Map; 023import java.util.ServiceLoader; 024import java.util.Set; 025import javax.jcr.Repository; 026import javax.jcr.RepositoryException; 027import javax.jcr.Session; 028import javax.servlet.ServletContext; 029import javax.servlet.http.HttpServletRequest; 030import org.modeshape.common.annotation.ThreadSafe; 031import org.modeshape.common.util.CheckArg; 032import org.modeshape.jcr.api.Logger; 033import org.modeshape.jcr.api.RepositoriesContainer; 034import org.modeshape.jcr.api.ServletCredentials; 035 036/** 037 * Manager for accessing JCR Repository instances. This manager uses the idiomatic way to find JCR Repository (and ModeShape 038 * Repositories) instances via the {@link ServiceLoader} and {@link org.modeshape.jcr.api.RepositoriesContainer} mechanism. 039 */ 040@ThreadSafe 041public class RepositoryManager { 042 043 private static final Logger LOGGER = WebLogger.getLogger(RepositoryManager.class); 044 private static final Map<String, Object> factoryParams = new HashMap<String, Object>(); 045 046 private static RepositoriesContainer repositoriesContainer; 047 048 private RepositoryManager() { 049 } 050 051 /** 052 * Initializes the repository factory. For more details, please see the {@link RepositoryManager class-level documentation}. 053 * 054 * @param context the servlet context; may not be null 055 * @see RepositoryManager 056 */ 057 static synchronized void initialize( ServletContext context ) { 058 CheckArg.isNotNull(context, "context"); 059 loadFactoryParameters(context); 060 loadRepositoriesContainer(); 061 } 062 063 private static void loadRepositoriesContainer() { 064 Iterator<RepositoriesContainer> containersIterator = ServiceLoader.load(RepositoriesContainer.class).iterator(); 065 if (!containersIterator.hasNext()) { 066 throw new IllegalStateException( 067 WebJcrI18n.repositoriesContainerNotFoundInClasspath.text(RepositoriesContainer.class.getName())); 068 } 069 //there shouldn't be more than 1 container 070 repositoriesContainer = containersIterator.next(); 071 } 072 073 private static void loadFactoryParameters( ServletContext context ) { 074 factoryParams.clear(); 075 Enumeration<?> names = context.getInitParameterNames(); 076 if (names == null) { 077 addParameter(RepositoriesContainer.URL, context); 078 addParameter(RepositoriesContainer.REPOSITORY_NAME, context); 079 } else { 080 while (names.hasMoreElements()) { 081 Object next = names.nextElement(); 082 if (next == null) continue; 083 String name = next.toString(); 084 addParameter(name, context); 085 } 086 } 087 } 088 089 private static void addParameter( String name, 090 ServletContext context ) { 091 String value = context.getInitParameter(name); 092 if (value != null) factoryParams.put(name, value); 093 } 094 095 /** 096 * Get a JCR Session for the named workspace in the named repository, using the supplied HTTP servlet request for 097 * authentication information. 098 * 099 * @param request the servlet request; may not be null or unauthenticated 100 * @param repositoryName the name of the repository in which the session is created 101 * @param workspaceName the name of the workspace to which the session should be connected 102 * @return an active session with the given workspace in the named repository 103 * @throws RepositoryException if the named repository does not exist or there was a problem obtaining the named repository 104 */ 105 public static Session getSession( HttpServletRequest request, 106 String repositoryName, 107 String workspaceName ) throws RepositoryException { 108 // Go through all the RepositoryFactory instances and try to create one ... 109 Repository repository = getRepository(repositoryName); 110 111 // If there's no authenticated user, try an anonymous login 112 if (request == null || request.getUserPrincipal() == null) { 113 return repository.login(workspaceName); 114 } 115 116 return repository.login(new ServletCredentials(request), workspaceName); 117 } 118 119 /** 120 * Returns the {@link Repository} instance with the given name. 121 * @param repositoryName a {@code non-null} string 122 * @return a {@link Repository} instance, never {@code null} 123 * @throws NoSuchRepositoryException if no repository with the given name exists. 124 */ 125 public static Repository getRepository( String repositoryName ) throws NoSuchRepositoryException { 126 Repository repository = null; 127 try { 128 repository = repositoriesContainer.getRepository(repositoryName, Collections.unmodifiableMap(factoryParams)); 129 } catch (RepositoryException e) { 130 throw new NoSuchRepositoryException(WebJcrI18n.cannotInitializeRepository.text(repositoryName), e); 131 } 132 133 if (repository == null) { 134 throw new NoSuchRepositoryException(WebJcrI18n.repositoryNotFound.text(repositoryName)); 135 } 136 return repository; 137 } 138 139 /** 140 * Returns a set with all the names of the available repositories. 141 * @return a set with the names, never {@code null} 142 */ 143 public static Set<String> getJcrRepositoryNames() { 144 try { 145 return repositoriesContainer.getRepositoryNames(Collections.unmodifiableMap(factoryParams)); 146 } catch (RepositoryException e) { 147 LOGGER.error(e, WebJcrI18n.cannotLoadRepositoryNames.text()); 148 return Collections.emptySet(); 149 } 150 } 151 152 static void shutdown() { 153 repositoriesContainer.shutdown(); 154 } 155}