001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2017-2018 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Affero General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 013 * for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jgrapes.webconlet.sysinfo; 020 021import freemarker.core.ParseException; 022import freemarker.template.MalformedTemplateNameException; 023import freemarker.template.Template; 024import freemarker.template.TemplateNotFoundException; 025import java.io.IOException; 026import java.io.Serializable; 027import java.time.Duration; 028import java.util.HashSet; 029import java.util.Optional; 030import java.util.Properties; 031import java.util.Set; 032import org.jgrapes.core.Channel; 033import org.jgrapes.core.Event; 034import org.jgrapes.core.Manager; 035import org.jgrapes.core.annotation.Handler; 036import org.jgrapes.webconsole.base.Conlet.RenderMode; 037import org.jgrapes.webconsole.base.ConsoleConnection; 038import org.jgrapes.webconsole.base.WebConsoleUtils; 039import org.jgrapes.webconsole.base.events.AddConletType; 040import org.jgrapes.webconsole.base.events.AddPageResources.ScriptResource; 041import org.jgrapes.webconsole.base.events.ConsoleReady; 042import org.jgrapes.webconsole.base.events.NotifyConletModel; 043import org.jgrapes.webconsole.base.events.NotifyConletView; 044import org.jgrapes.webconsole.base.events.RenderConlet; 045import org.jgrapes.webconsole.base.events.RenderConletRequestBase; 046import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet; 047 048/** 049 * 050 */ 051public class SysInfoConlet 052 extends FreeMarkerConlet<SysInfoConlet.SysInfoModel> { 053 054 private static final Set<RenderMode> MODES = RenderMode.asSet( 055 RenderMode.Preview, RenderMode.View); 056 057 /** 058 * The periodically generated update event. 059 */ 060 public static class Update extends Event<Void> { 061 } 062 063 /** 064 * Creates a new component with its channel set to the given channel. 065 * 066 * @param componentChannel the channel that the component's handlers listen 067 * on by default and that {@link Manager#fire(Event, Channel...)} 068 * sends the event to 069 */ 070 public SysInfoConlet(Channel componentChannel) { 071 super(componentChannel); 072 setPeriodicRefresh(Duration.ofSeconds(1), () -> new Update()); 073 } 074 075 /** 076 * On {@link ConsoleReady}, fire the {@link AddConletType}. 077 * 078 * @param event the event 079 * @param connection the console connection 080 * @throws TemplateNotFoundException the template not found exception 081 * @throws MalformedTemplateNameException the malformed template name 082 * exception 083 * @throws ParseException the parse exception 084 * @throws IOException Signals that an I/O exception has occurred. 085 */ 086 @Handler 087 public void onConsoleReady(ConsoleReady event, ConsoleConnection connection) 088 throws TemplateNotFoundException, MalformedTemplateNameException, 089 ParseException, IOException { 090 // Add SysInfoConlet resources to page 091 connection.respond(new AddConletType(type()) 092 .addRenderMode(RenderMode.Preview).setDisplayNames( 093 localizations(connection.supportedLocales(), "conletName")) 094 .addScript(new ScriptResource() 095 .setRequires("jquery") 096 .setScriptType("module") 097 .setScriptUri(event.renderSupport().conletResource( 098 type(), "SysInfo-functions.ftl.js"))) 099 .addCss(event.renderSupport(), WebConsoleUtils.uriFromPath( 100 "SysInfo-style.css"))); 101 } 102 103 @Override 104 protected Optional<SysInfoModel> createStateRepresentation(Event<?> event, 105 ConsoleConnection session, String conletId) throws Exception { 106 return Optional.of(new SysInfoModel()); 107 } 108 109 @Override 110 protected Set<RenderMode> doRenderConlet(RenderConletRequestBase<?> event, 111 ConsoleConnection connection, String conletId, 112 SysInfoModel conletState) throws Exception { 113 Set<RenderMode> renderedAs = new HashSet<>(); 114 if (event.renderAs().contains(RenderMode.Preview)) { 115 Template tpl 116 = freemarkerConfig().getTemplate("SysInfo-preview.ftl.html"); 117 connection.respond(new RenderConlet(type(), conletId, 118 processTemplate(event, tpl, 119 fmModel(event, connection, conletId, conletState))) 120 .setRenderAs( 121 RenderMode.Preview.addModifiers(event.renderAs())) 122 .setSupportedModes(MODES)); 123 renderedAs.add(RenderMode.Preview); 124 } 125 if (event.renderAs().contains(RenderMode.View)) { 126 Template tpl 127 = freemarkerConfig().getTemplate("SysInfo-view.ftl.html"); 128 connection.respond(new RenderConlet(type(), conletId, 129 processTemplate(event, tpl, 130 fmModel(event, connection, conletId, conletState))) 131 .setRenderAs( 132 RenderMode.View.addModifiers(event.renderAs())) 133 .setSupportedModes(MODES)); 134 renderedAs.add(RenderMode.View); 135 } 136 if (!renderedAs.isEmpty()) { 137 updateView(connection, conletId); 138 } 139 return renderedAs; 140 } 141 142 private void updateView(ConsoleConnection connection, String conletId) { 143 if (!connection.isConnected()) { 144 return; 145 } 146 Runtime runtime = Runtime.getRuntime(); 147 connection.respond(new NotifyConletView(type(), 148 conletId, "updateMemorySizes", 149 System.currentTimeMillis(), runtime.maxMemory(), 150 runtime.totalMemory(), 151 runtime.totalMemory() - runtime.freeMemory())); 152 } 153 154 /** 155 * Handle the periodic update event by sending {@link NotifyConletView} 156 * events. 157 * 158 * @param event the event 159 * @param connection the console connection 160 */ 161 @Handler 162 public void onUpdate(Update event, ConsoleConnection connection) { 163 for (String conletId : conletIds(connection)) { 164 updateView(connection, conletId); 165 } 166 } 167 168 @Override 169 @SuppressWarnings("PMD.DoNotCallGarbageCollectionExplicitly") 170 protected void doUpdateConletState(NotifyConletModel event, 171 ConsoleConnection connection, SysInfoModel conletState) 172 throws Exception { 173 event.stop(); 174 System.gc(); 175 for (String conletId : conletIds(connection)) { 176 updateView(connection, conletId); 177 } 178 } 179 180 /** 181 * The conlet's model. 182 */ 183 @SuppressWarnings("serial") 184 public static class SysInfoModel implements Serializable { 185 186 /** 187 * Return the system properties. 188 * 189 * @return the properties 190 */ 191 public Properties systemProperties() { 192 return System.getProperties(); 193 } 194 195 /** 196 * Return the {@link Runtime}. 197 * 198 * @return the runtime 199 */ 200 public Runtime runtime() { 201 return Runtime.getRuntime(); 202 } 203 } 204 205}