001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.repository; 029 030import org.opencms.configuration.CmsConfigurationException; 031import org.opencms.configuration.CmsParameterConfiguration; 032import org.opencms.file.CmsObject; 033import org.opencms.file.wrapper.I_CmsResourceWrapper; 034import org.opencms.jlan.CmsJlanRepository; 035import org.opencms.jlan.CmsJlanThreadManager; 036import org.opencms.jlan.CmsJlanUsers; 037import org.opencms.main.CmsException; 038import org.opencms.main.CmsLog; 039import org.opencms.main.CmsShell; 040 041import java.util.ArrayList; 042import java.util.HashMap; 043import java.util.LinkedHashMap; 044import java.util.List; 045import java.util.Map; 046 047import org.apache.commons.logging.Log; 048 049import com.google.common.collect.Lists; 050 051/** 052 * The RepositoryManager keeps a list with all configured {@link I_CmsRepository} 053 * and can be used to get a repository by its name.<p> 054 * 055 * The configuration of the repositories is done in the configuration file 056 * <code>opencms-importexport.xml</code>.<p> 057 * 058 * @since 6.2.4 059 */ 060public class CmsRepositoryManager { 061 062 /** The logger instance for this class. */ 063 private static final Log LOG = CmsLog.getLog(CmsRepositoryManager.class); 064 065 /** Separator between a wrapper class and its parameters. */ 066 private static final String WRAPPER_CONFIG_SEPARATOR = ":"; 067 068 /** Determines if the repository manager was configured or not. */ 069 private boolean m_configured; 070 071 /** Indicates if the configuration is finalized (frozen). */ 072 private boolean m_frozen; 073 074 /** Flag indicating that a JLan repository is configured and enabled. */ 075 private boolean m_hasJlan; 076 077 /** The JLAN thread manager. */ 078 private CmsJlanThreadManager m_jlanThreadManager; 079 080 /** The list of repositories. */ 081 private List<I_CmsRepository> m_repositoryList = new ArrayList<I_CmsRepository>(); 082 083 /** All initialized repositories, mapped to their name. */ 084 private Map<String, I_CmsRepository> m_repositoryMap = new LinkedHashMap<String, I_CmsRepository>(); 085 086 /** 087 * Creates a new instance for the resource manager, 088 * will be called by the vfs configuration manager.<p> 089 */ 090 public CmsRepositoryManager() { 091 092 if (CmsLog.INIT.isInfoEnabled()) { 093 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_STARTING_REPOSITORY_CONFIG_0)); 094 } 095 m_repositoryMap = new HashMap<String, I_CmsRepository>(); 096 m_frozen = false; 097 m_configured = true; 098 } 099 100 /** 101 * Creates a new unconfigured instance of the repository manager.<p> 102 * 103 * Is used if there are no repositories configured.<p> 104 * 105 * @param configured determines if the repository manager was configured 106 */ 107 public CmsRepositoryManager(boolean configured) { 108 109 this(); 110 m_configured = configured; 111 m_frozen = true; 112 } 113 114 /** 115 * Creates a list of resource wrappers from a collection of configuration parameters, for use in configuring repositories.<p> 116 * 117 * @param config the configuration 118 * @param paramName the parameter name 119 * @param log the logger to use for error messages 120 * 121 * @return the list of resource wrappers 122 * 123 * @throws CmsConfigurationException if something goes wrong with reading the configuration 124 */ 125 public static List<I_CmsResourceWrapper> createResourceWrappersFromConfiguration( 126 CmsParameterConfiguration config, 127 String paramName, 128 Log log) 129 throws CmsConfigurationException { 130 131 List<I_CmsResourceWrapper> wrapperObjects = Lists.newArrayList(); 132 if (config.containsKey(paramName)) { 133 List<String> wrappers = config.getList(paramName); 134 for (String wrapperString : wrappers) { 135 wrapperString = wrapperString.trim(); 136 String className; 137 String configString = null; 138 int separatorPos = wrapperString.indexOf(WRAPPER_CONFIG_SEPARATOR); 139 if (separatorPos < 0) { 140 className = wrapperString; 141 } else { 142 className = wrapperString.substring(0, separatorPos); 143 configString = wrapperString.substring(separatorPos + 1); 144 } 145 146 Class<?> nameClazz; 147 148 // init class for wrapper 149 try { 150 nameClazz = Class.forName(className); 151 } catch (ClassNotFoundException e) { 152 log.error(Messages.get().getBundle().key(Messages.LOG_WRAPPER_CLASS_NOT_FOUND_1, className), e); 153 wrapperObjects.clear(); 154 break; 155 } 156 157 I_CmsResourceWrapper wrapper; 158 try { 159 wrapper = (I_CmsResourceWrapper)nameClazz.newInstance(); 160 if (configString != null) { 161 wrapper.configure(configString); 162 } 163 } catch (InstantiationException e) { 164 throw new CmsConfigurationException( 165 Messages.get().container(Messages.ERR_INVALID_WRAPPER_NAME_1, wrapperString)); 166 } catch (IllegalAccessException e) { 167 throw new CmsConfigurationException( 168 Messages.get().container(Messages.ERR_INVALID_WRAPPER_NAME_1, wrapperString)); 169 } catch (ClassCastException e) { 170 throw new CmsConfigurationException( 171 Messages.get().container(Messages.ERR_INVALID_WRAPPER_NAME_1, wrapperString)); 172 } 173 174 wrapperObjects.add(wrapper); 175 176 if (CmsLog.INIT.isInfoEnabled()) { 177 CmsLog.INIT.info( 178 Messages.get().getBundle().key(Messages.INIT_ADD_WRAPPER_1, wrapper.getClass().getName())); 179 } 180 } 181 } 182 return wrapperObjects; 183 } 184 185 /** 186 * Adds a new configured repository.<p> 187 * 188 * @param repository the repository to add 189 * 190 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 191 */ 192 public void addRepositoryClass(I_CmsRepository repository) throws CmsConfigurationException { 193 194 // check if new repositories can still be added 195 if (m_frozen) { 196 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 197 } 198 m_repositoryList.add(repository); 199 } 200 201 /** 202 * Gets the additional infos for the user who just logged in which is required for the repositories to work.<p> 203 * 204 * @param userName the name of the logged in user 205 * @param password the password of the logged in user 206 * 207 * @return the additional info entries which should be written to the user 208 */ 209 public Map<String, Object> getAdditionalInfoForLogin(String userName, String password) { 210 211 Map<String, Object> additionalInfos = new HashMap<String, Object>(); 212 if (m_hasJlan) { 213 try { 214 additionalInfos.put(CmsJlanUsers.JLAN_HASH, CmsJlanUsers.hashPassword(password)); 215 } catch (Exception e) { 216 LOG.error(e.getLocalizedMessage(), e); 217 } 218 } 219 return additionalInfos; 220 } 221 222 /** 223 * Returns the repositories.<p> 224 * 225 * @return the repositories 226 */ 227 public List<I_CmsRepository> getRepositories() { 228 229 return new ArrayList<I_CmsRepository>(m_repositoryMap.values()); 230 } 231 232 /** 233 * Gets a list of the repositories for the given superclass.<p> 234 * 235 * @param cls the superclass 236 * 237 * @return the repositories for whose classes the given class is a superclass 238 */ 239 @SuppressWarnings("unchecked") 240 public <REPO extends I_CmsRepository> List<REPO> getRepositories(Class<REPO> cls) { 241 242 List<REPO> result = new ArrayList<REPO>(); 243 for (I_CmsRepository repo : m_repositoryMap.values()) { 244 if (cls.isInstance(repo)) { 245 result.add((REPO)repo); 246 } 247 } 248 return result; 249 } 250 251 /** 252 * Returns the repository with the given name.<p> 253 * 254 * @param name the name of the repository 255 * 256 * @return the repository configured for that name 257 */ 258 public I_CmsRepository getRepository(String name) { 259 260 return m_repositoryMap.get(name); 261 } 262 263 /** 264 * Gets a repository by name, but only if its class is a subclass of the class passed as a parameter.<p> 265 * Otherwise, null will be returned.<p> 266 * 267 * @param name the repository name 268 * @param cls the class used to filter repositories 269 * 270 * @return the repository with the given name, or null 271 */ 272 @SuppressWarnings("unchecked") 273 public <REPO extends I_CmsRepository> REPO getRepository(String name, Class<REPO> cls) { 274 275 I_CmsRepository repo = getRepository(name); 276 if (repo == null) { 277 return null; 278 } 279 if (cls.isInstance(repo)) { 280 return (REPO)repo; 281 } else { 282 return null; 283 } 284 285 } 286 287 /** 288 * Initializes a configuration after all parameters have been added.<p> 289 * 290 * @throws CmsConfigurationException if something goes wrong 291 */ 292 public void initConfiguration() throws CmsConfigurationException { 293 294 for (I_CmsRepository rep : m_repositoryList) { 295 if (CmsLog.INIT.isInfoEnabled()) { 296 CmsLog.INIT.info( 297 Messages.get().getBundle().key( 298 Messages.INIT_ADD_REPOSITORY_2, 299 rep.getClass().getName(), 300 rep.getName())); 301 } 302 rep.initConfiguration(); 303 m_repositoryMap.put(rep.getName(), rep); 304 } 305 m_frozen = true; 306 307 if (CmsLog.INIT.isInfoEnabled()) { 308 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_REPOSITORY_CONFIG_FINISHED_0)); 309 } 310 311 } 312 313 /** 314 * Initializes repositories using an admin CMS object.<p> 315 * 316 * @param cms the CMS object with admin privileges 317 */ 318 public void initializeCms(CmsObject cms) { 319 320 List<String> toRemove = new ArrayList<String>(); 321 // Repositories which can't be fully initialized need to be removed. 322 for (I_CmsRepository repository : m_repositoryMap.values()) { 323 String repoName = repository.getName(); 324 try { 325 repository.initializeCms(cms); 326 } catch (CmsException e) { 327 LOG.warn("Could not fully initialize repository " + repoName, e); 328 toRemove.add(repoName); 329 } 330 } 331 for (String removeRepo : toRemove) { 332 m_repositoryMap.remove(removeRepo); 333 } 334 m_hasJlan = !getRepositories(CmsJlanRepository.class).isEmpty(); 335 if (!CmsShell.isJlanDisabled() && m_hasJlan) { 336 CmsJlanUsers.setAdminCms(cms); 337 m_jlanThreadManager = new CmsJlanThreadManager(); 338 m_jlanThreadManager.start(); 339 } 340 341 } 342 343 /** 344 * Returns the configured.<p> 345 * 346 * @return the configured 347 */ 348 public boolean isConfigured() { 349 350 return m_configured; 351 } 352 353 /** 354 * Shuts down the repository manager.<p> 355 */ 356 public void shutDown() { 357 358 if (m_jlanThreadManager != null) { 359 m_jlanThreadManager.stop(); 360 } 361 } 362 363}