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