From 903f21409b0bb61eda28e014a38ab0d9d2b151d5 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Mon, 19 Nov 2012 13:47:41 +0100 Subject: [PATCH] OO-422: new layout for the administration tree, break the "system infromations" tabbed panel in single controllers under a main menu point, add a new system informations controller with some VIP values --- .../admin/_i18n/LocalStrings_de.properties | 4 + .../olat/admin/cache/AllCachesController.java | 1 + .../sysinfo/CoreFunctionsController.java | 86 ++++ .../JavaEnvironmmentPropertiesController.java | 155 +++++++ .../admin/sysinfo/JavaMemoryController.java | 112 +++++ .../admin/sysinfo/JavaThreadsController.java | 129 ++++++ .../olat/admin/sysinfo/JavaVMController.java | 67 ++- .../olat/admin/sysinfo/SysinfoController.java | 382 ++++++------------ .../admin/sysinfo/ThreadInfosManager.java | 139 +++++++ .../org/olat/admin/sysinfo/ThreadView.java | 149 +++++++ .../admin/sysinfo/_content/buildinfo.html | 19 - .../olat/admin/sysinfo/_content/coreinfo.html | 5 + .../admin/sysinfo/_content/hibernateinfo.html | 21 +- .../olat/admin/sysinfo/_content/infomsg.html | 8 +- .../admin/sysinfo/_content/jvm_envprops.html | 4 + .../admin/sysinfo/_content/jvm_memory.html | 5 + .../admin/sysinfo/_content/jvm_threads.html | 5 + .../olat/admin/sysinfo/_content/memory.html | 3 + .../olat/admin/sysinfo/_content/sysinfo.html | 22 +- .../sysinfo/_i18n/LocalStrings_de.properties | 34 ++ .../admin/sysinfo/_spring/sysinfoContext.xml | 30 +- .../generic/layout/GenericMainController.java | 19 +- .../restapi/system/ThreadsWebService.java | 96 +---- .../org/olat/restapi/system/vo/ThreadVO.java | 31 +- .../org/olat/_spring/extensionContext.xml | 50 ++- .../java/org/olat/restapi/SystemTest.java | 2 - 26 files changed, 1138 insertions(+), 440 deletions(-) create mode 100644 src/main/java/org/olat/admin/sysinfo/CoreFunctionsController.java create mode 100644 src/main/java/org/olat/admin/sysinfo/JavaEnvironmmentPropertiesController.java create mode 100644 src/main/java/org/olat/admin/sysinfo/JavaMemoryController.java create mode 100644 src/main/java/org/olat/admin/sysinfo/JavaThreadsController.java create mode 100644 src/main/java/org/olat/admin/sysinfo/ThreadInfosManager.java create mode 100644 src/main/java/org/olat/admin/sysinfo/ThreadView.java delete mode 100644 src/main/java/org/olat/admin/sysinfo/_content/buildinfo.html create mode 100644 src/main/java/org/olat/admin/sysinfo/_content/coreinfo.html create mode 100644 src/main/java/org/olat/admin/sysinfo/_content/jvm_envprops.html create mode 100644 src/main/java/org/olat/admin/sysinfo/_content/jvm_memory.html create mode 100644 src/main/java/org/olat/admin/sysinfo/_content/jvm_threads.html create mode 100644 src/main/java/org/olat/admin/sysinfo/_content/memory.html diff --git a/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties index 9ae4fde885f..21654c60793 100644 --- a/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties @@ -36,6 +36,8 @@ menu.deletedusers=Gel\u00F6schte Benutzer menu.deletedusers.alt=Benutzer, die in OLAT gel\u00F6scht wurden menu.devel=Development menu.devel.alt=Development tools +menu.javavm=Java VM Infos +menu.javavm.alt=Java Virtual Machine informations menu.snoop=Snoop user request menu.snoop.alt=Snoop user requests menu.groupmanagergroup=Gruppenverwalter @@ -44,6 +46,8 @@ menu.i18n=Sprachen menu.i18n.alt=Konfiguration der Standard- und aktivierten Systemsprachen menu.imadmin=Instant-Messaging menu.imadmin.alt=Instant-Messaging administrieren +menu.infomsg=Info messages +menu.infomsg.alt=Info messages menu.jmx=JMX menu.jmx.alt=JMW-Werte betrachten menu.errors=Errors diff --git a/src/main/java/org/olat/admin/cache/AllCachesController.java b/src/main/java/org/olat/admin/cache/AllCachesController.java index 0059ab53594..7e63fc8ee00 100644 --- a/src/main/java/org/olat/admin/cache/AllCachesController.java +++ b/src/main/java/org/olat/admin/cache/AllCachesController.java @@ -84,6 +84,7 @@ public class AllCachesController extends BasicController { myContent = createVelocityContainer("index"); TableGuiConfiguration tableConfig = new TableGuiConfiguration(); + tableConfig.setDownloadOffered(true); tableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator()); tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("cache.name", 0, null, ureq.getLocale())); diff --git a/src/main/java/org/olat/admin/sysinfo/CoreFunctionsController.java b/src/main/java/org/olat/admin/sysinfo/CoreFunctionsController.java new file mode 100644 index 00000000000..1244dbf0ba3 --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/CoreFunctionsController.java @@ -0,0 +1,86 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.admin.sysinfo; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.chiefcontrollers.BaseChiefController; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.servlets.WebDAVManager; +import org.olat.restapi.RestModule; + +/** + * + * Initial date: 19.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CoreFunctionsController extends FormBasicController { + + /** + * @param ureq + * @param wControl + */ + public CoreFunctionsController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, "coreinfo"); + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + + //server informations + FormLayoutContainer serverCont = FormLayoutContainer.createDefaultFormLayout("functions", getTranslator()); + formLayout.add(serverCont); + formLayout.add("functions", serverCont); + + MultipleSelectionElement clusterEl + = uifactory.addCheckboxesHorizontal("webdav", "core.webdav", serverCont, new String[]{"xx"}, new String[]{""}, null); + clusterEl.setEnabled(false); + clusterEl.select("xx", WebDAVManager.getInstance().isEnabled()); + + MultipleSelectionElement jsMathEl + = uifactory.addCheckboxesHorizontal("jsmath", "core.jsMath", serverCont, new String[]{"xx"}, new String[]{""}, null); + jsMathEl.setEnabled(false); + jsMathEl.select("xx", BaseChiefController.isJsMathEnabled()); + + MultipleSelectionElement restEl + = uifactory.addCheckboxesHorizontal("restapi", "core.restapi", serverCont, new String[]{"xx"}, new String[]{""}, null); + restEl.setEnabled(false); + RestModule restModule = CoreSpringFactory.getImpl(RestModule.class); + restEl.select("xx", restModule.isEnabled()); + + } + + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + // + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/JavaEnvironmmentPropertiesController.java b/src/main/java/org/olat/admin/sysinfo/JavaEnvironmmentPropertiesController.java new file mode 100644 index 00000000000..2194de72f9c --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/JavaEnvironmmentPropertiesController.java @@ -0,0 +1,155 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.admin.sysinfo; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.table.DefaultColumnDescriptor; +import org.olat.core.gui.components.table.DefaultTableDataModel; +import org.olat.core.gui.components.table.TableController; +import org.olat.core.gui.components.table.TableGuiConfiguration; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; + +/** + * + * Initial date: 19.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class JavaEnvironmmentPropertiesController extends BasicController { + private static final int lineCut = 100; + + private final TableController tableCtr; + private final VelocityContainer mainVC; + + public JavaEnvironmmentPropertiesController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + mainVC = createVelocityContainer("jvm_envprops"); + + TableGuiConfiguration tableConfig = new TableGuiConfiguration(); + tableConfig.setDownloadOffered(true); + tableConfig.setPageingEnabled(false); + tableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator()); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.name.i18nKey(), Cols.name.ordinal(), null, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.value.i18nKey(), Cols.value.ordinal(), null, getLocale())); + listenTo(tableCtr); + loadModel(); + mainVC.put("javaenv", tableCtr.getInitialComponent()); + + putInitialPanel(mainVC); + } + + private void loadModel() { + Properties p = System.getProperties(); + List<NameValuePair> pairs = new ArrayList<NameValuePair>(p.size()); + for(Map.Entry<Object,Object> entry : p.entrySet()) { + String name = entry.getKey().toString(); + String value = entry.getValue().toString(); + pairs.add(new NameValuePair(name, value)); + } + tableCtr.setTableDataModel(new PropertiesDataModel(pairs)); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + private enum Cols { + name("java.envprops.name"), + value("java.envprops.value"); + + private final String i18nKey; + + private Cols(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } + } + + private static class NameValuePair { + private final String name; + private final String value; + + public NameValuePair(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + } + + private static class PropertiesDataModel extends DefaultTableDataModel<NameValuePair> { + public PropertiesDataModel(List<NameValuePair> threads) { + super(threads); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int row, int col) { + NameValuePair view = getObject(row); + switch(Cols.values()[col]) { + case name: return view.getName(); + case value: { + String value = view.getValue(); + if(value.length() < lineCut) { + return value; + } + StringBuilder props = new StringBuilder(value.length() + 50); + while (value.length() > lineCut) { + value = (props.length() == 0 ? "" : "<br />") + value.substring(lineCut); + props.append(value.substring(0, value.length() > lineCut ? lineCut : value.length())); + } + return props.toString(); + } + default: return "ERROR"; + } + } + } + + +} diff --git a/src/main/java/org/olat/admin/sysinfo/JavaMemoryController.java b/src/main/java/org/olat/admin/sysinfo/JavaMemoryController.java new file mode 100644 index 00000000000..142bacad147 --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/JavaMemoryController.java @@ -0,0 +1,112 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.admin.sysinfo; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryType; +import java.lang.management.MemoryUsage; +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.util.StringHelper; + +/** + * + * Initial date: 19.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class JavaMemoryController extends BasicController { + + private final Link gcButton; + private final VelocityContainer mainVC; + + public JavaMemoryController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + mainVC = createVelocityContainer("jvm_memory"); + gcButton = LinkFactory.createButton("run.gc", mainVC, this); + + loaddModel(); + putInitialPanel(mainVC); + } + + private void loaddModel() { + mainVC.contextPut("memory", getMemoryInfos()); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if (source == gcButton){ + Runtime.getRuntime().gc(); + getWindowControl().setInfo("Garbage collection done."); + loaddModel(); + } + } + + private String getMemoryInfos() { + Runtime r = Runtime.getRuntime(); + StringBuilder sb = new StringBuilder(); + appendFormattedKeyValue(sb, "Processors", new Integer(r.availableProcessors())); + appendFormattedKeyValue(sb, "Total Memory", StringHelper.formatMemory(r.totalMemory())); + appendFormattedKeyValue(sb, "Free Memory", StringHelper.formatMemory(r.freeMemory())); + appendFormattedKeyValue(sb, "Max Memory", StringHelper.formatMemory(r.maxMemory())); + + sb.append("<br />Detailed Memory Information (Init/Used/Max)<br/> "); + List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); + for(MemoryPoolMXBean item:pools) { + String name = item.getName(); + MemoryType type = item.getType(); + appendFormattedKeyValue(sb, name, " Type: " + type); + MemoryUsage usage = item.getUsage(); + appendFormattedKeyValue(sb, "Usage", StringHelper.formatMemory(usage.getInit()) + "/" + StringHelper.formatMemory(usage.getUsed()) + "/" + StringHelper.formatMemory(usage.getMax())); + MemoryUsage peak = item.getPeakUsage(); + appendFormattedKeyValue(sb, "Peak", StringHelper.formatMemory(peak.getInit()) + "/" + StringHelper.formatMemory(peak.getUsed()) + "/" + StringHelper.formatMemory(peak.getMax())); + MemoryUsage collections = item.getCollectionUsage(); + if (collections!= null){ + appendFormattedKeyValue(sb, "Collections", StringHelper.formatMemory(collections.getInit()) + "/" + StringHelper.formatMemory(collections.getUsed()) + "/" + StringHelper.formatMemory(collections.getMax())); + } + sb.append("<hr/>"); + } + + return sb.toString(); + } + + private void appendFormattedKeyValue(StringBuilder sb, String key, Object value) { + sb.append(" <b>"); + sb.append(key); + sb.append(":</b> "); + sb.append(value); + sb.append("<br />"); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/JavaThreadsController.java b/src/main/java/org/olat/admin/sysinfo/JavaThreadsController.java new file mode 100644 index 00000000000..1b414eab971 --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/JavaThreadsController.java @@ -0,0 +1,129 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.admin.sysinfo; + +import java.util.List; + +import org.olat.core.CoreSpringFactory; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.table.DefaultColumnDescriptor; +import org.olat.core.gui.components.table.DefaultTableDataModel; +import org.olat.core.gui.components.table.TableController; +import org.olat.core.gui.components.table.TableGuiConfiguration; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; + +/** + * + * Initial date: 19.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class JavaThreadsController extends BasicController { + + private final TableController tableCtr; + private final VelocityContainer mainVC; + + private final ThreadInfosManager threadInfosManager; + + public JavaThreadsController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + threadInfosManager = CoreSpringFactory.getImpl(ThreadInfosManager.class); + + mainVC = createVelocityContainer("jvm_threads"); + + TableGuiConfiguration tableConfig = new TableGuiConfiguration(); + tableConfig.setDownloadOffered(true); + tableConfig.setPageingEnabled(false); + tableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator()); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.name.i18nKey(), Cols.name.ordinal(), null, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.state.i18nKey(), Cols.state.ordinal(), null, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.cpuPercent.i18nKey(), Cols.cpuPercent.ordinal(), null, getLocale())); + tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.cpuTime.i18nKey(), Cols.cpuTime.ordinal(), null, getLocale())); + listenTo(tableCtr); + loadModel(); + mainVC.put("threads", tableCtr.getInitialComponent()); + + putInitialPanel(mainVC); + } + + private void loadModel() { + List<ThreadView> threads = threadInfosManager.getThreadViews(); + ThreadsDataModel model = new ThreadsDataModel(threads); + tableCtr.setTableDataModel(model); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } + + private enum Cols { + name("java.thread.name"), + state("java.thread.alive"), + cpuPercent("java.thread.cpu.percent"), + cpuTime("java.thread.cpu.time"); + + private final String i18nKey; + + private Cols(String i18nKey) { + this.i18nKey = i18nKey; + } + + public String i18nKey() { + return i18nKey; + } + } + + private static class ThreadsDataModel extends DefaultTableDataModel<ThreadView> { + public ThreadsDataModel(List<ThreadView> threads) { + super(threads); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int row, int col) { + ThreadView view = getObject(row); + switch(Cols.values()[col]) { + case name: return view.getName(); + case state: return view.getState().name(); + case cpuPercent: return view.getCpuUsagePercent(); + case cpuTime: { + long timeInNanoSeconds = view.getCpuTime(); + return (double)timeInNanoSeconds / (1000.0d * 1000.0d * 1000.0d); + } + default: return "ERROR"; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/JavaVMController.java b/src/main/java/org/olat/admin/sysinfo/JavaVMController.java index acf4a9a7618..2d2527c94ca 100644 --- a/src/main/java/org/olat/admin/sysinfo/JavaVMController.java +++ b/src/main/java/org/olat/admin/sysinfo/JavaVMController.java @@ -21,6 +21,12 @@ package org.olat.admin.sysinfo; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.segmentedview.SegmentViewComponent; +import org.olat.core.gui.components.segmentedview.SegmentViewEvent; +import org.olat.core.gui.components.segmentedview.SegmentViewFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; @@ -33,10 +39,32 @@ import org.olat.core.gui.control.controller.BasicController; */ public class JavaVMController extends BasicController { + private final Link memoryLink, threadsLink, envPropsLink; + private final SegmentViewComponent segmentView; + private final VelocityContainer mainVC; + + private JavaMemoryController memoryCtrl; + private JavaThreadsController threadsCtrl; + private JavaEnvironmmentPropertiesController envPropsCtrl; + public JavaVMController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); + + mainVC = createVelocityContainer("segments"); + segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this); + memoryLink = LinkFactory.createLink("java.memory", mainVC, this); + segmentView.addSegment(memoryLink, true); + + threadsLink = LinkFactory.createLink("java.threads", mainVC, this); + segmentView.addSegment(threadsLink, false); + envPropsLink = LinkFactory.createLink("java.envProps", mainVC, this); + segmentView.addSegment(envPropsLink, false); + + mainVC.put("segments", segmentView); + doOpenMemory(ureq); + putInitialPanel(mainVC); } @Override @@ -46,12 +74,43 @@ public class JavaVMController extends BasicController { @Override protected void event(UserRequest ureq, Component source, Event event) { - // + if(source == segmentView) { + if(event instanceof SegmentViewEvent) { + SegmentViewEvent sve = (SegmentViewEvent)event; + String segmentCName = sve.getComponentName(); + Component clickedLink = mainVC.getComponent(segmentCName); + if (clickedLink == memoryLink) { + doOpenMemory(ureq); + } else if (clickedLink == threadsLink) { + doOpenThreads(ureq); + } else if (clickedLink == envPropsLink) { + doOpenEnvProps(ureq); + } + } + } } - - - + private void doOpenMemory(UserRequest ureq) { + if(memoryCtrl == null) { + memoryCtrl = new JavaMemoryController(ureq, getWindowControl()); + listenTo(memoryCtrl); + } + mainVC.put("segmentCmp", memoryCtrl.getInitialComponent()); + } + private void doOpenThreads(UserRequest ureq) { + if(threadsCtrl == null) { + threadsCtrl = new JavaThreadsController(ureq, getWindowControl()); + listenTo(threadsCtrl); + } + mainVC.put("segmentCmp", threadsCtrl.getInitialComponent()); + } + private void doOpenEnvProps(UserRequest ureq) { + if(envPropsCtrl == null) { + envPropsCtrl = new JavaEnvironmmentPropertiesController(ureq, getWindowControl()); + listenTo(envPropsCtrl); + } + mainVC.put("segmentCmp", envPropsCtrl.getInitialComponent()); + } } diff --git a/src/main/java/org/olat/admin/sysinfo/SysinfoController.java b/src/main/java/org/olat/admin/sysinfo/SysinfoController.java index a92912b368c..811f66f4a3b 100644 --- a/src/main/java/org/olat/admin/sysinfo/SysinfoController.java +++ b/src/main/java/org/olat/admin/sysinfo/SysinfoController.java @@ -28,45 +28,25 @@ package org.olat.admin.sysinfo; import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; -import java.lang.management.MemoryPoolMXBean; -import java.lang.management.MemoryType; -import java.lang.management.MemoryUsage; -import java.text.SimpleDateFormat; +import java.lang.management.MemoryMXBean; +import java.util.Calendar; import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Properties; import org.olat.basesecurity.BaseSecurity; -import org.olat.basesecurity.BaseSecurityManager; -import org.olat.basesecurity.Constants; import org.olat.core.CoreSpringFactory; -import org.olat.core.commons.chiefcontrollers.BaseChiefController; import org.olat.core.dispatcher.DispatcherAction; import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.link.Link; -import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.tabbedpane.TabbedPane; -import org.olat.core.gui.components.tabbedpane.TabbedPaneChangedEvent; -import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.DefaultController; -import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.helpers.Settings; -import org.olat.core.id.context.ContextEntry; -import org.olat.core.id.context.StateEntry; -import org.olat.core.logging.OLATSecurityException; -import org.olat.core.servlets.WebDAVManager; +import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; -import org.olat.core.util.resource.OresHelper; /** @@ -75,255 +55,147 @@ import org.olat.core.util.resource.OresHelper; * * @author Felix Jost */ -public class SysinfoController extends BasicController implements Activateable2 { - - private static final String ACTION_INFOMSG = "infomsg"; - private static final String ACTION_SYSINFO = "sysinfo"; - - private VelocityContainer mySysinfo; - - private TabbedPane tabbedPane; - private Link gcButton; - private Controller clusterController; - private Controller infoMsgCtrl; +public class SysinfoController extends FormBasicController { + + private final BaseSecurity securityManager; /** * @param ureq * @param wControl */ public SysinfoController(UserRequest ureq, WindowControl wControl) { - super(ureq, wControl); - - BaseSecurity mgr = BaseSecurityManager.getInstance(); - if (!mgr.isIdentityPermittedOnResourceable( - ureq.getIdentity(), - Constants.PERMISSION_ACCESS, - OresHelper.lookupType(this.getClass()))) - throw new OLATSecurityException("Insufficient permissions to access SysinfoController"); - - - mySysinfo = createVelocityContainer("sysinfo"); - gcButton = LinkFactory.createButton("run.gc", mySysinfo, this); - // add system startup time - SimpleDateFormat startupTimeFormatter = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", ureq.getLocale()); - mySysinfo.contextPut("startupTime", startupTimeFormatter.format(new Date(WebappHelper.getTimeOfServerStartup()))); + super(ureq, wControl, "sysinfo"); - - - - //info message controller has two implementations (SingleVM or cluster) - InfoMessageManager InfoMgr = (InfoMessageManager)CoreSpringFactory.getBean(InfoMessageManager.class); - infoMsgCtrl = InfoMgr.getInfoMessageController(ureq, getWindowControl()); - - tabbedPane = new TabbedPane("tp", ureq.getLocale()); - tabbedPane.addTab(ACTION_INFOMSG,infoMsgCtrl.getInitialComponent()); - //fxdiff: FXOLAT-79 check fxadmin-rights - tabbedPane.addTab(ACTION_SYSINFO, mySysinfo); - - //fxdiff: no cluster anyway: -// AutoCreator controllerCreator = (AutoCreator)CoreSpringFactory.getBean("clusterAdminControllerCreator"); -// clusterController = controllerCreator.createController(ureq, wControl); -// tabbedPane.addTab("Cluster", clusterController.getInitialComponent()); - - VelocityContainer myBuildinfo = createVelocityContainer("buildinfo"); - fillBuildInfoTab(myBuildinfo); - tabbedPane.addTab("buildinfo", myBuildinfo); + securityManager = CoreSpringFactory.getImpl(BaseSecurity.class); - tabbedPane.addListener(this); - putInitialPanel(tabbedPane); + initForm(ureq); } - private void fillBuildInfoTab(VelocityContainer myBuildinfo) { - List<Map> properties = new LinkedList<Map>(); - Map<String, String> m = new HashMap<String, String>(); - m.put("key", "Version"); - m.put("value", Settings.getFullVersionInfo()); - properties.add(m); - - m = new HashMap<String, String>(); - m.put("key", "HG changeset on build"); - m.put("value", Settings.getRepoRevision()); - properties.add(m); - - m = new HashMap<String, String>(); - m.put("key", "isClusterMode"); - m.put("value", Settings.getClusterMode().equals("Cluster") ? "true" : "false" ); - properties.add(m); - - m = new HashMap<String, String>(); - m.put("key", "nodeId"); - m.put("value", Settings.getNodeInfo().equals("") ? "N1" : Settings.getNodeInfo()); - properties.add(m); - - m = new HashMap<String, String>(); - m.put("key", "serverStartTime"); - final Date timeOfServerStartup = new Date(WebappHelper.getTimeOfServerStartup()); - m.put("value", String.valueOf(timeOfServerStartup)); - properties.add(m); - - m = new HashMap<String, String>(); - m.put("key", "Build date"); - m.put("value", String.valueOf(Settings.getBuildDate())); - properties.add(m); - + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + Formatter format = Formatter.getInstance(getLocale()); + + //runtime informations + FormLayoutContainer runtimeCont = FormLayoutContainer.createDefaultFormLayout("runtime", getTranslator()); + formLayout.add(runtimeCont); + formLayout.add("runtime", runtimeCont); + + String startup = format.formatDateAndTime(new Date(WebappHelper.getTimeOfServerStartup())); + uifactory.addStaticTextElement("runtime.startup", "runtime.startup", startup, runtimeCont); + + Calendar lastLoginMonthlyLimit = Calendar.getInstance(); + //users monthly + lastLoginMonthlyLimit.add(Calendar.MONTH, -1); + Long userLastMonth = securityManager.countUniqueUserLoginsSince(lastLoginMonthlyLimit.getTime()); + lastLoginMonthlyLimit.add(Calendar.MONTH, -5); // -1 -5 = -6 for half a year + Long userLastSixMonths = securityManager.countUniqueUserLoginsSince(lastLoginMonthlyLimit.getTime()); + uifactory.addStaticTextElement("users1month", "runtime.users.lastmonth", userLastMonth.toString(), runtimeCont); + uifactory.addStaticTextElement("users6month", "runtime.users.last6months", userLastSixMonths.toString(), runtimeCont); + + //users daily + Calendar lastLoginDailyLimit = Calendar.getInstance(); + lastLoginDailyLimit.add(Calendar.DAY_OF_YEAR, -1); + Long userLastDay = securityManager.countUniqueUserLoginsSince(lastLoginDailyLimit.getTime()); + lastLoginDailyLimit.add(Calendar.DAY_OF_YEAR, -6); // -1 - 6 = -7 for last week + Long userLast6Days = securityManager.countUniqueUserLoginsSince(lastLoginDailyLimit.getTime()); + uifactory.addStaticTextElement("userslastday", "runtime.users.lastday", userLastDay.toString(), runtimeCont); + uifactory.addStaticTextElement("userslastweek", "runtime.users.lastweek", userLast6Days.toString(), runtimeCont); + + //memory + String memoryPage = velocity_root + "/memory.html"; + FormLayoutContainer memoryCont = FormLayoutContainer.createCustomFormLayout("memory", getTranslator(), memoryPage); + runtimeCont.add(memoryCont); + memoryCont.contextPut("used", getHeapValue()); + memoryCont.contextPut("tooltip", getHeapTooltip()); + memoryCont.setLabel("runtime.memory", null); + + FormLayoutContainer permGenCont = FormLayoutContainer.createCustomFormLayout("permgen", getTranslator(), memoryPage); + runtimeCont.add(permGenCont); + permGenCont.contextPut("used", getNonHeapValue()); + permGenCont.contextPut("tooltip", getNonHeapTooltip()); + permGenCont.setLabel("runtime.memory.permGen", null); + + //controllers + int controllerCnt = DefaultController.getControllerCount(); + uifactory.addStaticTextElement("controllercount", "runtime.controllercount", Integer.toString(controllerCnt), runtimeCont); + int numOfDispatchingThreads = DispatcherAction.getConcurrentCounter(); + uifactory.addStaticTextElement("dispatchingthreads", "runtime.dispatchingthreads", Integer.toString(numOfDispatchingThreads), runtimeCont); + + //server informations + FormLayoutContainer serverCont = FormLayoutContainer.createDefaultFormLayout("server", getTranslator()); + formLayout.add(serverCont); + formLayout.add("server", serverCont); + + //version + uifactory.addStaticTextElement("version", "sysinfo.version", Settings.getFullVersionInfo(), serverCont); + uifactory.addStaticTextElement("version.hg", "sysinfo.version.hg", Settings.getRepoRevision(), serverCont); + String buildDate = format.formatDateAndTime(Settings.getBuildDate()); + uifactory.addStaticTextElement("version.date", "sysinfo.version.date", buildDate, serverCont); + + //cluster + boolean clusterMode = "Cluster".equals(Settings.getClusterMode()); + MultipleSelectionElement clusterEl + = uifactory.addCheckboxesHorizontal("cluster", "sysinfo.cluster", serverCont, new String[]{"xx"}, new String[]{""}, null); + clusterEl.setEnabled(false); + clusterEl.select("xx", clusterMode); + + String nodeId = StringHelper.containsNonWhitespace(Settings.getNodeInfo()) ? Settings.getNodeInfo() : "N1"; + uifactory.addStaticTextElement("node", "sysinfo.node", nodeId, serverCont); + File baseDir = new File(WebappHelper.getContextRoot(), ".."); - m = new HashMap<String, String>(); + String baseDirPath = null; try { - m.put("key", "baseDir"); - m.put("value", baseDir.getCanonicalPath()); + baseDirPath = baseDir.getCanonicalPath(); } catch (IOException e1) { - // then fall back to unresolved path - m.put("key", "baseDir"); - m.put("value", baseDir.getAbsolutePath()); + baseDirPath = baseDir.getAbsolutePath(); } - properties.add(m); - - m = new HashMap<String, String>(); - m.put("key", "jsMathEnabled"); - boolean jsMathEnabled = BaseChiefController.isJsMathEnabled(); - m.put("value", Boolean.toString(jsMathEnabled)); - properties.add(m); - - m = new HashMap<String, String>(); - m.put("key", "WebDAVEnabled"); - boolean webDavEnabled = WebDAVManager.getInstance().isEnabled(); - m.put("value", Boolean.toString(webDavEnabled)); - properties.add(m); - - myBuildinfo.contextPut("properties", properties); + uifactory.addStaticTextElement("sysinfo.basedir", "sysinfo.basedir", baseDirPath, serverCont); } - - - - @Override - //fxdiff BAKS-7 Resume function - public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { - if(entries != null && entries.isEmpty()) return; - tabbedPane.activate(ureq, entries, state); + + private String getHeapValue() { + MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); + long used = memoryBean.getHeapMemoryUsage().getUsed(); + long max = memoryBean.getHeapMemoryUsage().getMax(); + return toPercent(used, max); } - - /** - * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) - */ - public void event(UserRequest ureq, Component source, Event event) { - if (source == tabbedPane) { // those must be links - TabbedPaneChangedEvent tbcEvent = (TabbedPaneChangedEvent)event; - Component newComponent = tbcEvent.getNewComponent(); - //fxdiff BAKS-7 Resume function - tabbedPane.addToHistory(ureq, getWindowControl()); - if (newComponent == infoMsgCtrl.getInitialComponent()) { - - } - - else if (newComponent == mySysinfo) { - Runtime r = Runtime.getRuntime(); - StringBuilder sb = new StringBuilder(); - appendFormattedKeyValue(sb, "Processors", new Integer(r.availableProcessors())); - appendFormattedKeyValue(sb, "Total Memory", StringHelper.formatMemory(r.totalMemory())); - appendFormattedKeyValue(sb, "Free Memory", StringHelper.formatMemory(r.freeMemory())); - appendFormattedKeyValue(sb, "Max Memory", StringHelper.formatMemory(r.maxMemory())); - - sb.append("<br />Detailed Memory Information (Init/Used/Max)<br/> "); - Iterator<MemoryPoolMXBean> iter = ManagementFactory.getMemoryPoolMXBeans().iterator(); - while (iter.hasNext()) { - MemoryPoolMXBean item = iter.next(); - String name = item.getName(); - MemoryType type = item.getType(); - appendFormattedKeyValue(sb, name, " Type: " + type); - MemoryUsage usage = item.getUsage(); - appendFormattedKeyValue(sb, "Usage", StringHelper.formatMemory(usage.getInit()) + "/" + StringHelper.formatMemory(usage.getUsed()) + "/" + StringHelper.formatMemory(usage.getMax())); - MemoryUsage peak = item.getPeakUsage(); - appendFormattedKeyValue(sb, "Peak", StringHelper.formatMemory(peak.getInit()) + "/" + StringHelper.formatMemory(peak.getUsed()) + "/" + StringHelper.formatMemory(peak.getMax())); - MemoryUsage collections = item.getCollectionUsage(); - if (collections!= null){ - appendFormattedKeyValue(sb, "Collections", StringHelper.formatMemory(collections.getInit()) + "/" + StringHelper.formatMemory(collections.getUsed()) + "/" + StringHelper.formatMemory(collections.getMax())); - } - sb.append("<hr/>"); - } - - int controllerCnt = DefaultController.getControllerCount(); - sb.append("<br />Controller Count (active and not disposed):"+controllerCnt); - sb.append("<br />Concurrent Dispatching Threads: "+DispatcherAction.getConcurrentCounter()); - mySysinfo.contextPut("memory", sb.toString()); - mySysinfo.contextPut("threads",getThreadsInfo()); - mySysinfo.contextPut("javaenv", getJavaenv()); - - } - } - else if (source == gcButton){ - Runtime.getRuntime().gc(); - getWindowControl().setInfo("Garbage collection done."); - event(ureq, tabbedPane, new TabbedPaneChangedEvent(null, mySysinfo)); - } - - + + private String getHeapTooltip() { + MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); + long used = toMB(memoryBean.getHeapMemoryUsage().getUsed()); + long max = toMB(memoryBean.getHeapMemoryUsage().getMax()); + return translate("runtime.memory.tooltip", new String[]{ Long.toString(used), Long.toString(max)}); } - - private String getJavaenv() { - Properties p = System.getProperties(); - Iterator it = p.keySet().iterator(); - StringBuilder props = new StringBuilder(); - int lineCut = 100; - while (it.hasNext()) { - String key = (String) it.next(); - props.append("<b>" + key + "</b> = "); - String value = p.getProperty(key); - if (value.length() <= lineCut) - props.append(value); - else { - props.append(value.substring(0, lineCut - key.length())); - while (value.length() > lineCut) { - value = "<br />" + value.substring(lineCut); - props.append(value.substring(0, value.length() > lineCut ? lineCut : value.length())); - } - } - props.append("<br />"); - } - return props.toString(); + + private String getNonHeapValue() { + MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); + long used = memoryBean.getNonHeapMemoryUsage().getUsed(); + long max = memoryBean.getNonHeapMemoryUsage().getMax(); + return toPercent(used, max); } - - - private void appendFormattedKeyValue(StringBuilder sb, String key, Object value) { - sb.append(" <b>"); - sb.append(key); - sb.append(":</b> "); - sb.append(value); - sb.append("<br />"); + private String getNonHeapTooltip() { + MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); + long used = toMB(memoryBean.getNonHeapMemoryUsage().getUsed()); + long max = toMB(memoryBean.getNonHeapMemoryUsage().getMax()); + return translate("runtime.memory.tooltip", new String[]{ Long.toString(used), Long.toString(max)}); } - private String getThreadsInfo() { - StringBuilder sb = new StringBuilder("<pre>threads:<br />"); - try { // to be sure - ThreadGroup tg = Thread.currentThread().getThreadGroup(); - int actCnt = tg.activeCount(); - int grpCnt = tg.activeGroupCount(); - sb.append("about "+actCnt +" threads, "+grpCnt+" groups<br /><br />"); - Thread[] threads = new Thread[actCnt]; - tg.enumerate(threads, true); - for (int i = 0; i < actCnt; i++) { - Thread tr = threads[i]; - if (tr != null) { // thread may have finished in the meantime - String name = tr.getName(); - boolean alive = tr.isAlive(); - boolean interrupted = tr.isInterrupted(); - sb.append("Thread: (alive = "+alive+", interrupted: "+interrupted+", group:"+tr.getThreadGroup().getName()+") "+name+"<br />"); - } - } - } - catch (Exception e) { - sb.append("exception occured:"+e.getMessage()); - } - return sb.toString()+"</pre>"; + private final String toPercent(long used, long max) { + double ratio = (double)used / (double)max; + double percent = ratio * 100.0d; + return Math.round(percent) + "%"; } - - /** - * - * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) - */ + + private final long toMB(long val) { + return val / (1024 * 1024); + } + protected void doDispose() { - if (clusterController != null) { - clusterController.dispose(); - } + // + } + + @Override + protected void formOK(UserRequest ureq) { + // } -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/ThreadInfosManager.java b/src/main/java/org/olat/admin/sysinfo/ThreadInfosManager.java new file mode 100644 index 00000000000..bfa8d954baf --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/ThreadInfosManager.java @@ -0,0 +1,139 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.admin.sysinfo; + +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.WorkThreadInformations; +import org.olat.restapi.system.Sampler; +import org.springframework.stereotype.Service; + +/** + * + * <h3>Description:</h3> + * + * Initial Date: 21 juin 2010 <br> + * @author srosse, stephane.rosse@frentix.com, www.frentix.com + */ +@Service +public class ThreadInfosManager implements Sampler { + + private static final OLog log = Tracing.createLoggerFor(ThreadInfosManager.class); + + private final static NumberFormat percentFormat = NumberFormat.getPercentInstance(Locale.ENGLISH); + + private long prevUpTime; + private Map<Long,ThreadView> threadMap = new HashMap<Long,ThreadView>(); + + public List<ThreadView> getThreadViews() { + if(threadMap.isEmpty()) { + takeSample(); + } + + List<ThreadView> threads = new ArrayList<ThreadView>(threadMap.values()); + Collections.sort(threads); + return threads; + } + + @Override + public synchronized void takeSample() { + updateTimeSeries(); + } + + + private void updateTimeSeries() { + ThreadMXBean threadProxy = ManagementFactory.getThreadMXBean(); + RuntimeMXBean runtimeProxy = ManagementFactory.getRuntimeMXBean(); + ThreadInfo tis[] = threadProxy.dumpAllThreads(false, false); + + List<String> currentThreadNames = new ArrayList<String>(); + + Set<Long> currentThreadIds = new HashSet<Long>(); + for (ThreadInfo ti : tis) { + if (!threadMap.containsKey(ti.getThreadId())) { + ThreadView threadVO = new ThreadView(); + threadVO.setId(ti.getThreadId()); + threadVO.setName(ti.getThreadName()); + threadVO.setState(ti.getThreadState()); + threadMap.put(ti.getThreadId(), threadVO); + } + currentThreadIds.add(ti.getThreadId()); + } + WorkThreadInformations.currentThreadNames(currentThreadNames); + + for (ThreadView threadVO:threadMap.values()) { + threadVO.setPrevCpuTime(Math.max(0, threadVO.getCpuTime())); + threadVO.setCpuTime(Math.max(0, threadProxy.getThreadCpuTime(threadVO.getId()))); + } + + long upTime = runtimeProxy.getUptime(); + if (prevUpTime > 0L && upTime > prevUpTime) { + // elapsedTime is in ms + long elapsedTime = upTime - prevUpTime; + for (ThreadView threadVO:threadMap.values()) { + // elapsedCpu is in ns + long elapsedCpu = threadVO.getCpuTime() - threadVO.getPrevCpuTime(); + // cpuUsage could go higher than 100% because elapsedTime + // and elapsedCpu are not fetched simultaneously. Limit to + // 99% to avoid Chart showing a scale from 0% to 200%. + float cpuUsage = Math.min(99f, elapsedCpu / (elapsedTime * 1000000F)); + threadVO.setCpuUsage(cpuUsage); + threadVO.setCpuUsagePercent(percentFormat.format(cpuUsage)); + + if(cpuUsage > 0.8) { + threadVO.setWarningCounter(threadVO.getWarningCounter() + 1); + if(threadVO.getWarningCounter() >= 2) { + String currentWork = WorkThreadInformations.get(threadVO.getName()); + if(currentWork == null) { + currentWork = "unkown"; + } + log.info("High usage on thread:" + threadVO + " because thread work at: " + currentWork); + } + } else { + threadVO.setWarningCounter(0); + } + } + } + prevUpTime = upTime; + + //clean-up closed threads + for (Iterator<Map.Entry<Long,ThreadView>> it=threadMap.entrySet().iterator(); it.hasNext(); ) { + Map.Entry<Long,ThreadView> entry = it.next(); + if(!currentThreadIds.contains(entry.getKey())) { + it.remove(); + } + } + } +} diff --git a/src/main/java/org/olat/admin/sysinfo/ThreadView.java b/src/main/java/org/olat/admin/sysinfo/ThreadView.java new file mode 100644 index 00000000000..3817a56df0e --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/ThreadView.java @@ -0,0 +1,149 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.admin.sysinfo; + + +/** + * + * Initial date: 19.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ThreadView implements Comparable<ThreadView> { + + private long id; + private String name; + private String groupName; + private float cpuUsage; + private String cpuUsagePercent; + private long cpuTime; + private long prevCpuTime = 0l; + private int warningCounter = 0; + private Thread.State state; + + + public ThreadView() { + // + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public float getCpuUsage() { + return cpuUsage; + } + + public void setCpuUsage(float cpuUsage) { + this.cpuUsage = cpuUsage; + } + + public String getCpuUsagePercent() { + return cpuUsagePercent; + } + + public void setCpuUsagePercent(String cpuUsagePercent) { + this.cpuUsagePercent = cpuUsagePercent; + } + + /** + * @return CPU time in nanoseconds + */ + public long getCpuTime() { + return cpuTime; + } + + public void setCpuTime(long cpuTime) { + this.cpuTime = cpuTime; + } + + public long getPrevCpuTime() { + return prevCpuTime; + } + + public void setPrevCpuTime(long prevCpuTime) { + this.prevCpuTime = prevCpuTime; + } + + public int getWarningCounter() { + return warningCounter; + } + + public void setWarningCounter(int warningCounter) { + this.warningCounter = warningCounter; + } + + public Thread.State getState() { + return state; + } + + public void setState(Thread.State state) { + this.state = state; + } + + @Override + public int compareTo(ThreadView o) { + return name.compareToIgnoreCase(o.name); + } + + @Override + public int hashCode() { + return (int)id; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof ThreadView) { + ThreadView thread = (ThreadView)obj; + return id == thread.id; + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ThreadInfo[id=").append(id).append(":name=").append(name).append(":cpu=").append(cpuUsagePercent).append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/_content/buildinfo.html b/src/main/java/org/olat/admin/sysinfo/_content/buildinfo.html deleted file mode 100644 index d8d6620cba1..00000000000 --- a/src/main/java/org/olat/admin/sysinfo/_content/buildinfo.html +++ /dev/null @@ -1,19 +0,0 @@ -<h4>$r.translate("buildinfo")</h4> -<p/> -<fieldset> - <legend>Server</legend> - <table class="b_table b_grid"> - <thead> - <tr> - <th>key</th> - <th>value</th> - </tr> - </thead> - #foreach($property in $properties) - <tr> - <td>$property.key</td> - <td>$property.value</td> - </tr> - #end - </table> -</fieldset> diff --git a/src/main/java/org/olat/admin/sysinfo/_content/coreinfo.html b/src/main/java/org/olat/admin/sysinfo/_content/coreinfo.html new file mode 100644 index 00000000000..6cba385909f --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/_content/coreinfo.html @@ -0,0 +1,5 @@ +<fieldset><legend>$r.translate("core.functions")</legend> +$r.render("functions") +</fieldset> + + diff --git a/src/main/java/org/olat/admin/sysinfo/_content/hibernateinfo.html b/src/main/java/org/olat/admin/sysinfo/_content/hibernateinfo.html index 739b74b350f..5ded1263058 100644 --- a/src/main/java/org/olat/admin/sysinfo/_content/hibernateinfo.html +++ b/src/main/java/org/olat/admin/sysinfo/_content/hibernateinfo.html @@ -1,11 +1,13 @@ -<h4>$r.translate("title.hibernate.statistics")</h4> +<div class="o_buttons_box_right"> #if ($isStatisticsEnabled) - $r.render("disable.hibernate.statistics") , $r.render("clear.hibernate.statistics") + $r.render("disable.hibernate.statistics") $r.render("clear.hibernate.statistics") #else $r.render("enable.hibernate.statistics") #end -<br> -<br> +</div> + +<br/><br/> +<fieldset><legend>$r.translate("title.hibernate.statistics")</legend> Hibernate.ConnectCount : $hibernateStatistics.connectCount<br> Hibernate.FlushCount : $hibernateStatistics.flushCount<br> Hibernate.SessionOpenCount : $hibernateStatistics.sessionOpenCount<br> @@ -19,16 +21,19 @@ Hibernate.QueryCacheHitCount : $hibernateStatistics.queryCacheHitCount<br> Hibernate.QueryCacheMissCount : $hibernateStatistics.queryCacheMissCount<br> Hibernate.TransactionCount : $hibernateStatistics.transactionCount<br> Hibernate.SuccessfulTransactionCount : $hibernateStatistics.successfulTransactionCount<br> -<br> -<h4>List all queries</h4> +</fieldset> + +<fieldset><legend>List all queries</legend> #foreach ($query in $hibernateStatistics.queries) <b>$query</b><br> $hibernateStatistics.getQueryStatistics($query)<br> #end -<br> -<h4>List all entities </h4> +</fieldset> + +<fieldset><legend>List all entities</legend> #foreach ($entity in $hibernateStatistics.entityNames) <b>$entity</b><br> $hibernateStatistics.getEntityStatistics($entity)<br> #end +</fieldset> diff --git a/src/main/java/org/olat/admin/sysinfo/_content/infomsg.html b/src/main/java/org/olat/admin/sysinfo/_content/infomsg.html index b4651b1d184..f9a098df1d5 100644 --- a/src/main/java/org/olat/admin/sysinfo/_content/infomsg.html +++ b/src/main/java/org/olat/admin/sysinfo/_content/infomsg.html @@ -1,6 +1,8 @@ -<p> - <i>Message Admin-Token: $!admintoken</i> -</p> +<fieldset> + <legend>Admin.</legend> + <p><i>Message Admin-Token: $!admintoken</i></p> +</fieldset> + <fieldset> <legend>$r.translate("infomsg.title")</legend> diff --git a/src/main/java/org/olat/admin/sysinfo/_content/jvm_envprops.html b/src/main/java/org/olat/admin/sysinfo/_content/jvm_envprops.html new file mode 100644 index 00000000000..9f14c774df4 --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/_content/jvm_envprops.html @@ -0,0 +1,4 @@ +<fieldset><legend>$r.translate("java.envProps.title")</legend> +$r.render("javaenv") +</fieldset> + diff --git a/src/main/java/org/olat/admin/sysinfo/_content/jvm_memory.html b/src/main/java/org/olat/admin/sysinfo/_content/jvm_memory.html new file mode 100644 index 00000000000..062521d2105 --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/_content/jvm_memory.html @@ -0,0 +1,5 @@ + +<fieldset><legend>$r.translate("sysinfo.memory")</legend> +$r.render("run.gc") +</fieldset> +$memory \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/_content/jvm_threads.html b/src/main/java/org/olat/admin/sysinfo/_content/jvm_threads.html new file mode 100644 index 00000000000..a9525561389 --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/_content/jvm_threads.html @@ -0,0 +1,5 @@ +<fieldset><legend>$r.translate("java.threads.title")</legend> +$r.render("threads") +</fieldset> + + diff --git a/src/main/java/org/olat/admin/sysinfo/_content/memory.html b/src/main/java/org/olat/admin/sysinfo/_content/memory.html new file mode 100644 index 00000000000..25c04eb8931 --- /dev/null +++ b/src/main/java/org/olat/admin/sysinfo/_content/memory.html @@ -0,0 +1,3 @@ +<div class="o_eff_statement_progress" ext:qtip="${tooltip}"> + <div class="o_eff_statement_solved" style="width:${used}"> </div> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/admin/sysinfo/_content/sysinfo.html b/src/main/java/org/olat/admin/sysinfo/_content/sysinfo.html index 67456f116a6..a2488072ea8 100644 --- a/src/main/java/org/olat/admin/sysinfo/_content/sysinfo.html +++ b/src/main/java/org/olat/admin/sysinfo/_content/sysinfo.html @@ -1,14 +1,8 @@ -<h4>$r.translate("sysinfo")</h4> -<p> - $r.translate("sysinfo.startuptime") : $startupTime -</p> -<h4>$r.translate("sysinfo.memory")</h4> -$memory -<br><br> -$r.render("run.gc") -<br> -<h4>Current Threads</h4> -$threads -<br> -<h4>JAVA Environment Properties</h4> -$javaenv +<fieldset><legend>$r.translate("runtime")</legend> +$r.render("runtime") +</fieldset> + +<fieldset><legend>$r.translate("sysinfo")</legend> +$r.render("server") +</fieldset> + diff --git a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties index 91580387c2c..e4d367a029d 100644 --- a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties @@ -6,6 +6,10 @@ buildinfo=Build Information clear.hibernate.statistics=Hibernate Statistik l\u00F6schen disable.hibernate.statistics=Hibernate Statistik ausschalten enable.hibernate.statistics=Hibernate Statistik einschalten +core.functions=Funktionen Ubersicht +core.webdav=WebDAV +core.jsMath=JS Math +core.restapi=REST API error.date=Datum error.format=(tt.mm.jjjj) error.number=Fehlernummer @@ -41,6 +45,19 @@ loglevels=Log levels loglevels.title=Log4J log levels resetloglevels=Alle loglevels auf INFO zur\u00FCcksetzen run.gc=Run garbage collection +java.memory=Memory +java.threads=Threads +java.threads.title=Current threads +java.thread.name=Name +java.thread.group=Gruppe +java.thread.alive=Alive +java.thread.interrupted=Interrupted +java.thread.cpu.percent=CPU % +java.thread.cpu.time=CPU Zeit +java.envProps=Environment properties +java.envProps.title=Java Environment properties +java.envprops.name=Name +java.envprops.value=Wert sess.access=Letzter Zugriff sess.active = Anzahl der Nutzer, die in den letzten {0} Minuten geklickt haben sess.attributes.title=Attribute @@ -90,6 +107,23 @@ snoop=Snoop sysinfo=Systeminformation sysinfo.memory=Speicherinformation sysinfo.startuptime=Server Startzeit +sysinfo.version=Version +sysinfo.version.hg=Mercurial Version +sysinfo.version.date=Build Datum +sysinfo.cluster=Cluster +sysinfo.basedir=Root Ordner +sysinfo.node=Node +runtime=Runtime infos +runtime.startup=Startup +runtime.users.lastmonth=Active users within last month +runtime.users.last6months=Active users within last six months +runtime.users.lastday=Active users within last day +runtime.users.lastweek=Active users within last week +runtime.controllercount=Controllers (active and not disposed) +runtime.dispatchingthreads=Concurrent Dispatching Threads +runtime.memory=Memory +runtime.memory.permGen=Memory (Perm. gen.) +runtime.memory.tooltip={0} MB von {1} MB available title.hibernate.statistics=Hibernate Datenbank Zugriff Statistik usersession.title=Information \u00FCber Benutzer-Sessions filesystemtest=File System Test (Verteilte File Tests mit write/read für clustering). Wichtig nicht auf produktiven Systemen starten, kann zu Performance Problemen führen! diff --git a/src/main/java/org/olat/admin/sysinfo/_spring/sysinfoContext.xml b/src/main/java/org/olat/admin/sysinfo/_spring/sysinfoContext.xml index e9f5111fff7..635808a1238 100644 --- a/src/main/java/org/olat/admin/sysinfo/_spring/sysinfoContext.xml +++ b/src/main/java/org/olat/admin/sysinfo/_spring/sysinfoContext.xml @@ -1,20 +1,26 @@ <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + + <context:component-scan base-package="org.olat.admin.sysinfo" /> + + <bean id="org.olat.admin.sysinfo.InfoMessageManager" + class="org.olat.admin.sysinfo.InfoMessageManager"> + <constructor-arg index="0" ref="coordinatorManager"/> + <constructor-arg index="1" value="${node.id}" /> + <property name="actionController"> + <!-- there are two versions of the infoMessageController (singleVM or Cluster versions). Dynamic creation based on the value in olat.properties--> + <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> + <property name="className" value="org.olat.admin.sysinfo.InfoMessageController${cluster.mode}"/> + </bean> + </property> + </bean> -<bean id="org.olat.admin.sysinfo.InfoMessageManager" - class="org.olat.admin.sysinfo.InfoMessageManager"> - <constructor-arg index="0" ref="coordinatorManager"/> - <constructor-arg index="1" value="${node.id}" /> - <property name="actionController"> - <!-- there are two versions of the infoMessageController (singleVM or Cluster versions). Dynamic creation based on the value in olat.properties--> - <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> - <property name="className" value="org.olat.admin.sysinfo.InfoMessageController${cluster.mode}"/> - </bean> - </property> -</bean> </beans> \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java b/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java index 031ddf790b7..d49300255ea 100644 --- a/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java +++ b/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java @@ -276,9 +276,22 @@ public abstract class GenericMainController extends MainLayoutBasicController im GenericTreeNode parentNode = (GenericTreeNode) gtm.getNodeById(childNodeEntry.getValue()); if (parentNode != null) { parentNode.addChild(childNode); - if (parentNode.getDelegate() == null) { - parentNode.setDelegate(childNode); - parentNode.setUserObject(childNode.getUserObject()); + if (parentNode.getDelegate() == null ) { + boolean addDelegate = true; + + //add delegate only if hte parent hasn't not a controller defined + Object uo = parentNode.getUserObject(); + if(uo instanceof GenericActionExtension) { + GenericActionExtension gae = (GenericActionExtension)uo; + if(StringHelper.containsNonWhitespace(gae.getClassNameOfCorrespondingController())) { + addDelegate = false; + } + } + + if(addDelegate) { + parentNode.setDelegate(childNode); + parentNode.setUserObject(childNode.getUserObject()); + } } } else { logWarn("Could not add navigation-menu (" + childNode.getTitle() + ") to parent:: " + childNodeEntry.getValue(), null); diff --git a/src/main/java/org/olat/restapi/system/ThreadsWebService.java b/src/main/java/org/olat/restapi/system/ThreadsWebService.java index 4ad9ac59706..4dc27698162 100644 --- a/src/main/java/org/olat/restapi/system/ThreadsWebService.java +++ b/src/main/java/org/olat/restapi/system/ThreadsWebService.java @@ -20,19 +20,10 @@ package org.olat.restapi.system; import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -40,9 +31,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.olat.core.logging.OLog; -import org.olat.core.logging.Tracing; -import org.olat.core.util.WorkThreadInformations; +import org.olat.admin.sysinfo.ThreadInfosManager; +import org.olat.admin.sysinfo.ThreadView; +import org.olat.core.CoreSpringFactory; import org.olat.restapi.system.vo.ThreadVO; import org.olat.restapi.system.vo.ThreadVOes; import org.olat.restapi.system.vo.ThreadsVO; @@ -55,13 +46,6 @@ import org.olat.restapi.system.vo.ThreadsVO; * @author srosse, stephane.rosse@frentix.com, www.frentix.com */ public class ThreadsWebService implements Sampler { - - private static final OLog log = Tracing.createLoggerFor(ThreadsWebService.class); - - private final static NumberFormat percentFormat = NumberFormat.getPercentInstance(Locale.ENGLISH); - - private long prevUpTime; - private Map<Long,ThreadVO> threadMap = new HashMap<Long,ThreadVO>(); @GET @Produces(MediaType.TEXT_PLAIN) @@ -83,11 +67,12 @@ public class ThreadsWebService implements Sampler { @Path("cpu") @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public synchronized Response getThreadsCpu() { - if(threadMap.isEmpty()) { - takeSample(); + List<ThreadView> threadViews = CoreSpringFactory.getImpl(ThreadInfosManager.class).getThreadViews(); + List<ThreadVO> threads = new ArrayList<ThreadVO>(threadViews.size()); + for(ThreadView view: threadViews) { + threads.add(new ThreadVO(view)); } - List<ThreadVO> threads = new ArrayList<ThreadVO>(threadMap.values()); Collections.sort(threads); ThreadVO[] threadVos = threads.toArray(new ThreadVO[threads.size()]); ThreadVOes voes = new ThreadVOes(); @@ -98,69 +83,6 @@ public class ThreadsWebService implements Sampler { @Override public synchronized void takeSample() { - updateTimeSeries(); - } - - private void updateTimeSeries() { - ThreadMXBean threadProxy = ManagementFactory.getThreadMXBean(); - RuntimeMXBean runtimeProxy = ManagementFactory.getRuntimeMXBean(); - ThreadInfo tis[] = threadProxy.dumpAllThreads(false, false); - - List<String> currentThreadNames = new ArrayList<String>(); - - Set<Long> currentThreadIds = new HashSet<Long>(); - for (ThreadInfo ti : tis) { - if (!threadMap.containsKey(ti.getThreadId())) { - ThreadVO threadVO = new ThreadVO(); - threadVO.setId(ti.getThreadId()); - threadVO.setName(ti.getThreadName()); - threadMap.put(ti.getThreadId(), threadVO); - } - currentThreadIds.add(ti.getThreadId()); - } - WorkThreadInformations.currentThreadNames(currentThreadNames); - - for (ThreadVO threadVO:threadMap.values()) { - threadVO.setPrevCpuTime(Math.max(0, threadVO.getCpuTime())); - threadVO.setCpuTime(Math.max(0, threadProxy.getThreadCpuTime(threadVO.getId()))); - } - - long upTime = runtimeProxy.getUptime(); - if (prevUpTime > 0L && upTime > prevUpTime) { - // elapsedTime is in ms - long elapsedTime = upTime - prevUpTime; - for (ThreadVO threadVO:threadMap.values()) { - // elapsedCpu is in ns - long elapsedCpu = threadVO.getCpuTime() - threadVO.getPrevCpuTime(); - // cpuUsage could go higher than 100% because elapsedTime - // and elapsedCpu are not fetched simultaneously. Limit to - // 99% to avoid Chart showing a scale from 0% to 200%. - float cpuUsage = Math.min(99f, elapsedCpu / (elapsedTime * 1000000F)); - threadVO.setCpuUsage(cpuUsage); - threadVO.setCpuUsagePercent(percentFormat.format(cpuUsage)); - - if(cpuUsage > 0.8) { - threadVO.setWarningCounter(threadVO.getWarningCounter() + 1); - if(threadVO.getWarningCounter() >= 2) { - String currentWork = WorkThreadInformations.get(threadVO.getName()); - if(currentWork == null) { - currentWork = "unkown"; - } - log.info("High usage on thread:" + threadVO + " because thread work at: " + currentWork); - } - } else { - threadVO.setWarningCounter(0); - } - } - } - prevUpTime = upTime; - - //clean-up closed threads - for (Iterator<Map.Entry<Long,ThreadVO>> it=threadMap.entrySet().iterator(); it.hasNext(); ) { - Map.Entry<Long,ThreadVO> entry = it.next(); - if(!currentThreadIds.contains(entry.getKey())) { - it.remove(); - } - } + CoreSpringFactory.getImpl(ThreadInfosManager.class).takeSample(); } -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/restapi/system/vo/ThreadVO.java b/src/main/java/org/olat/restapi/system/vo/ThreadVO.java index 2edaab1dccc..1b567c5c96f 100644 --- a/src/main/java/org/olat/restapi/system/vo/ThreadVO.java +++ b/src/main/java/org/olat/restapi/system/vo/ThreadVO.java @@ -23,7 +23,8 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlTransient; + +import org.olat.admin.sysinfo.ThreadView; /** * @@ -48,21 +49,23 @@ public class ThreadVO implements Comparable<ThreadVO> { private String cpuUsagePercent; @XmlAttribute(name="cpuTime") private long cpuTime; - @XmlTransient - private long prevCpuTime = 0l; - @XmlTransient - private int warningCounter = 0; public ThreadVO() { //make JAXB happy } - public ThreadVO(Long id, String name, Float cpuUsage) { + public ThreadVO(Long id, String name, float cpuUsage) { this.id = id; this.name = name; this.cpuUsage = cpuUsage; } + public ThreadVO(ThreadView view) { + this(view.getId(), view.getName(), view.getCpuUsage()); + cpuUsagePercent = view.getCpuUsagePercent(); + cpuTime = view.getCpuTime(); + } + public long getId() { return id; } @@ -103,22 +106,6 @@ public class ThreadVO implements Comparable<ThreadVO> { this.cpuTime = cpuTime; } - public long getPrevCpuTime() { - return prevCpuTime; - } - - public void setPrevCpuTime(long prevCpuTime) { - this.prevCpuTime = prevCpuTime; - } - - public int getWarningCounter() { - return warningCounter; - } - - public void setWarningCounter(int warningCounter) { - this.warningCounter = warningCounter; - } - @Override public int compareTo(ThreadVO o) { return name.compareToIgnoreCase(o.name); diff --git a/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml b/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml index 7fd2ad3c1db..ca1a32cf8a4 100644 --- a/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml +++ b/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml @@ -17,6 +17,11 @@ <!-- The system menu point --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> <property name="order" value="7100" /> + <property name="actionController"> + <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> + <property name="className" value="org.olat.admin.sysinfo.SysinfoController"/> + </bean> + </property> <property name="navigationKey" value="system" /> <property name="nodeIdentifierIfParent" value="systemParent" /> <property name="translationPackage" value="org.olat.admin" /> @@ -33,14 +38,14 @@ <property name="order" value="7110" /> <property name="actionController"> <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> - <property name="className" value="org.olat.admin.sysinfo.SysinfoController"/> + <property name="className" value="org.olat.admin.sysinfo.InfoMessageControllerSingleVM"/> </bean> </property> <property name="navigationKey" value="sysinfo" /> <property name="parentTreeNodeIdentifier" value="systemParent" /> <property name="translationPackage" value="org.olat.admin"/> - <property name="i18nActionKey" value="menu.sysinfo"/> - <property name="i18nDescriptionKey" value="menu.sysinfo.alt"/> + <property name="i18nActionKey" value="menu.infomsg"/> + <property name="i18nDescriptionKey" value="menu.infomsg.alt"/> <property name="extensionPoints"> <list> <value>org.olat.admin.SystemAdminMainController</value> @@ -148,6 +153,26 @@ </property> </bean> + <!-- System / java --> + <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> + <property name="order" value="7170" /> + <property name="actionController"> + <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> + <property name="className" value="org.olat.admin.sysinfo.JavaVMController"/> + </bean> + </property> + <property name="navigationKey" value="locks" /> + <property name="parentTreeNodeIdentifier" value="systemParent" /> + <property name="translationPackage" value="org.olat.admin"/> + <property name="i18nActionKey" value="menu.javavm"/> + <property name="i18nDescriptionKey" value="menu.javavm.alt"/> + <property name="extensionPoints"> + <list> + <value>org.olat.admin.SystemAdminMainController</value> + </list> + </property> + </bean> + <!-- The devel menu point --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> @@ -204,6 +229,11 @@ <!-- the "systemconfig" parent node --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> <property name="order" value="7200" /> + <property name="actionController"> + <bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype"> + <property name="className" value="org.olat.admin.sysinfo.CoreFunctionsController"/> + </bean> + </property> <property name="navigationKey" value="sysconfig" /> <property name="nodeIdentifierIfParent" value="sysconfigParent" /> <property name="translationPackage" value="org.olat.admin" /> @@ -227,7 +257,7 @@ <property name="translationPackage" value="org.olat.admin"/> <property name="i18nActionKey" value="menu.layout"/> <property name="i18nDescriptionKey" value="menu.layout.alt"/> - <property name="parentTreeNodeIdentifier" value="sysconfigParent" /> + <property name="parentTreeNodeIdentifier" value="sysAdminMenueNodeCustomizing" /> <property name="extensionPoints"> <list> <value>org.olat.admin.SystemAdminMainController</value> @@ -392,12 +422,11 @@ </list> </property> <property name="enabled" value="${instantMessaging.enable}"/> - <property name="parentTreeNodeIdentifier" value="sysconfigParent" /> + <property name="parentTreeNodeIdentifier" value="modulesParent" /> </bean> - <!-- SYSADMIN customizing parent node --> - <!-- + <!-- Customizing parent node --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> <property name="order" value="7400" /> <property name="navigationKey" value="customizing" /> @@ -411,9 +440,8 @@ </list> </property> </bean> - --> - <!-- "Sprachanpassungswerkzeug" --> + <!-- Customizin / "Sprachanpassungswerkzeug" --> <bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints"> <property name="order" value="7401" /> <property name="actionController"> @@ -431,7 +459,7 @@ <value>org.olat.admin.SystemAdminMainController</value> </list> </property> - <property name="parentTreeNodeIdentifier" value="sysconfigParent" /> + <property name="parentTreeNodeIdentifier" value="sysAdminMenueNodeCustomizing" /> </bean> <!-- System registration --> @@ -451,7 +479,7 @@ <value>org.olat.admin.SystemAdminMainController</value> </list> </property> - <property name="parentTreeNodeIdentifier" value="sysconfigParent" /> + <property name="parentTreeNodeIdentifier" value="sysAdminMenueNodeCustomizing" /> </bean> diff --git a/src/test/java/org/olat/restapi/SystemTest.java b/src/test/java/org/olat/restapi/SystemTest.java index 55a05971e3a..721cbdd3fe7 100644 --- a/src/test/java/org/olat/restapi/SystemTest.java +++ b/src/test/java/org/olat/restapi/SystemTest.java @@ -106,8 +106,6 @@ public class SystemTest extends OlatJerseyTestCase { Assert.assertTrue(threadVo.getCpuTime() >= 0); Assert.assertTrue(threadVo.getCpuUsage() >= 0.0f); Assert.assertTrue(threadVo.getId() > 0l); - Assert.assertTrue(threadVo.getPrevCpuTime() >= 0f); - Assert.assertTrue(threadVo.getWarningCounter() >= 0); conn.shutdown(); } -- GitLab