001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.ui.apps.cacheadmin; 029 030import org.opencms.cache.CmsLruCache; 031import org.opencms.flex.CmsFlexCache; 032import org.opencms.loader.CmsImageLoader; 033import org.opencms.loader.I_CmsImageCache; 034import org.opencms.main.CmsLog; 035import org.opencms.main.OpenCms; 036import org.opencms.monitor.CmsMemoryStatus; 037import org.opencms.ui.A_CmsUI; 038import org.opencms.ui.CmsVaadinUtils; 039import org.opencms.ui.FontOpenCms; 040import org.opencms.ui.apps.A_CmsWorkplaceApp; 041import org.opencms.ui.apps.CmsFileExplorer; 042import org.opencms.ui.apps.Messages; 043import org.opencms.ui.components.CmsInfoButton; 044import org.opencms.util.CmsFileUtil; 045import org.opencms.util.CmsStringUtil; 046 047import java.io.File; 048import java.util.LinkedHashMap; 049import java.util.List; 050import java.util.Map; 051 052import org.apache.commons.io.FileUtils; 053import org.apache.commons.logging.Log; 054 055import com.vaadin.server.Sizeable.Unit; 056import com.vaadin.ui.Component; 057import com.vaadin.ui.HorizontalSplitPanel; 058import com.vaadin.ui.UI; 059import com.vaadin.ui.themes.ValoTheme; 060import com.vaadin.v7.event.FieldEvents.TextChangeEvent; 061import com.vaadin.v7.event.FieldEvents.TextChangeListener; 062import com.vaadin.v7.shared.ui.label.ContentMode; 063import com.vaadin.v7.ui.Label; 064import com.vaadin.v7.ui.ProgressBar; 065import com.vaadin.v7.ui.TextField; 066import com.vaadin.v7.ui.VerticalLayout; 067 068/** 069 * Class for the app which shows the content of caches.<p> 070 */ 071public class CmsCacheViewApp extends A_CmsWorkplaceApp { 072 073 /** 074 * Modes to run this app. 075 */ 076 public static enum Mode { 077 /**Shows FlexCache.*/ 078 FlexCache, 079 /**Shows ImageCache.*/ 080 ImageCache; 081 } 082 083 /** The logger for this class. */ 084 private static final Log LOG = CmsLog.getLog(CmsCacheViewApp.class); 085 086 /**Mode.*/ 087 private Mode m_mode; 088 089 /** The file table filter input. */ 090 private TextField m_siteTableFilter; 091 092 /** 093 * public constructor.<p> 094 * 095 * @param mode of app 096 */ 097 public CmsCacheViewApp(Mode mode) { 098 099 m_mode = mode; 100 } 101 102 /** 103 * Creates in info button for java cache statistics.<p> 104 * 105 * @return CmsInfoButton 106 */ 107 public static CmsInfoButton getJavaStatisticButton() { 108 109 return getJavaStatisticButton(OpenCms.getMemoryMonitor().getMemoryStatus()); 110 111 } 112 113 /** 114 * Creates in info button for java cache statistics.<p> 115 * @param memory memory object 116 * 117 * @return CmsInfoButton 118 */ 119 public static CmsInfoButton getJavaStatisticButton(CmsMemoryStatus memory) { 120 121 Map<String, String> infoMap = new LinkedHashMap<String, String>(); 122 123 infoMap.put( 124 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_JAVA_HEAP_MAX_0), 125 CmsFileUtil.formatFilesize( 126 memory.getMaxMemory() * 1048576, 127 A_CmsUI.getCmsObject().getRequestContext().getLocale())); 128 infoMap.put( 129 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_JAVA_HEAP_TOTAL_0), 130 CmsFileUtil.formatFilesize( 131 memory.getTotalMemory() * 1048576, 132 A_CmsUI.getCmsObject().getRequestContext().getLocale())); 133 infoMap.put( 134 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_JAVA_HEAP_USED_0), 135 CmsFileUtil.formatFilesize( 136 memory.getUsedMemory() * 1048576, 137 A_CmsUI.getCmsObject().getRequestContext().getLocale())); 138 infoMap.put( 139 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_JAVA_HEAP_FREE_0), 140 CmsFileUtil.formatFilesize( 141 memory.getFreeMemory() * 1048576, 142 A_CmsUI.getCmsObject().getRequestContext().getLocale())); 143 144 CmsInfoButton info = new CmsInfoButton(infoMap); 145 VerticalLayout prog = new VerticalLayout(); 146 Label label = new Label(); 147 label.setContentMode(ContentMode.HTML); 148 label.setValue( 149 "<p>" + CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEXCACHE_LABEL_MEMORY_BLOCK_0) + "</p>"); 150 prog.addComponent(label); 151 prog.addComponent(getProgressBar((((float)memory.getUsage() / 100)))); 152 info.addAdditionalElement(prog, 0); 153 info.setWindowCaption(CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEX_0)); 154 info.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEX_0)); 155 return info; 156 } 157 158 /** 159 * Gets a Progressbar with css style set.<p> 160 * 161 * @param value of the bar 162 * @return vaadin ProgressBar 163 */ 164 public static ProgressBar getProgressBar(float value) { 165 166 ProgressBar res = new ProgressBar(value); 167 String style = ""; 168 if (value > 0.75) { 169 style = "o-nearlyfull"; 170 } 171 if (value > 0.9) { 172 style = "o-full"; 173 } 174 res.addStyleName(style); 175 return res; 176 } 177 178 /** 179 * Creates in info button for flex cache statistics.<p> 180 * 181 * @return CmsInfoButton 182 */ 183 protected static CmsInfoButton getFlexStatisticButton() { 184 185 Map<String, String> infoMap = new LinkedHashMap<String, String>(); 186 187 CmsFlexCache cache = OpenCms.getFlexCache(); 188 CmsLruCache entryLruCache = cache.getEntryLruCache(); 189 190 infoMap.put( 191 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEXCACHE_LABEL_STATS_KEYS_0), 192 String.valueOf(cache.keySize())); 193 infoMap.put( 194 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEXCACHE_LABEL_STATS_VARIATIONS_0), 195 String.valueOf(cache.size())); 196 infoMap.put( 197 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEXCACHE_LABEL_MEMORY_MAXSIZE_0), 198 CmsFileUtil.formatFilesize( 199 entryLruCache.getMaxCacheCosts(), 200 A_CmsUI.getCmsObject().getRequestContext().getLocale())); 201 infoMap.put( 202 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEXCACHE_LABEL_MEMORY_CURSIZE_0), 203 CmsFileUtil.formatFilesize( 204 entryLruCache.getObjectCosts(), 205 A_CmsUI.getCmsObject().getRequestContext().getLocale())); 206 CmsInfoButton info = new CmsInfoButton(infoMap); 207 VerticalLayout prog = new VerticalLayout(); 208 Label label = new Label(); 209 label.setContentMode(ContentMode.HTML); 210 label.setValue( 211 "<p>" + CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEXCACHE_LABEL_MEMORY_BLOCK_0) + "</p>"); 212 prog.addComponent(label); 213 214 prog.addComponent( 215 getProgressBar((float)entryLruCache.getObjectCosts() / (float)entryLruCache.getMaxCacheCosts())); 216 info.addAdditionalElement(prog, 0); 217 info.setWindowCaption(CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEX_0)); 218 info.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_FLEX_0)); 219 return info; 220 } 221 222 /** 223 * Creates in info button for image cache statistics.<p> 224 * 225 * @return CmsInfoButton 226 */ 227 protected static CmsInfoButton getImageStatisticButton() { 228 229 String repositoryPath = CmsImageLoader.getImageRepositoryPath(); 230 I_CmsImageCache imageCache = CmsImageLoader.getImageCache(); 231 CmsInfoButton info; 232 if (imageCache != null) { 233 // Listing a remote cache can be expensive and should not delay opening the cache app. 234 info = CmsInfoButton.createLazy(() -> getImageCacheStatistics(imageCache, null)); 235 } else { 236 info = new CmsInfoButton(getImageCacheStatistics(null, repositoryPath)); 237 } 238 239 info.setWindowCaption(CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_IMAGE_0)); 240 info.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_IMAGE_0)); 241 return info; 242 } 243 244 /** Calculates image cache statistics. */ 245 private static Map<String, String> getImageCacheStatistics(I_CmsImageCache imageCache, String repositoryPath) { 246 247 final long[] size = new long[] {0L}; 248 Map<String, String> infoMap = new LinkedHashMap<String, String>(); 249 if (imageCache != null) { 250 try { 251 imageCache.visitEntries((key, length) -> size[0] += length); 252 } catch (Exception e) { 253 LOG.warn("Unable to calculate image cache statistics.", e); 254 } 255 } else if (repositoryPath != null) { 256 File repository = new File(repositoryPath); 257 if (repository.exists()) { 258 size[0] = FileUtils.sizeOfDirectory(repository); 259 } 260 } 261 infoMap.put( 262 CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_IMAGECACHE_LABEL_MEMORY_BLOCK_0), 263 CmsFileUtil.formatFilesize(size[0], A_CmsUI.getCmsObject().getRequestContext().getLocale())); 264 return infoMap; 265 } 266 267 /** 268 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getBreadCrumbForState(java.lang.String) 269 */ 270 @Override 271 protected LinkedHashMap<String, String> getBreadCrumbForState(String state) { 272 273 LinkedHashMap<String, String> crumbs = new LinkedHashMap<String, String>(); 274 275 if (CmsStringUtil.isEmptyOrWhitespaceOnly(state)) { 276 if (Mode.FlexCache.equals(m_mode)) { 277 crumbs.put("", CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_VIEW_FLEX_0)); 278 } else { 279 crumbs.put("", CmsVaadinUtils.getMessageText(Messages.GUI_CACHE_VIEW_IMAGE_0)); 280 } 281 return crumbs; 282 } 283 return new LinkedHashMap<String, String>(); //size==1 & state was not empty -> state doesn't match to known path 284 } 285 286 /** 287 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getComponentForState(java.lang.String) 288 */ 289 @Override 290 protected Component getComponentForState(String state) { 291 292 //remove filter field 293 if (m_siteTableFilter != null) { 294 m_infoLayout.removeComponent(m_siteTableFilter); 295 m_siteTableFilter = null; 296 } 297 298 if (Mode.FlexCache.equals(m_mode)) { 299 m_rootLayout.setMainHeightFull(true); 300 return getFlexViewComponent(); 301 } 302 303 if (Mode.ImageCache.equals(m_mode)) { 304 m_rootLayout.setMainHeightFull(true); 305 return getImageViewComponent(); 306 } 307 return null; 308 } 309 310 /** 311 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getSubNavEntries(java.lang.String) 312 */ 313 @Override 314 protected List<NavEntry> getSubNavEntries(String state) { 315 316 return null; 317 318 } 319 320 /** 321 * Layout for the Flex Cache View includings statistics and cache table.<p> 322 * 323 * @return vaadin component 324 */ 325 private Component getFlexViewComponent() { 326 327 final CmsFlexCacheTable table = new CmsFlexCacheTable(); 328 m_siteTableFilter = new TextField(); 329 m_siteTableFilter.setIcon(FontOpenCms.FILTER); 330 m_siteTableFilter.setInputPrompt( 331 Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_FILTER_0)); 332 m_siteTableFilter.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); 333 m_siteTableFilter.setWidth("200px"); 334 m_siteTableFilter.addTextChangeListener(new TextChangeListener() { 335 336 private static final long serialVersionUID = 1L; 337 338 public void textChange(TextChangeEvent event) { 339 340 table.filterTable(event.getText()); 341 } 342 }); 343 m_infoLayout.addComponent(m_siteTableFilter); 344 345 m_uiContext.addToolbarButton(getFlexStatisticButton()); 346 m_uiContext.addToolbarButton(CmsFlushCache.getFlushToolButton()); 347 348 table.setSizeFull(); 349 return table; 350 } 351 352 /** 353 * Creates the view for the image cache.<p> 354 * 355 * @return a vaadin vertical layout with the information about the image cache 356 */ 357 private Component getImageViewComponent() { 358 359 m_siteTableFilter = new TextField(); 360 361 HorizontalSplitPanel sp = new HorizontalSplitPanel(); 362 sp.setSizeFull(); 363 VerticalLayout intro = CmsVaadinUtils.getInfoLayout(Messages.GUI_CACHE_IMAGE_INTRODUCTION_0); 364 VerticalLayout nullResult = CmsVaadinUtils.getInfoLayout(Messages.GUI_CACHE_IMAGE_NO_RESULTS_0); 365 final CmsImageCacheTable table = new CmsImageCacheTable(intro, nullResult, m_siteTableFilter); 366 367 sp.setFirstComponent(new CmsImageCacheInput(table)); 368 369 VerticalLayout secC = new VerticalLayout(); 370 secC.setSizeFull(); 371 secC.addComponent(intro); 372 secC.addComponent(nullResult); 373 secC.addComponent(table); 374 375 m_siteTableFilter.setIcon(FontOpenCms.FILTER); 376 m_siteTableFilter.setInputPrompt( 377 Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_FILTER_0)); 378 m_siteTableFilter.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); 379 m_siteTableFilter.setWidth("200px"); 380 m_siteTableFilter.addTextChangeListener(new TextChangeListener() { 381 382 private static final long serialVersionUID = 1L; 383 384 public void textChange(TextChangeEvent event) { 385 386 table.filterTable(event.getText()); 387 } 388 }); 389 m_infoLayout.addComponent(m_siteTableFilter); 390 391 m_uiContext.addToolbarButton(getImageStatisticButton()); 392 m_uiContext.addToolbarButton(CmsFlushCache.getFlushToolButton()); 393 table.setSizeFull(); 394 sp.setSecondComponent(secC); 395 sp.setSplitPosition(CmsFileExplorer.LAYOUT_SPLIT_POSITION, Unit.PIXELS); 396 397 table.setVisible(false); 398 nullResult.setVisible(false); 399 m_siteTableFilter.setVisible(false); 400 401 return sp; 402 } 403}