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.workplace.commons; 029 030import org.opencms.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.file.CmsVfsResourceNotFoundException; 035import org.opencms.file.history.I_CmsHistoryResource; 036import org.opencms.flex.CmsFlexController; 037import org.opencms.i18n.CmsEncoder; 038import org.opencms.jsp.CmsJspActionElement; 039import org.opencms.main.CmsContextInfo; 040import org.opencms.main.CmsException; 041import org.opencms.main.CmsLog; 042import org.opencms.main.OpenCms; 043import org.opencms.util.CmsRequestUtil; 044import org.opencms.util.CmsStringUtil; 045import org.opencms.workplace.CmsDialog; 046import org.opencms.workplace.CmsWorkplaceSettings; 047 048import java.io.IOException; 049 050import javax.servlet.http.HttpServletRequest; 051import javax.servlet.http.HttpServletResponse; 052import javax.servlet.jsp.PageContext; 053 054import org.apache.commons.logging.Log; 055 056/** 057 * Shows a preview of the selected resource in the Explorer view.<p> 058 * 059 * This is required to get correct previews of statically exported pages 060 * in the Online project.<p> 061 * 062 * The following file uses this class: 063 * <ul> 064 * <li>/commons/displayresource.jsp 065 * </ul> 066 * <p> 067 * 068 * @since 6.0.0 069 */ 070public class CmsDisplayResource extends CmsDialog { 071 072 /** Request parameter name for versionid. */ 073 public static final String PARAM_VERSION = "version"; 074 075 /** The log object for this class. */ 076 private static final Log LOG = CmsLog.getLog(CmsDisplayResource.class); 077 078 /** The version number parameter. */ 079 private String m_paramVersion; 080 081 /** 082 * Public constructor with JSP action element.<p> 083 * 084 * @param jsp an initialized JSP action element 085 */ 086 public CmsDisplayResource(CmsJspActionElement jsp) { 087 088 super(jsp); 089 } 090 091 /** 092 * Public constructor with JSP variables.<p> 093 * 094 * @param context the JSP page context 095 * @param req the JSP request 096 * @param res the JSP response 097 */ 098 public CmsDisplayResource(PageContext context, HttpServletRequest req, HttpServletResponse res) { 099 100 this(new CmsJspActionElement(context, req, res)); 101 } 102 103 /** 104 * Returns the content of an historical resource.<p> 105 * 106 * @param cms a CmsObject 107 * @param resource the name of the historical resource 108 * @param version the version number of the historical resource 109 * 110 * @return the content of an historical resource 111 */ 112 protected static byte[] getHistoricalResourceContent(CmsObject cms, String resource, String version) { 113 114 if (CmsStringUtil.isNotEmpty(resource) && CmsStringUtil.isNotEmpty(version)) { 115 // try to load the historical resource 116 I_CmsHistoryResource res = null; 117 String storedSiteRoot = cms.getRequestContext().getSiteRoot(); 118 try { 119 cms.getRequestContext().setSiteRoot("/"); 120 res = cms.readResource( 121 cms.readResource(resource, CmsResourceFilter.ALL).getStructureId(), 122 Integer.parseInt(version)); 123 } catch (CmsException e) { 124 // can usually be ignored 125 if (LOG.isInfoEnabled()) { 126 LOG.info(e.getLocalizedMessage()); 127 } 128 return "".getBytes(); 129 } finally { 130 cms.getRequestContext().setSiteRoot(storedSiteRoot); 131 } 132 if (res.isFile()) { 133 byte[] historyResourceContent = ((CmsFile)res).getContents(); 134 if ((historyResourceContent == null) || (historyResourceContent.length == 0)) { 135 try { 136 CmsFile file = cms.readFile((CmsResource)res); 137 historyResourceContent = file.getContents(); 138 } catch (CmsException e) { 139 // ignore 140 } 141 } 142 historyResourceContent = CmsEncoder.changeEncoding( 143 historyResourceContent, 144 OpenCms.getSystemInfo().getDefaultEncoding(), 145 cms.getRequestContext().getEncoding()); 146 return historyResourceContent; 147 } 148 } 149 return "".getBytes(); 150 } 151 152 /** 153 * Redirects to the specified file or shows an historical resource.<p> 154 * 155 * @throws Exception if redirection fails 156 */ 157 public void actionShow() throws Exception { 158 159 // try to load the historical resource 160 if (CmsStringUtil.isNotEmpty(getParamVersion())) { 161 showHistoricVersion(); 162 } else { 163 String resourceStr = getParamResource(); 164 // trying to read the resource 165 CmsResource resource = readResource(resourceStr); 166 if (isDeleted(resource)) { 167 // resource has been deleted in offline project 168 throw new CmsVfsResourceNotFoundException(Messages.get().container( 169 Messages.ERR_RESOURCE_DELETED_2, 170 resourceStr, 171 getCms().getRequestContext().getCurrentProject().getName())); 172 } 173 174 // check for release / expiration time window 175 autoTimeWarp(resource); 176 177 // code for display resource after all tests for displayability (exists, not deleted) 178 // if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) { 179 // // if we have a container page look for the first sitemap entry 180 // // and use that to display the container page 181 // List<CmsInternalSitemapEntry> entries = OpenCms.getSitemapManager().getEntriesForStructureId( 182 // getJsp().getCmsObject(), 183 // resource.getStructureId()); 184 // if (!entries.isEmpty()) { 185 // CmsInternalSitemapEntry entry = entries.get(0); 186 // resourceStr = entry.getRootPath(); 187 // } 188 // } 189 if (OpenCms.getSiteManager().isSharedFolder(getCms().getRequestContext().getSiteRoot())) { 190 if (!OpenCms.getSiteManager().startsWithShared(resourceStr)) { 191 resourceStr = CmsStringUtil.joinPaths(OpenCms.getSiteManager().getSharedFolder(), resourceStr); 192 } 193 } 194 String url = getJsp().link(resourceStr); 195 // if in online project 196 if ((url.indexOf("://") < 0) && getCms().getRequestContext().getCurrentProject().isOnlineProject()) { 197 url = prependSiteRoot(url); 198 } 199 getJsp().getResponse().sendRedirect(url); 200 } 201 } 202 203 /** 204 * Returns the version number parameter value.<p> 205 * 206 * @return the version number parameter value 207 */ 208 public String getParamVersion() { 209 210 return m_paramVersion; 211 } 212 213 /** 214 * Sets the version number parameter value.<p> 215 * 216 * @param paramVersion the version number parameter value to set 217 */ 218 public void setParamVersionid(String paramVersion) { 219 220 m_paramVersion = paramVersion; 221 } 222 223 /** 224 * Performs a timewarp for resources that are expired or not released yet to always allow a 225 * preview of a page out of the workplace.<p> 226 * 227 * If the user has a configured timewarp (preferences dialog) a mandatory timewarp will lead to 228 * an exception. One cannot auto timewarp with configured timewarp time.<p> 229 * 230 * @param resource the resource to show 231 * 232 * @throws CmsVfsResourceNotFoundException if a warp would be needed to show the resource but the user has a configured 233 * timewarp which disallows auto warping 234 */ 235 protected void autoTimeWarp(CmsResource resource) throws CmsVfsResourceNotFoundException { 236 237 long surfTime = getCms().getRequestContext().getRequestTime(); 238 if (resource.isReleasedAndNotExpired(surfTime)) { 239 // resource is valid, no modification of time required 240 return; 241 } 242 243 if (getSettings().getUserSettings().getTimeWarp() == CmsContextInfo.CURRENT_TIME) { 244 // no time warp has been set, enable auto time warp 245 long timeWarp; 246 // will also work if ATTRIBUTE_REQUEST_TIME was CmsResource.DATE_RELEASED_EXPIRED_IGNORE 247 if (resource.isExpired(surfTime)) { 248 // do a time warp into the past 249 timeWarp = resource.getDateExpired() - 1; 250 } else if (!resource.isReleased(surfTime)) { 251 // do a time warp into the future 252 timeWarp = resource.getDateReleased() + 1; 253 } else { 254 // do no time warp 255 timeWarp = CmsContextInfo.CURRENT_TIME; 256 } 257 if (timeWarp != CmsContextInfo.CURRENT_TIME) { 258 // let's do the time warp again... 259 getSession().setAttribute(CmsContextInfo.ATTRIBUTE_REQUEST_TIME, Long.valueOf(timeWarp)); 260 } 261 } else { 262 // resource is not vaild in the time window set by the user, 263 // report an error message 264 throw new CmsVfsResourceNotFoundException( 265 Messages.get().container(Messages.ERR_RESOURCE_OUTSIDE_TIMEWINDOW_1, getParamResource())); 266 } 267 } 268 269 /** 270 * @see org.opencms.workplace.CmsDialog#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest) 271 */ 272 @Override 273 protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) { 274 275 fillParamValues(settings, request); 276 } 277 278 /** 279 * Returns if the given resource has the state "deleted".<p> 280 * 281 * @param resource the resource 282 * 283 * @return <code>true</code> if the resource is of state "deleted" 284 */ 285 private boolean isDeleted(CmsResource resource) { 286 287 return resource.getState().isDeleted(); 288 } 289 290 /** 291 * Prepends the site-root to the given URL.<p> 292 * 293 * @param url the URL 294 * 295 * @return the absolute URL 296 */ 297 private String prependSiteRoot(String url) { 298 299 String site = getCms().getRequestContext().getSiteRoot(); 300 if (CmsStringUtil.isEmptyOrWhitespaceOnly(site) || OpenCms.getSiteManager().isSharedFolder(site)) { 301 site = OpenCms.getSiteManager().getDefaultUri(); 302 if (CmsStringUtil.isEmptyOrWhitespaceOnly(site) 303 || (OpenCms.getSiteManager().getSiteForSiteRoot(site) == null)) { 304 return OpenCms.getSiteManager().getWorkplaceServer() + url; 305 } else { 306 return OpenCms.getSiteManager().getSiteForSiteRoot(site).getUrl() + url; 307 } 308 } 309 return OpenCms.getSiteManager().getSiteForSiteRoot(site).getUrl() + url; 310 } 311 312 /** 313 * Reads the resource from the DB.<p> 314 * 315 * @param resourceName the resource name 316 * 317 * @return the resource 318 * 319 * @throws CmsException if the resource can not be read 320 */ 321 private CmsResource readResource(String resourceName) throws CmsException { 322 323 CmsResource resource = null; 324 try { 325 resource = getCms().readResource(resourceName, CmsResourceFilter.ALL); 326 } catch (CmsVfsResourceNotFoundException e) { 327 throw new CmsVfsResourceNotFoundException( 328 Messages.get().container( 329 Messages.ERR_RESOURCE_DOES_NOT_EXIST_3, 330 resourceName, 331 getCms().getRequestContext().getCurrentProject().getName(), 332 getCms().getRequestContext().getSiteRoot()), 333 e); 334 } 335 return resource; 336 } 337 338 /** 339 * Displays the requested historic version of the resource.<p> 340 */ 341 private void showHistoricVersion() { 342 343 String resourceStr = getParamResource(); 344 byte[] result = getHistoricalResourceContent(getCms(), resourceStr, getParamVersion()); 345 if (result != null) { 346 // get the top level response to change the content type 347 String contentType = OpenCms.getResourceManager().getMimeType( 348 resourceStr, 349 getCms().getRequestContext().getEncoding()); 350 351 HttpServletResponse res = getJsp().getResponse(); 352 HttpServletRequest req = getJsp().getRequest(); 353 354 res.setHeader( 355 CmsRequestUtil.HEADER_CONTENT_DISPOSITION, 356 new StringBuffer("attachment; filename=\"").append(resourceStr).append("\"").toString()); 357 res.setContentLength(result.length); 358 359 CmsFlexController controller = CmsFlexController.getController(req); 360 res = controller.getTopResponse(); 361 res.setContentType(contentType); 362 363 try { 364 res.getOutputStream().write(result); 365 res.getOutputStream().flush(); 366 } catch (IOException e) { 367 // can usually be ignored 368 if (LOG.isInfoEnabled()) { 369 LOG.info(e.getLocalizedMessage()); 370 } 371 } 372 } 373 } 374}