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.EnumSet; 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 @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") 071 public SysInfoConlet(Channel componentChannel) { 072 super(componentChannel); 073 setPeriodicRefresh(Duration.ofSeconds(1), () -> new Update()); 074 } 075 076 /** 077 * On {@link ConsoleReady}, fire the {@link AddConletType}. 078 * 079 * @param event the event 080 * @param connection the console connection 081 * @throws TemplateNotFoundException the template not found exception 082 * @throws MalformedTemplateNameException the malformed template name 083 * exception 084 * @throws ParseException the parse exception 085 * @throws IOException Signals that an I/O exception has occurred. 086 */ 087 @Handler 088 public void onConsoleReady(ConsoleReady event, ConsoleConnection connection) 089 throws TemplateNotFoundException, MalformedTemplateNameException, 090 ParseException, IOException { 091 // Add SysInfoConlet resources to page 092 connection.respond(new AddConletType(type()) 093 .addRenderMode(RenderMode.Preview).setDisplayNames( 094 localizations(connection.supportedLocales(), "conletName")) 095 .addScript(new ScriptResource() 096 .setRequires("jquery") 097 .setScriptType("module") 098 .setScriptUri(event.renderSupport().conletResource( 099 type(), "SysInfo-functions.ftl.js"))) 100 .addCss(event.renderSupport(), WebConsoleUtils.uriFromPath( 101 "SysInfo-style.css"))); 102 } 103 104 @Override 105 protected Optional<SysInfoModel> createStateRepresentation(Event<?> event, 106 ConsoleConnection session, String conletId) throws Exception { 107 return Optional.of(new SysInfoModel()); 108 } 109 110 @Override 111 protected Set<RenderMode> doRenderConlet(RenderConletRequestBase<?> event, 112 ConsoleConnection connection, String conletId, 113 SysInfoModel conletState) throws Exception { 114 Set<RenderMode> renderedAs = EnumSet.noneOf(RenderMode.class); 115 if (event.renderAs().contains(RenderMode.Preview)) { 116 Template tpl 117 = freemarkerConfig().getTemplate("SysInfo-preview.ftl.html"); 118 connection.respond(new RenderConlet(type(), conletId, 119 processTemplate(event, tpl, 120 fmModel(event, connection, conletId, conletState))) 121 .setRenderAs( 122 RenderMode.Preview.addModifiers(event.renderAs())) 123 .setSupportedModes(MODES)); 124 renderedAs.add(RenderMode.Preview); 125 } 126 if (event.renderAs().contains(RenderMode.View)) { 127 Template tpl 128 = freemarkerConfig().getTemplate("SysInfo-view.ftl.html"); 129 connection.respond(new RenderConlet(type(), conletId, 130 processTemplate(event, tpl, 131 fmModel(event, connection, conletId, conletState))) 132 .setRenderAs( 133 RenderMode.View.addModifiers(event.renderAs())) 134 .setSupportedModes(MODES)); 135 renderedAs.add(RenderMode.View); 136 } 137 if (!renderedAs.isEmpty()) { 138 updateView(connection, conletId); 139 } 140 return renderedAs; 141 } 142 143 private void updateView(ConsoleConnection connection, String conletId) { 144 if (!connection.isConnected()) { 145 return; 146 } 147 Runtime runtime = Runtime.getRuntime(); 148 connection.respond(new NotifyConletView(type(), 149 conletId, "updateMemorySizes", 150 System.currentTimeMillis(), runtime.maxMemory(), 151 runtime.totalMemory(), 152 runtime.totalMemory() - runtime.freeMemory())); 153 } 154 155 /** 156 * Handle the periodic update event by sending {@link NotifyConletView} 157 * events. 158 * 159 * @param event the event 160 * @param connection the console connection 161 */ 162 @Handler 163 public void onUpdate(Update event, ConsoleConnection connection) { 164 for (String conletId : conletIds(connection)) { 165 updateView(connection, conletId); 166 } 167 } 168 169 @Override 170 @SuppressWarnings("PMD.DoNotCallGarbageCollectionExplicitly") 171 protected void doUpdateConletState(NotifyConletModel event, 172 ConsoleConnection connection, SysInfoModel conletState) 173 throws Exception { 174 event.stop(); 175 System.gc(); 176 for (String conletId : conletIds(connection)) { 177 updateView(connection, conletId); 178 } 179 } 180 181 /** 182 * The conlet's model. 183 */ 184 @SuppressWarnings("serial") 185 public static class SysInfoModel implements Serializable { 186 187 /** 188 * Return the system properties. 189 * 190 * @return the properties 191 */ 192 public Properties systemProperties() { 193 return System.getProperties(); 194 } 195 196 /** 197 * Return the {@link Runtime}. 198 * 199 * @return the runtime 200 */ 201 public Runtime runtime() { 202 return Runtime.getRuntime(); 203 } 204 } 205 206}