001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (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.gwt; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.file.CmsUser; 035import org.opencms.lock.CmsLock; 036import org.opencms.lock.CmsLockActionRecord; 037import org.opencms.lock.CmsLockActionRecord.LockChange; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.OpenCms; 041import org.opencms.security.CmsRole; 042import org.opencms.security.CmsRoleViolationException; 043import org.opencms.util.CmsUUID; 044 045import java.io.IOException; 046import java.util.HashMap; 047import java.util.List; 048import java.util.Map; 049 050import javax.servlet.ServletException; 051import javax.servlet.ServletRequest; 052import javax.servlet.ServletResponse; 053import javax.servlet.http.HttpServletRequest; 054import javax.servlet.http.HttpServletResponse; 055 056import org.apache.commons.logging.Log; 057 058import com.google.gwt.user.server.rpc.RemoteServiceServlet; 059import com.google.gwt.user.server.rpc.SerializationPolicy; 060 061/** 062 * Wrapper for GWT services served through OpenCms.<p> 063 * 064 * @since 8.0.0 065 */ 066public class CmsGwtService extends RemoteServiceServlet { 067 068 /** The static log object for this class. */ 069 private static final Log LOG = CmsLog.getLog(CmsGwtService.class); 070 071 /** Serialization id. */ 072 private static final long serialVersionUID = 8119684308154724518L; 073 074 /** The service class context. */ 075 private CmsGwtServiceContext m_context; 076 077 /** The current CMS context. */ 078 private ThreadLocal<CmsObject> m_perThreadCmsObject; 079 080 /** 081 * Constructor.<p> 082 */ 083 public CmsGwtService() { 084 085 super(); 086 } 087 088 /** 089 * Checks the permissions of the current user to match the required security level.<p> 090 * 091 * Note that the current request and response are not available yet.<p> 092 * 093 * Override if needed.<p> 094 * 095 * @param cms the current cms object 096 * 097 * @throws CmsRoleViolationException if the security level can not be satisfied 098 */ 099 public void checkPermissions(CmsObject cms) throws CmsRoleViolationException { 100 101 OpenCms.getRoleManager().checkRole(cms, CmsRole.WORKPLACE_USER); 102 } 103 104 /** 105 * Logs and re-throws the given exception for RPC responses.<p> 106 * 107 * @param t the exception 108 * 109 * @throws CmsRpcException the converted exception 110 */ 111 public void error(Throwable t) throws CmsRpcException { 112 113 logError(t); 114 throw new CmsRpcException(t); 115 } 116 117 /** 118 * Returns the current cms context.<p> 119 * 120 * @return the current cms context 121 */ 122 public CmsObject getCmsObject() { 123 124 return m_perThreadCmsObject.get(); 125 } 126 127 /** 128 * Returns the current request.<p> 129 * 130 * @return the current request 131 * 132 * @see #getThreadLocalRequest() 133 */ 134 public HttpServletRequest getRequest() { 135 136 return getThreadLocalRequest(); 137 } 138 139 /** 140 * Returns the current response.<p> 141 * 142 * @return the current response 143 * 144 * @see #getThreadLocalResponse() 145 */ 146 public HttpServletResponse getResponse() { 147 148 return getThreadLocalResponse(); 149 } 150 151 /** 152 * @see javax.servlet.GenericServlet#log(java.lang.String) 153 */ 154 @Override 155 public void log(String msg) { 156 157 if (getResponse() != null) { 158 super.log(msg); 159 } 160 // also log to opencms.log 161 LOG.info(msg); 162 } 163 164 /** 165 * @see javax.servlet.GenericServlet#log(java.lang.String, java.lang.Throwable) 166 */ 167 @Override 168 public void log(String message, Throwable t) { 169 170 if (getResponse() != null) { 171 super.log(message, t); 172 } 173 // also log to opencms.log 174 LOG.info(message, t); 175 } 176 177 /** 178 * Logs the given exception.<p> 179 * 180 * @param t the exception to log 181 */ 182 public void logError(Throwable t) { 183 184 LOG.error(t.getLocalizedMessage(), t); 185 } 186 187 /** 188 * @see javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) 189 */ 190 @Override 191 public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { 192 193 try { 194 arg1.setCharacterEncoding(arg0.getCharacterEncoding()); 195 super.service(arg0, arg1); 196 } finally { 197 clearThreadStorage(); 198 } 199 } 200 201 /** 202 * Sets the current cms context.<p> 203 * 204 * @param cms the current cms context to set 205 */ 206 public synchronized void setCms(CmsObject cms) { 207 208 if (m_perThreadCmsObject == null) { 209 m_perThreadCmsObject = new ThreadLocal<CmsObject>(); 210 } 211 m_perThreadCmsObject.set(cms); 212 } 213 214 /** 215 * Sets the service context.<p> 216 * 217 * @param context the new service context 218 */ 219 public synchronized void setContext(CmsGwtServiceContext context) { 220 221 m_context = context; 222 } 223 224 /** 225 * Sets the current request.<p> 226 * 227 * @param request the request to set 228 */ 229 public synchronized void setRequest(HttpServletRequest request) { 230 231 if (perThreadRequest == null) { 232 perThreadRequest = new ThreadLocal<HttpServletRequest>(); 233 } 234 perThreadRequest.set(request); 235 } 236 237 /** 238 * Sets the current response.<p> 239 * 240 * @param response the response to set 241 */ 242 public synchronized void setResponse(HttpServletResponse response) { 243 244 if (perThreadResponse == null) { 245 perThreadResponse = new ThreadLocal<HttpServletResponse>(); 246 } 247 perThreadResponse.set(response); 248 } 249 250 /** 251 * We do not want that the server goes to fetch files from the servlet context.<p> 252 * 253 * @see com.google.gwt.user.server.rpc.RemoteServiceServlet#doGetSerializationPolicy(javax.servlet.http.HttpServletRequest, java.lang.String, java.lang.String) 254 */ 255 @Override 256 protected SerializationPolicy doGetSerializationPolicy( 257 HttpServletRequest request, 258 String moduleBaseURL, 259 String strongName) { 260 261 return m_context.getSerializationPolicy(getCmsObject(), moduleBaseURL, strongName); 262 } 263 264 /** 265 * @see com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet#doUnexpectedFailure(java.lang.Throwable) 266 */ 267 @Override 268 protected void doUnexpectedFailure(Throwable e) { 269 270 LOG.error(String.valueOf(System.currentTimeMillis()), e); 271 super.doUnexpectedFailure(e); 272 } 273 274 /** 275 * Locks the given resource with a temporary, if not already locked by the current user. 276 * Will throw an exception if the resource could not be locked for the current user.<p> 277 * 278 * @param resource the resource to lock 279 * 280 * @return the assigned lock 281 * 282 * @throws CmsException if the resource could not be locked 283 */ 284 protected CmsLockActionRecord ensureLock(CmsResource resource) throws CmsException { 285 286 CmsObject cms = getCmsObject(); 287 LockChange change = LockChange.unchanged; 288 List<CmsResource> blockingResources = cms.getBlockingLockedResources(resource); 289 if ((blockingResources != null) && !blockingResources.isEmpty()) { 290 throw new CmsException(Messages.get().container( 291 Messages.ERR_RESOURCE_HAS_BLOCKING_LOCKED_CHILDREN_1, 292 cms.getSitePath(resource))); 293 } 294 CmsUser user = cms.getRequestContext().getCurrentUser(); 295 CmsLock lock = cms.getLock(resource); 296 if (!lock.isOwnedBy(user)) { 297 cms.lockResourceTemporary(resource); 298 change = LockChange.locked; 299 lock = cms.getLock(resource); 300 } else if (!lock.isOwnedInProjectBy(user, cms.getRequestContext().getCurrentProject())) { 301 cms.changeLock(resource); 302 change = LockChange.changed; 303 lock = cms.getLock(resource); 304 } 305 return new CmsLockActionRecord(lock, change); 306 } 307 308 /** 309 * 310 * Locks the given resource with a temporary, if not already locked by the current user. 311 * Will throw an exception if the resource could not be locked for the current user.<p> 312 * 313 * @param structureId the structure id of the resource 314 * 315 * @return the assigned lock 316 * 317 * @throws CmsException if something goes wrong 318 */ 319 protected CmsLockActionRecord ensureLock(CmsUUID structureId) throws CmsException { 320 321 return ensureLock(getCmsObject().readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION)); 322 323 } 324 325 /** 326 * Locks the given resource with a temporary, if not already locked by the current user. 327 * Will throw an exception if the resource could not be locked for the current user.<p> 328 * 329 * @param sitepath the site-path of the resource to lock 330 * 331 * @return the assigned lock 332 * 333 * @throws CmsException if the resource could not be locked 334 */ 335 protected CmsLockActionRecord ensureLock(String sitepath) throws CmsException { 336 337 return ensureLock(getCmsObject().readResource(sitepath, CmsResourceFilter.IGNORE_EXPIRATION)); 338 } 339 340 /** 341 * Ensures that the user session is still valid.<p> 342 * 343 * @throws CmsException if the current user is the guest user 344 */ 345 protected void ensureSession() throws CmsException { 346 347 CmsUser user = getCmsObject().getRequestContext().getCurrentUser(); 348 if (user.isGuestUser()) { 349 throw new CmsException(Messages.get().container(Messages.ERR_SESSION_EXPIRED_0)); 350 } 351 } 352 353 /** 354 * Converts a list of properties to a map.<p> 355 * 356 * @param properties the list of properties 357 * 358 * @return a map from property names to properties 359 */ 360 protected Map<String, CmsProperty> getPropertiesByName(List<CmsProperty> properties) { 361 362 Map<String, CmsProperty> result = new HashMap<String, CmsProperty>(); 363 for (CmsProperty property : properties) { 364 String key = property.getName(); 365 result.put(key, property.clone()); 366 } 367 return result; 368 } 369 370 /** 371 * Tries to unlock a resource.<p> 372 * 373 * @param resource the resource to unlock 374 */ 375 protected void tryUnlock(CmsResource resource) { 376 377 try { 378 getCmsObject().unlockResource(resource); 379 } catch (CmsException e) { 380 LOG.debug("Unable to unlock " + resource.getRootPath(), e); 381 } 382 } 383 384 /** 385 * Clears the objects stored in thread local.<p> 386 */ 387 protected void clearThreadStorage() { 388 389 if (m_perThreadCmsObject != null) { 390 m_perThreadCmsObject.remove(); 391 } 392 if (perThreadRequest != null) { 393 perThreadRequest.remove(); 394 } 395 if (perThreadResponse != null) { 396 perThreadResponse.remove(); 397 } 398 } 399}