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, 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.jlan; 029 030import org.opencms.configuration.CmsConfigurationException; 031import org.opencms.configuration.CmsParameterConfiguration; 032import org.opencms.file.CmsObject; 033import org.opencms.file.CmsProject; 034import org.opencms.file.wrapper.CmsObjectWrapper; 035import org.opencms.file.wrapper.CmsSilentWrapperException; 036import org.opencms.file.wrapper.I_CmsResourceWrapper; 037import org.opencms.main.CmsContextInfo; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.CmsShell; 041import org.opencms.main.OpenCms; 042import org.opencms.repository.CmsRepositoryFilter; 043import org.opencms.repository.CmsRepositoryManager; 044import org.opencms.repository.I_CmsRepository; 045import org.opencms.util.CmsStringUtil; 046import org.opencms.xml.content.CmsXmlContent; 047 048import java.lang.reflect.InvocationHandler; 049import java.lang.reflect.InvocationTargetException; 050import java.lang.reflect.Method; 051import java.lang.reflect.Proxy; 052import java.util.ArrayList; 053import java.util.Collections; 054import java.util.List; 055 056import org.apache.commons.logging.Log; 057 058import org.alfresco.jlan.server.SrvSession; 059import org.alfresco.jlan.server.filesys.DiskDeviceContext; 060import org.alfresco.jlan.server.filesys.DiskInterface; 061import org.alfresco.jlan.server.filesys.DiskSharedDevice; 062import org.alfresco.jlan.server.filesys.TreeConnection; 063 064import com.google.common.collect.Lists; 065 066/** 067 * Repository class for configuring repositories for Alfresco JLAN.<p> 068 */ 069public class CmsJlanRepository implements I_CmsRepository { 070 071 /** Parameter for controlling whether byte order marks should be added to plaintext files. */ 072 public static final String PARAM_ADD_BOM = "addBOM"; 073 074 /** The parameter for the project in which this repository should operate. */ 075 public static final String PARAM_PROJECT = "project"; 076 077 /** Name of the parameter to configure the root directory. */ 078 public static final String PARAM_ROOT = "root"; 079 080 /** Name of the parameter to configure resource wrappers. */ 081 public static final String PARAM_WRAPPER = "wrapper"; 082 083 /** The logger instance for this class. */ 084 private static final Log LOG = CmsLog.getLog(CmsJlanRepository.class); 085 086 /** Flag which controls whether the CmsObjectWrapper should add byte order marks for plain files. */ 087 private boolean m_addByteOrderMark; 088 089 /** The CMS context. */ 090 private CmsObject m_cms; 091 092 /** The configuration for this repository. */ 093 private CmsParameterConfiguration m_configuration = new CmsParameterConfiguration(); 094 095 /** The shared disk device. */ 096 private DiskSharedDevice m_device; 097 098 /** The JLAN device context for this repository. */ 099 private DiskDeviceContext m_deviceContext; 100 101 /** The JLAN disk interface for this repository. */ 102 private DiskInterface m_diskInterface; 103 104 /** The name of the repository. */ 105 private String m_name; 106 107 /** The disk interface. */ 108 private CmsJlanDiskInterface m_originalDiskInterface; 109 110 /** The configured project. */ 111 private CmsProject m_project; 112 113 /** The name of the configured project. */ 114 private String m_projectName; 115 116 /** The root VFS directory of the repository. */ 117 private String m_root; 118 119 /** The list of wrappers configured for this repository. */ 120 private List<I_CmsResourceWrapper> m_wrappers = Lists.newArrayList(); 121 122 /** 123 * Creates a new repository instance.<p> 124 */ 125 public CmsJlanRepository() { 126 127 m_deviceContext = new CmsJlanDeviceContext(this); 128 m_deviceContext.enableChangeHandler(true); 129 m_deviceContext.setFileServerNotifications(true); 130 m_originalDiskInterface = new CmsJlanDiskInterface(); 131 m_diskInterface = createLoggingProxy(m_originalDiskInterface); 132 } 133 134 /** 135 * Creates a dynamic proxy for a disk interface which logs the method calls and their results.<p> 136 * 137 * @param impl the disk interface for which a logging proxy should be created 138 * 139 * @return the dynamic proxy which logs methods calls 140 */ 141 public static DiskInterface createLoggingProxy(final DiskInterface impl) { 142 143 return (DiskInterface)Proxy.newProxyInstance( 144 Thread.currentThread().getContextClassLoader(), 145 new Class[] {DiskInterface.class}, 146 new InvocationHandler() { 147 148 @SuppressWarnings("synthetic-access") 149 public Object invoke(Object target, Method method, Object[] params) throws Throwable { 150 151 // Just to be on the safe side performance-wise, we only log the parameters/result 152 // if the info channel is enabled 153 if (LOG.isInfoEnabled()) { 154 List<String> paramStrings = new ArrayList<String>(); 155 for (Object param : params) { 156 paramStrings.add("" + param); 157 } 158 String paramsAsString = CmsStringUtil.listAsString(paramStrings, ", "); 159 LOG.info("Call: " + method.getName() + " " + paramsAsString); 160 } 161 try { 162 Object result = method.invoke(impl, params); 163 if (LOG.isInfoEnabled()) { 164 LOG.info("Returned from " + method.getName() + ": " + result); 165 } 166 return result; 167 } catch (InvocationTargetException e) { 168 Throwable cause = e.getCause(); 169 if ((cause != null) && (cause instanceof CmsSilentWrapperException)) { 170 // not really an error 171 LOG.info(cause.getCause().getLocalizedMessage(), cause.getCause()); 172 } else { 173 LOG.error(e.getLocalizedMessage(), e); 174 } 175 throw e.getCause(); 176 } 177 } 178 }); 179 } 180 181 /** 182 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#addConfigurationParameter(java.lang.String, java.lang.String) 183 */ 184 public void addConfigurationParameter(String paramName, String paramValue) { 185 186 m_configuration.add(paramName, paramValue); 187 188 } 189 190 /** 191 * Checks if a user may access this repository.<p> 192 * 193 * @param user the name of the user 194 * 195 * @return true if the user may access the repository 196 */ 197 public boolean allowAccess(String user) { 198 199 try { 200 return m_cms.getPermissions(m_root, user).requiresViewPermission(); 201 } catch (CmsException e) { 202 LOG.error(e.getLocalizedMessage(), e); 203 return true; 204 } 205 } 206 207 /** 208 * Creates a CmsObjectWrapper for the current session.<p> 209 * 210 * @param session the current session 211 * @param connection the tree connection 212 * 213 * @return the correctly configured CmsObjectWrapper for this session 214 * 215 * @throws CmsException if something goes wrong 216 */ 217 public CmsObjectWrapper getCms(SrvSession session, TreeConnection connection) throws CmsException { 218 219 String userName = session.getClientInformation().getUserName(); 220 userName = CmsJlanUsers.translateUser(userName); 221 CmsContextInfo contextInfo = new CmsContextInfo(m_cms.getRequestContext()); 222 contextInfo.setUserName(userName); 223 CmsObject newCms = OpenCms.initCmsObject(m_cms, contextInfo); 224 newCms.getRequestContext().setSiteRoot(getRoot()); 225 newCms.getRequestContext().setCurrentProject(getProject()); 226 CmsObjectWrapper result = new CmsObjectWrapper(newCms, getWrappers()); 227 result.setAddByteOrderMark(m_addByteOrderMark); 228 result.getRequestContext().setAttribute(CmsXmlContent.AUTO_CORRECTION_ATTRIBUTE, Boolean.TRUE); 229 return result; 230 } 231 232 /** 233 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#getConfiguration() 234 */ 235 public CmsParameterConfiguration getConfiguration() { 236 237 return m_configuration; 238 } 239 240 /** 241 * Gets the device context for this repository.<p> 242 * 243 * @return the device context 244 */ 245 public DiskDeviceContext getDeviceContext() { 246 247 return m_deviceContext; 248 } 249 250 /** 251 * Gets the disk interface for this repository.<p> 252 * 253 * @return the disk interface 254 */ 255 public DiskInterface getDiskInterface() { 256 257 return m_diskInterface; 258 } 259 260 /** 261 * @see org.opencms.repository.I_CmsRepository#getFilter() 262 */ 263 public CmsRepositoryFilter getFilter() { 264 265 return null; 266 } 267 268 /** 269 * @see org.opencms.repository.I_CmsRepository#getName() 270 */ 271 public String getName() { 272 273 return m_name; 274 } 275 276 /** 277 * Gets the configured project.<p> 278 * 279 * @return the configured project 280 */ 281 public CmsProject getProject() { 282 283 return m_project; 284 } 285 286 /** 287 * Gets the root directory configured for this repository.<p> 288 * 289 * @return the root directory 290 */ 291 public String getRoot() { 292 293 return m_root; 294 } 295 296 /** 297 * Gets the resource wrappers which have been configured for this repository.<p> 298 * 299 * @return the resource wrappers which have been configured 300 */ 301 public List<I_CmsResourceWrapper> getWrappers() { 302 303 return m_wrappers; 304 } 305 306 /** 307 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration() 308 */ 309 public void initConfiguration() throws CmsConfigurationException { 310 311 List<I_CmsResourceWrapper> wrapperObjects = CmsRepositoryManager.createResourceWrappersFromConfiguration( 312 getConfiguration(), 313 PARAM_WRAPPER, 314 LOG); 315 m_wrappers = Collections.unmodifiableList(wrapperObjects); 316 m_root = getConfiguration().getString(PARAM_ROOT, "").trim(); 317 m_projectName = getConfiguration().getString(PARAM_PROJECT, "Offline").trim(); 318 String addByteOrderMarkStr = getConfiguration().getString(PARAM_ADD_BOM, "" + true).trim(); 319 m_addByteOrderMark = Boolean.parseBoolean(addByteOrderMarkStr); 320 } 321 322 /** 323 * @see org.opencms.repository.I_CmsRepository#initializeCms(org.opencms.file.CmsObject) 324 */ 325 public void initializeCms(CmsObject cms) throws CmsException { 326 327 m_cms = cms; 328 if (CmsShell.isJlanDisabled()) { 329 return; 330 } 331 m_project = m_cms.readProject(m_projectName); 332 m_device = new DiskSharedDevice(getName(), getDiskInterface(), getDeviceContext(), 0); 333 m_device.addAccessControl(new CmsRepositoryAccessControl(this)); 334 } 335 336 /** 337 * @see org.opencms.repository.I_CmsRepository#setFilter(org.opencms.repository.CmsRepositoryFilter) 338 */ 339 public void setFilter(CmsRepositoryFilter filter) { 340 341 // do nothing 342 } 343 344 /** 345 * @see org.opencms.repository.I_CmsRepository#setName(java.lang.String) 346 */ 347 public void setName(String name) { 348 349 // case sensitive share names don't work 350 m_name = name.toUpperCase(); 351 } 352 353 /** 354 * Gets the shared device for this repository.<p> 355 * 356 * @return the shared device 357 */ 358 DiskSharedDevice getSharedDevice() { 359 360 return m_device; 361 } 362 363}