1 13 16 package org.jahia.operations; 17 18 import java.io.IOException ; 19 import java.io.OutputStreamWriter ; 20 import java.util.ArrayList ; 21 import java.util.Date ; 22 import java.util.Hashtable ; 23 import java.util.Locale ; 24 import java.util.Map ; 25 26 import javax.servlet.ServletContext ; 27 import javax.servlet.ServletOutputStream ; 28 import javax.servlet.http.HttpServletResponse ; 29 import javax.servlet.http.HttpSession ; 30 31 import org.apache.commons.collections.FastHashMap; 32 import org.apache.log4j.Logger; 33 import org.jahia.bin.Jahia; 34 import org.jahia.data.JahiaData; 35 import org.jahia.engines.JahiaEngine; 36 import org.jahia.exceptions.JahiaException; 37 import org.jahia.exceptions.JahiaForbiddenAccessException; 38 import org.jahia.exceptions.JahiaSessionExpirationException; 39 import org.jahia.exceptions.JahiaServerOverloadedException; 40 import org.jahia.params.ParamBean; 41 import org.jahia.registries.EnginesRegistry; 42 import org.jahia.services.cache.CacheEntry; 43 import org.jahia.services.cache.CacheFactory; 44 import org.jahia.services.cache.HtmlCache; 45 import org.jahia.services.cache.HtmlCacheEntry; 46 import org.jahia.services.database.ConnectionDispenser; 47 import org.jahia.settings.SettingsBean; 48 import org.jahia.utils.LanguageCodeConverters; 49 50 import EDU.oswego.cs.dl.util.concurrent.Latch; 51 import EDU.oswego.cs.dl.util.concurrent.Semaphore; 52 import EDU.oswego.cs.dl.util.concurrent.WaiterPreferenceSemaphore; 53 54 78 public class OperationManager { 79 80 private static Logger logger = Logger.getLogger(OperationManager.class); 81 82 private static Map generatingPage = new FastHashMap(10); 84 85 private static Map notCacheablePage = new FastHashMap(2503); 87 88 private PageState pageState = null; 89 90 private static final Semaphore availableProcessings = new WaiterPreferenceSemaphore(Jahia.getSettings().getMaxParallelProcessings()); 91 92 96 public OperationManager() { 97 logger.debug("Starting up..."); 98 } 99 100 117 public void handleOperations(ParamBean jParams, SettingsBean jSettings) 118 throws JahiaException, JahiaSessionExpirationException, 119 JahiaForbiddenAccessException { 120 if (handleSiteCheck(jParams)) 122 return; 123 124 handleOperationModeCheck(jParams); 125 126 String engineName = jParams.getEngine(); 128 JahiaEngine theEngine = getEngineInstance(engineName); 129 130 ConnectionDispenser.terminateConnection(); 132 133 if (theEngine != null) { 134 if (theEngine.needsJahiaData(jParams)) { 136 138 handlePageAccessCheck(jParams); 139 140 if (checkCache(jParams, null)) 141 return; 142 } 143 144 Latch latch = null; 148 149 boolean mustBeWaited = false; 153 154 if (pageState != null && pageState.isCacheable 155 && !notCacheablePage.containsKey(pageState.getKey())) { 156 synchronized (generatingPage) { 157 if (!generatingPage.containsKey(pageState.getKey())) { 158 latch = new Latch(); 159 generatingPage.put(pageState.getKey(), latch); 160 } else { 161 latch = (Latch) generatingPage.get(pageState 162 .getKey()); 163 mustBeWaited = true; 164 } 165 } 166 try { 167 if (mustBeWaited) { 168 if (!latch.attempt(jParams.settings().getPageGenerationWaitTime())) { 169 throw new JahiaServerOverloadedException(); 170 } 171 if (checkCache(jParams, null)) 172 return; 173 } 174 } catch (InterruptedException ie) { 175 logger.debug("The waiting thread has been interrupted :", 176 ie); 177 } 178 } 179 boolean semaphoreAcquired = false; 180 try { 181 if (!availableProcessings.attempt(jParams.settings().getPageGenerationWaitTime())){ 182 throw new JahiaServerOverloadedException(); 183 } else { 184 semaphoreAcquired = true; 185 } 186 processPage(jParams, theEngine); 187 } catch (InterruptedException ie) { 188 logger.debug("The waiting thread has been interrupted :", 189 ie); 190 } finally { 191 if (semaphoreAcquired) { 192 availableProcessings.release(); 193 } 194 if (latch != null) { 195 latch.release(); 196 } 197 if (pageState != null && pageState.getKey() != null) { 198 synchronized (generatingPage) { 199 generatingPage.remove(pageState.getKey()); 200 } 201 } 202 } 203 } 204 } 205 206 private void processPage(ParamBean jParams, JahiaEngine theEngine) 207 throws JahiaException { 208 try { 209 generatePage(jParams, theEngine); 210 211 setResponseOutput(jParams); 212 213 if (Jahia.getSettings().lookupBoolean( 214 SettingsBean.OUTPUT_CACHE_ACTIVATED)) { 215 storeInCache(jParams, pageState != null ? pageState.getKey() 216 : null, jParams.getGeneratedOutput(), jParams 217 .getContentType()); 218 } 219 } catch (java.io.IOException ioe) { 220 logger 221 .debug( 222 "Error retrieving real response writer object or while retrieving generated output :", 223 ioe); 224 } 225 } 226 227 private boolean handleSiteCheck(ParamBean jParams) throws JahiaException { 228 boolean exitProcessing = false; 229 if (jParams.getSite() == null) { 230 ServletContext context = jParams.getContext(); 231 if (context != null) { 232 try { 233 jParams.getRequest().setAttribute("Jahia_ParamBean", 234 jParams); 235 context.getRequestDispatcher( 236 "/jsp/jahia/errors/site_not_found.jsp").forward( 237 jParams.getRequest(), jParams.getResponse()); 238 } catch (Throwable t) { 239 logger.error(t); 240 throw new JahiaException( 241 "400 Page Not Found: No site specified", 242 "The requested site not found", 243 JahiaException.SECURITY_ERROR, 244 JahiaException.ERROR_SEVERITY); 245 } 246 exitProcessing = true; 247 } else { 248 throw new JahiaException("400 Page Not Found:", 249 "Context is null", JahiaException.SECURITY_ERROR, 250 JahiaException.ERROR_SEVERITY); 251 } 252 } 253 return exitProcessing; 254 } 255 256 private void handleOperationModeCheck(ParamBean jParams) 257 throws JahiaException { 258 if ("core".equals(jParams.getEngine())) { 259 if (jParams.getPage() == null 260 && (jParams.getOperationMode().equals(ParamBean.EDIT) || jParams 261 .getOperationMode().equals(ParamBean.COMPARE))) { 262 jParams.getSession().removeAttribute(ParamBean.SESSION_LOCALE); 266 jParams.flushLocaleListCache(); 267 ArrayList locales = jParams.getLocales(true); 268 Hashtable pageTitles = jParams.getContentPage().getTitles(true); 269 Locale locale = null; 270 String lang = null; 271 for (int i = 0; i < locales.size(); i++) { 272 locale = (Locale ) locales.get(i); 273 if (pageTitles.containsKey(locale.toString())) { 274 lang = locale.toString(); 275 break; 276 } 277 } 278 279 if (lang != null) { 280 jParams.getSession().setAttribute(ParamBean.SESSION_LOCALE, 281 locale); 282 jParams.setUser(jParams.getUser()); 283 jParams.changePage(jParams.getContentPage()); 284 } 285 } 286 } 287 } 288 289 private void handlePageAccessCheck(ParamBean jParams) throws JahiaException { 290 297 if (jParams.getPage() != null 298 && !jParams.getPage().checkReadAccess(jParams.getUser())) { 299 if (Jahia.usesSso()) { 300 try { 301 jParams.getResponse().sendRedirect(Jahia.getSsoValve().getRedirectUrl(jParams)); 302 return; 303 } catch (IOException e) { 304 } 305 } 306 throw new JahiaException("403 Forbidden - Page:" 307 + jParams.getPageID(), "No read access for page " 308 + jParams.getPageID() + " user=" 309 + jParams.getUser().getUsername() + " acl=" 310 + jParams.getPage().getAclID(), 311 JahiaException.SECURITY_ERROR, JahiaException.ERROR_SEVERITY); 312 } 313 } 314 315 private void generatePage(ParamBean jParams, JahiaEngine theEngine) 316 throws JahiaException { 317 try { 318 JahiaData jData = null; 319 320 if (logger.isDebugEnabled()) { 321 logger.debug("We generate page " 322 + (pageState != null ? pageState.getKey() : "")); 323 } 327 328 if (theEngine.needsJahiaData(jParams) && jParams.getPage() != null) { 329 jData = new JahiaData(jParams); 330 } else { 331 jData = new JahiaData(jParams, false); 332 } 333 334 jParams.getRequest() 336 .setAttribute("org.jahia.data.JahiaData", jData); 337 338 logger.debug("Start of handling operation"); 339 theEngine.handleActions(jParams, jData); 340 logger.debug("Operation handled for engine " + jParams.getEngine()); 341 342 HttpSession session = jParams.getRequest().getSession(); 343 344 session.setAttribute(ParamBean.SESSION_LAST_ENGINE_NAME, jParams 346 .getEngine()); 347 348 session.setAttribute(ParamBean.SESSION_LAST_REQUESTED_PAGE_ID, 350 new Integer (jParams.getPageID())); 351 } catch (Throwable e) { 352 throw new JahiaException("Error during handle of operation", 353 "Error during handle of operation", JahiaException.PAGE_ERROR, 354 JahiaException.ERROR_SEVERITY, e); 355 } 356 } 357 358 private void setResponseOutput(ParamBean jParams) throws IOException { 359 HttpServletResponse realResp = jParams.getRealResponse(); 362 String curContentType = jParams.getContentType(); 363 if (jParams.getRedirectLocation() != null) { 364 logger 365 .debug("sendRedirect call detected during output generation, no other output..."); 366 if (!realResp.isCommitted()) { 367 realResp.sendRedirect(realResp.encodeRedirectURL(jParams 368 .getRedirectLocation())); 369 } 370 } else { 371 376 if (!realResp.isCommitted()) { 377 logger.debug("Printing content output to real writer"); 378 if (curContentType != null) { 379 realResp.setContentType(curContentType); 380 } 381 388 } else { 389 logger 390 .debug("Output has already been committed, aborting display..."); 391 } 392 } 393 } 394 395 private boolean checkCache(ParamBean jParams, Object entryKey) 396 throws JahiaException { 397 boolean isCacheable = false; 398 boolean isBeingGenerated = false; 399 400 if (!Jahia.getSettings().lookupBoolean( 401 SettingsBean.OUTPUT_CACHE_ACTIVATED)) { 402 logger.debug("Output cache not activated."); 403 } else { 404 411 if (("core".equals(jParams.getEngine())) 412 && (jParams.getHttpMethod() == ParamBean.GET_METHOD) 413 && (ParamBean.CACHE_ON.equals(jParams.getCacheStatus()))) { 414 HtmlCache htmlCache = CacheFactory.getHtmlCache(); 416 417 if (entryKey == null) { 418 String curLanguageCode = LanguageCodeConverters 420 .localeToLanguageTag(jParams.getLocale()); 421 int workflowState = jParams.getEntryLoadRequest() 423 .getWorkflowState(); 424 425 entryKey = htmlCache.computeEntryKey(Integer 426 .toString(jParams.getPageID()), jParams.getUser() 427 .getUsername(), curLanguageCode, workflowState, jParams 428 .getUserAgent(), jParams.getRequest().getScheme()); 429 } 430 431 433 CacheEntry cacheEntry = htmlCache.getCacheEntry(entryKey); 434 435 if (jParams.getCacheExpirationDelay() == -1 437 || jParams.getCacheExpirationDelay() > 0) 438 isCacheable = true; 439 440 if (cacheEntry != null) { 441 HtmlCacheEntry htmlEntry = (HtmlCacheEntry) cacheEntry 444 .getObject(); 445 String htmlContent = htmlEntry.getContentBody(); 446 if (!cacheEntry.getOperationMode().equals( 447 jParams.getOperationMode())) { 448 logger 449 .debug("Cache entry mode is NOT equal to current mode, flushing page entry and generating page..."); 450 htmlCache.remove(entryKey); 451 } else if (htmlContent != null) { 452 logger 453 .debug("Found content in cache, writing directly bypassing processing..."); 454 HttpServletResponse realResp = jParams 455 .getRealResponse(); 456 String contentType = htmlEntry.getContentType(); 457 if (contentType != null) { 458 realResp.setContentType(contentType); 459 logger.debug("Sending content type : [" 460 + contentType + "]"); 461 } 462 try { 463 ServletOutputStream outputStream = realResp 464 .getOutputStream(); 465 OutputStreamWriter streamWriter = new OutputStreamWriter ( 466 outputStream); 467 if (contentType != null) { 468 int charsetPos = contentType.toLowerCase() 469 .indexOf("charset="); 470 if (charsetPos != -1) { 471 String encoding = contentType.substring( 472 charsetPos + "charset=".length()) 473 .toUpperCase(); 474 logger 475 .debug("Using streamWriter with encoding : " 476 + encoding); 477 streamWriter = new OutputStreamWriter ( 478 outputStream, encoding); 479 } 480 } 481 streamWriter.write(htmlContent, 0, htmlContent 482 .length()); 483 streamWriter.flush(); 484 } catch (java.io.IOException ioe) { 485 logger 486 .error( 487 "Error writing cache output, IOException generated error", 488 ioe); 489 throw new JahiaException( 490 "OperationsManager.handleOperations", 491 "Error writing cache content to writer", 492 JahiaException.SECURITY_ERROR, 493 JahiaException.ERROR_SEVERITY, ioe); 494 } 495 return (true); 496 } 497 } 498 } 499 500 if ((ParamBean.CACHE_OFFONCE.equals(jParams.getCacheStatus())) 501 || (ParamBean.CACHE_BYPASS.equals(jParams.getCacheStatus())) 502 || (ParamBean.CACHE_ONLYUPDATE.equals(jParams 503 .getCacheStatus()))) { 504 jParams.setCacheStatus(ParamBean.CACHE_ON); 508 } 509 } 510 511 pageState = new PageState(isCacheable, isBeingGenerated, entryKey); 512 513 return (false); 514 } 515 516 528 private void storeInCache(ParamBean jParams, Object entryKey, 529 String generatedOutput, String contentType) throws JahiaException { 530 logger.debug("Storing generated content into the HTML Cache..."); 531 532 HtmlCache htmlCache = CacheFactory.getHtmlCache(); 534 535 if (entryKey == null) { 536 String curLanguageCode = LanguageCodeConverters 538 .localeToLanguageTag(jParams.getLocale()); 539 int workflowState = jParams.getEntryLoadRequest() 541 .getWorkflowState(); 542 entryKey = htmlCache.computeEntryKey(Integer.toString(jParams 543 .getPageID()), jParams.getUser().getUsername(), 544 curLanguageCode, workflowState, jParams.getUserAgent(), 545 jParams.getRequest().getScheme()); 546 } 547 548 if (("core".equals(jParams.getEngine())) 550 && ((ParamBean.CACHE_ON 551 .equals(jParams.getOriginalCacheStatus())) 552 || (ParamBean.CACHE_ONLYUPDATE.equals(jParams 553 .getOriginalCacheStatus())) || (ParamBean.CACHE_OFFONCE 554 .equals(jParams.getOriginalCacheStatus())))) { 555 if (logger.isDebugEnabled()) { 556 logger 558 .debug("Storing output in cache for entryKey=" + entryKey); 559 } 560 HtmlCacheEntry htmlEntry = new HtmlCacheEntry(generatedOutput, 561 contentType); 562 CacheEntry newEntry = new CacheEntry(htmlEntry); 563 newEntry.setOperationMode(jParams.getOperationMode()); 564 565 if (jParams.getUser() == null) 567 return; 568 569 if (jParams.getCacheExpirationDelay() == 0) 571 notCacheablePage.put(entryKey, entryKey); 572 if (Jahia.getSettings().getOutputCacheDefaultExpirationDelay() != -1) { 574 Date nowDate = new Date (); 575 576 Date expirationDate = new Date (nowDate.getTime() 580 + Jahia.getSettings() 581 .getOutputCacheDefaultExpirationDelay()); 582 logger.debug("Set the expiration date"); 583 newEntry.setExpirationDate(expirationDate); 584 } 585 586 if (jParams.getCacheExpirationDate() != null) { 588 logger.debug("Using default expiration date"); 589 Date nowDate = new Date (); 590 if (nowDate.compareTo(jParams.getCacheExpirationDate()) >= 0) { 591 return; 594 } 595 newEntry.setExpirationDate(jParams.getCacheExpirationDate()); 596 } 597 598 htmlCache.putCacheEntry(entryKey, newEntry, true); 599 logger.debug("Added HTML page into the cache."); 600 } else { 601 logger.debug("Bypassing HTML cache storage"); 602 if (htmlCache != null && jParams.getUser() != null) { 603 if (jParams.getCacheExpirationDelay() == 0) { 604 notCacheablePage.put(entryKey, entryKey); 605 } 606 } 607 } 608 } 609 610 622 private JahiaEngine getEngineInstance(String name) throws JahiaException { 623 EnginesRegistry registry = EnginesRegistry.getInstance(); 625 if (registry == null) 626 throw new JahiaException("Internal Error", 627 "Could not get the Engines Registry instance!", 628 JahiaException.INITIALIZATION_ERROR, 629 JahiaException.ERROR_SEVERITY); 630 631 return (JahiaEngine) registry.getEngine(name); 633 } 634 } 635 | Popular Tags |