Skip to content
Snippets Groups Projects
Commit 9a2e1412 authored by Nils Christian Ehmke's avatar Nils Christian Ehmke
Browse files

Some minor modifications for quality reasons; Further development of the cockpit

parent 7df6f7b2
No related branches found
No related tags found
No related merge requests found
Showing
with 518 additions and 379 deletions
......@@ -22,4 +22,12 @@
<Bug code="RV" />
</Match>
<!-- Ignores the fact that our comparator doesn't implement the Serializable interface. There is no need to. Also it is not possible for this comparator, as it uses a map to compare some values. This "bug" can therefore be ignored. -->
<Match>
<Class name="kieker.webgui.web.utility.CockpitLayout$RowComparator" />
<Bug code="Se" />
</Match>
</FindBugsFilter>
\ No newline at end of file
......@@ -23,6 +23,7 @@ import kieker.analysis.AnalysisControllerThread;
import kieker.analysis.display.HtmlText;
import kieker.analysis.display.Image;
import kieker.analysis.display.PlainText;
import kieker.analysis.display.Plot;
import kieker.analysis.display.annotation.Display;
import kieker.analysis.plugin.AbstractPlugin;
import kieker.analysis.plugin.annotation.InputPort;
......@@ -70,6 +71,7 @@ public class ClassAndMethodContainer {
private Class<? extends Annotation> inputPortAnnotationClass;
private Class<? extends Annotation> repositoryPortAnnotationClass;
private Class<? extends Annotation> displayAnnotationClass;
private Class<?> plotClass;
/**
* Creates a new instance of this class, using the given class loader.
......@@ -98,6 +100,7 @@ public class ClassAndMethodContainer {
this.htmlTextClass = classLoader.loadClass(HtmlText.class.getName());
this.plainTextClass = classLoader.loadClass(PlainText.class.getName());
this.imageClass = classLoader.loadClass(Image.class.getName());
this.plotClass = classLoader.loadClass(Plot.class.getName());
// Now we load the more specific annotation classes
this.pluginAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Plugin.class.getName());
......@@ -192,4 +195,8 @@ public class ClassAndMethodContainer {
return this.logImplWebguiLoggingClass;
}
public Class<?> getPlotClass() {
return this.plotClass;
}
}
/***************************************************************************
* Copyright 2013 Kieker Project (http://kieker-monitoring.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package kieker.webgui.domain;
/**
* This enumeration represents the different display types within Kieker.
*
* @author Nils Christian Ehmke
*/
public enum DisplayType {
/** Represents the plot display type. */
TYPE_PLOT,
/** Represents the plain text display type. */
TYPE_PLAIN_TEXT,
/** Represents the Html text display type. */
TYPE_HTML_TEXT,
/** Represents the image display type. */
TYPE_IMAGE
}
......@@ -30,6 +30,7 @@ import kieker.webgui.common.exception.NewerProjectException;
import kieker.webgui.common.exception.ProjectAlreadyExistingException;
import kieker.webgui.common.exception.ProjectNotExistingException;
import kieker.webgui.domain.ComponentListContainer;
import kieker.webgui.domain.DisplayType;
import org.primefaces.model.UploadedFile;
......@@ -421,4 +422,18 @@ public interface IProjectService {
*/
@PreAuthorize("isAuthenticated()")
public abstract String getCockpitLayout(String projectName);
/**
* Delivers the type of the given display connector.
*
* @param projectName
* The name of the project.
* @param viewName
* The name of the view.
* @param displayConnectorName
* The name of the display connector.
*
* @return The type of the display connector.
*/
public DisplayType getDisplayType(final String projectName, final String viewName, final String displayConnectorName);
}
......@@ -32,6 +32,7 @@ import kieker.webgui.common.exception.NewerProjectException;
import kieker.webgui.common.exception.ProjectAlreadyExistingException;
import kieker.webgui.common.exception.ProjectNotExistingException;
import kieker.webgui.domain.ComponentListContainer;
import kieker.webgui.domain.DisplayType;
import kieker.webgui.persistence.IProjectDAO;
import kieker.webgui.service.IProjectService;
import kieker.webgui.service.impl.utility.ACManager;
......@@ -308,6 +309,15 @@ public class ProjectServiceImpl implements IProjectService {
}
}
@Override
public DisplayType getDisplayType(final String projectName, final String viewName, final String displayConnectorName) {
final Object analysisLock = this.getLock(projectName, this.analysesLocks);
synchronized (analysisLock) {
return this.acManager.getDisplayType(projectName, viewName, displayConnectorName);
}
}
private Object getFirstLock(final String projectA, final String projectB, final ConcurrentHashMap<String, Object> lockMap) {
if (projectA.compareTo(projectB) < 0) {
return this.getLock(projectA, lockMap);
......@@ -349,4 +359,5 @@ public class ProjectServiceImpl implements IProjectService {
return lock;
}
}
......@@ -23,6 +23,7 @@ import kieker.analysis.AnalysisController.STATE;
import kieker.webgui.common.exception.AnalysisInitializationException;
import kieker.webgui.common.exception.DisplayNotFoundException;
import kieker.webgui.common.exception.InvalidAnalysisStateException;
import kieker.webgui.domain.DisplayType;
import kieker.webgui.persistence.IProjectDAO;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -231,9 +232,29 @@ public class ACManager {
* The project to update.
*/
public void updateDisplays(final String projectName) {
if (this.analyses.containsKey(projectName)) {
if (this.analyses.containsKey(projectName) && (this.getCurrentState(projectName) == STATE.RUNNING)) {
this.analyses.get(projectName).updateDisplays();
}
}
/**
* Delivers the type of the given display connector.
*
* @param projectName
* The name of the project.
* @param viewName
* The name of the view.
* @param displayConnectorName
* The name of the display connector.
*
* @return The type of the display connector.
*/
public DisplayType getDisplayType(final String projectName, final String viewName, final String displayConnectorName) {
if (this.analyses.containsKey(projectName)) {
return this.analyses.get(projectName).getDisplayType(viewName, displayConnectorName);
} else {
return null;
}
}
}
......@@ -29,6 +29,7 @@ import kieker.webgui.common.ClassAndMethodContainer;
import kieker.webgui.common.exception.AnalysisInitializationException;
import kieker.webgui.common.exception.InvalidAnalysisStateException;
import kieker.webgui.common.exception.ReflectionException;
import kieker.webgui.domain.DisplayType;
import net.vidageek.mirror.dsl.Mirror;
import net.vidageek.mirror.exception.MirrorException;
......@@ -203,6 +204,9 @@ public class Analysis {
}
}
/**
* Updates the display objects within this analysis.
*/
public void updateDisplays() {
for (final String view : this.displayMethods.keySet()) {
for (final String display : this.displayMethods.get(view).keySet()) {
......@@ -214,4 +218,30 @@ public class Analysis {
}
}
}
/**
* Delivers the type of the given display connector.
*
* @param viewName
* The name of the view.
* @param displayConnectorName
* The name of the display connector.
*
* @return The type of the display connector.
*/
public DisplayType getDisplayType(final String viewName, final String displayConnectorName) {
final Object parameter = this.displayObjects.get(viewName).get(displayConnectorName);
if (parameter.getClass() == this.classAndMethodContainer.getImageClass()) {
return DisplayType.TYPE_IMAGE;
} else if (parameter.getClass() == this.classAndMethodContainer.getPlainTextClass()) {
return DisplayType.TYPE_PLAIN_TEXT;
} else if (parameter.getClass() == this.classAndMethodContainer.getHtmlTextClass()) {
return DisplayType.TYPE_HTML_TEXT;
} else if (parameter.getClass() == this.classAndMethodContainer.getPlotClass()) {
return DisplayType.TYPE_PLOT;
} else {
return null;
}
}
}
......@@ -35,6 +35,7 @@ import kieker.monitoring.core.registry.Registry;
import kieker.webgui.common.exception.DisplayNotFoundException;
import kieker.webgui.common.exception.InvalidAnalysisStateException;
import kieker.webgui.common.exception.ProjectLoadException;
import kieker.webgui.domain.DisplayType;
import kieker.webgui.service.IProjectService;
import kieker.webgui.web.beans.application.GlobalPropertiesBean;
import kieker.webgui.web.beans.application.ProjectsBean;
......@@ -58,7 +59,7 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* This class is a {@code Spring} managed bean with view scope containing the necessary data behind an instance of the cockpit.<br>
* This class is a {@code Spring} managed bean containing the necessary data behind an instance of the cockpit.<br>
* <br/>
*
* It has view scope to make sure that one user (even in one session) can open multiple projects at a time without causing any problems.
......@@ -71,24 +72,25 @@ public class CurrentCockpitBean {
private static final Log LOG = LogFactory.getLog(CurrentCockpitBean.class);
private static final String ID_PREFIX = "displayConnector_";
private static final int NUMBER_COLUMNS = 2;
private static final String DASHBOARD_ID = "dashboard";
private static final String PANEL_ID_PREFIX = "panel_";
private static final int NUMBER_OF_COCKPIT_COLUMNS = 2;
private final Registry<MIDisplayConnector> displayConnectors = new Registry<MIDisplayConnector>();
private CockpitLayout cockpitLayout;
private DashboardModel dashboardModel;
private Dashboard dashboard;
private String projectName;
private MIProject project;
private MIView activeView;
private Dashboard dashboard;
private DashboardModel dashboardModel;
@Autowired
private GlobalPropertiesBean globalPropertiesBean;
@Autowired
private IProjectService projectService;
@Autowired
private ProjectsBean projectsBean;
@Autowired
private GlobalPropertiesBean globalPropertiesBean;
private CockpitLayout cockpitLayout;
private final Registry<MIDisplayConnector> displayConnectors = new Registry<MIDisplayConnector>();
/**
* Creates a new instance of this class. <b>Do not call this constructor manually. It will only be accessed by Spring.</b>
......@@ -105,11 +107,12 @@ public class CurrentCockpitBean {
try {
// Make sure that the initialization will only be done for the init request.
if (!FacesContext.getCurrentInstance().isPostback()) {
// Remember the given parameters
this.project = this.projectsBean.openProject(this.projectName);
this.createDashboard();
this.loadProject();
this.cockpitLayout = new CockpitLayout(this.project, this.projectService.getCockpitLayout(this.projectName), NUMBER_COLUMNS);
if (this.project != null) {
this.createDashboardComponent();
this.loadCockpitLayout();
}
}
} catch (final ProjectLoadException ex) {
CurrentCockpitBean.LOG.error("An error occured while loading the project.", ex);
......@@ -122,91 +125,48 @@ public class CurrentCockpitBean {
}
/**
* Creates the initial dashboard object.
* Sets the active view to a new value and updates the dashboard.
*
* @param activeView
* The new active view.
*/
private void createDashboard() {
final FacesContext fc = FacesContext.getCurrentInstance();
final Application application = fc.getApplication();
// Create the primefaces dashboard
this.dashboard = (Dashboard) application.createComponent(fc, "org.primefaces.component.Dashboard", "org.primefaces.component.DashboardRenderer");
this.dashboard.setId("dashboard");
// Create the model and add the columns
this.dashboardModel = new DefaultDashboardModel();
for (int i = 0; i < CurrentCockpitBean.NUMBER_COLUMNS; i++) {
final DashboardColumn column = new DefaultDashboardColumn();
this.dashboardModel.addColumn(column);
}
this.dashboard.setModel(this.dashboardModel);
public void setActiveView(final MIView activeView) {
this.activeView = activeView;
this.fillDashboardWithActiveView();
}
/**
* Fills the initial dashboard object.
* Sets the dashboard of this bean.
*
* @param dashboard
* The new dashboard.
*/
private void fillDashboard() {
// Dump the old entries
this.clearDashboard();
// Now add the entries from the current view
if (this.activeView != null) {
final List<List<MIDisplayConnector>> layout = this.cockpitLayout.getCurrentLayout(this.activeView);
for (int col = 0; col < NUMBER_COLUMNS; col++) {
final DashboardColumn column = this.dashboard.getModel().getColumn(col);
for (final MIDisplayConnector displayConnector : layout.get(col)) {
final Panel panel = this.createPanelFromDisplayConnector(displayConnector);
public void setDashboard(final Dashboard dashboard) {
this.dashboard = dashboard;
this.dashboard.getChildren().add(panel);
column.addWidget(panel.getId());
}
}
}
// This step is necessary as we lose otherwise the dashboard model
this.dashboard.setModel(this.dashboardModel);
}
private Panel createPanelFromDisplayConnector(final MIDisplayConnector connector) {
final FacesContext fc = FacesContext.getCurrentInstance();
final Application application = fc.getApplication();
final Panel panel = (Panel) application.createComponent(fc, "org.primefaces.component.Panel", "org.primefaces.component.PanelRenderer");
final String id = this.displayConnectorToID(connector);
public MIView getActiveView() {
return this.activeView;
}
// Set the usual properties of the panel
panel.setId(id);
panel.setHeader(connector.getName());
panel.setClosable(true);
panel.setToggleable(false);
public Dashboard getDashboard() {
return this.dashboard;
}
final HtmlOutputText text = new HtmlOutputText();
text.setValue("N/A");
panel.getChildren().add(text);
/*
* final GraphicImage graphImg = (GraphicImage) application.createComponent(fc, "org.primefaces.component.GraphicImage",
* "org.primefaces.component.GraphicImageRenderer");
* try {
* final BufferedImage bufferedImg = new BufferedImage(100, 25, BufferedImage.TYPE_INT_RGB);
* final Graphics2D g2 = bufferedImg.createGraphics();
* g2.drawString("This is a text", 0, 10);
* final ByteArrayOutputStream os = new ByteArrayOutputStream();
* ImageIO.write(bufferedImg, "png", os);
* final StreamedContent graphicText = new DefaultStreamedContent(new ByteArrayInputStream(os.toByteArray()), "image/png");
*
* graphImg.setValue(graphicText);
* } catch (final Exception ex) {
* ex.printStackTrace();
* }
*
* panel.getChildren().add(graphImg);
*/
public MIProject getProject() {
return this.project;
}
return panel;
public void setProjectName(final String newName) {
this.projectName = newName;
}
private String displayConnectorToID(final MIDisplayConnector displayConnector) {
return ID_PREFIX + this.displayConnectors.get(displayConnector);
public String getProjectName() {
return this.projectName;
}
/**
......@@ -285,162 +245,213 @@ public class CurrentCockpitBean {
}
/**
* Clears the dashboard and removes all children within it.
* Updates all displays of the currently active view.
*/
private void clearDashboard() {
// Run through all columns of the dashboard and remove the items
final List<DashboardColumn> columns = this.dashboard.getModel().getColumns();
for (final DashboardColumn column : columns) {
column.getWidgets().clear();
public void updateDisplaysOfActiveView() {
if (this.projectName != null) {
for (final UIComponent component : this.dashboard.getChildren()) {
// Get the correct display type of the current component
final int componentID = Integer.valueOf(component.getId().replace(PANEL_ID_PREFIX, ""));
final MIDisplayConnector displayConnector = this.displayConnectors.get(componentID);
if (this.projectService.getCurrentState(this.projectName) != null) {
final DisplayType displayType = this.projectService.getDisplayType(this.projectName, this.activeView.getName(), displayConnector.getName());
// Update the element depending on the display type
switch (displayType) {
case TYPE_PLAIN_TEXT:
this.updatePlainTextDisplay(component, displayConnector.getName());
break;
case TYPE_HTML_TEXT:
this.updateHTMLTextDisplay(component, displayConnector.getName());
break;
case TYPE_IMAGE:
this.updateImageDisplay(component, displayConnector.getName());
break;
case TYPE_PLOT:
this.updatePlotDisplay(component, displayConnector.getName());
break;
default:
// Unknown type
this.updateDisplayWithDefaultContent(component);
break;
}
} else {
// If the analysis has not yet been initialized, we add a simple note to each of the panels
this.updateDisplayWithDefaultContent(component);
}
}
}
// Now run through the dashboard itself and remove the items as well
this.dashboard.getChildren().clear();
}
public MIProject getProject() {
return this.project;
private void loadCockpitLayout() {
this.cockpitLayout = new CockpitLayout(this.project, this.projectService.getCockpitLayout(this.projectName), NUMBER_OF_COCKPIT_COLUMNS);
}
public void setProjectName(final String newName) {
// Remember the given parameters
this.projectName = newName;
}
private void createDashboardComponent() {
final FacesContext facesContext = FacesContext.getCurrentInstance();
final Application application = facesContext.getApplication();
public String getProjectName() {
return this.projectName;
}
// Create the Primefaces dashboard component
this.dashboard = (Dashboard) application.createComponent(facesContext, "org.primefaces.component.Dashboard", "org.primefaces.component.DashboardRenderer");
this.dashboard.setId(DASHBOARD_ID);
public void updateDisplays() {
for (final UIComponent child : this.dashboard.getChildren()) {
final int id = Integer.valueOf(child.getId().replace(ID_PREFIX, ""));
final MIDisplayConnector conn = this.displayConnectors.get(id);
this.updatePlainTextDisplay(child, conn.getName());
this.updatePlotDisplay(child, conn.getName());
}
}
// Create the corresponding model with the correct number of columns
this.dashboard.setModel(new DefaultDashboardModel());
/**
* @param child
* @param name
*/
private void updatePlotDisplay(final UIComponent child, final String displayName) {
if ((this.activeView != null) && (this.projectName != null)) {
try {
final Object displayObj = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayName);
final Collection<Long> entries = (Collection<Long>) new Mirror().on(displayObj).invoke().method("getEntries").withoutArgs();
for (int i = 0; i < NUMBER_OF_COCKPIT_COLUMNS; i++) {
this.dashboard.getModel().addColumn(new DefaultDashboardColumn());
}
final FacesContext fc = FacesContext.getCurrentInstance();
// Remember the dashboard model
this.dashboardModel = this.dashboard.getModel();
}
final Application application = fc.getApplication();
private void loadProject() throws ProjectLoadException {
this.project = this.projectsBean.openProject(this.projectName);
}
child.getChildren().clear();
private void fillDashboardWithActiveView() {
// Dump the old entries
this.clearDashboard();
final LineChart lineChart = (LineChart) application.createComponent(fc, "org.primefaces.component.chart.LineChart",
"org.primefaces.component.chart.LineChartRenderer");
// Now add the entries from the active view
if (this.activeView != null) {
final List<List<MIDisplayConnector>> layout = this.cockpitLayout.getCurrentLayout(this.activeView);
lineChart.setTitle("Title");
final CartesianChartModel linearModel = new CartesianChartModel();
for (int columnIndex = 0; columnIndex < NUMBER_OF_COCKPIT_COLUMNS; columnIndex++) {
final DashboardColumn column = this.dashboard.getModel().getColumn(columnIndex);
final LineChartSeries series = new LineChartSeries();
series.setLabel("Series");
for (final MIDisplayConnector displayConnector : layout.get(columnIndex)) {
final Panel panel = this.createPanelFromDisplayConnector(displayConnector);
int i = 0;
for (final Long entry : entries) {
series.set(i, entry);
i++;
// Add the panel to the dashboard and to its model
this.dashboard.getChildren().add(panel);
column.addWidget(panel.getId());
}
linearModel.addSeries(series);
lineChart.setValue(linearModel);
child.getChildren().add(lineChart);
} catch (final DisplayNotFoundException ex) {
CurrentCockpitBean.LOG.warn("Display not found.", ex);
} catch (final MirrorException ex) {
CurrentCockpitBean.LOG.warn("Reflection exception.", ex);
} catch (final InvalidAnalysisStateException ex) {
CurrentCockpitBean.LOG.info("Project is in invalid state.", ex);
}
}
}
/**
* Delivers the current content for the given display as plain text.
*
* @param displayName
* The name of the display.
* @return The current content of the display, if it exists. If the display does not exist or the active view is not set 'N/A' will be returned. If an access to
* the display fails, "Error" will be returned.
*/
public void updatePlainTextDisplay(final UIComponent child, final String displayName) {
if ((this.activeView != null) && (this.projectName != null)) {
try {
final FacesContext fc = FacesContext.getCurrentInstance();
fc.getApplication();
child.getChildren().clear();
final Object displayObj = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayName);
final String text = (String) new Mirror().on(displayObj).invoke().method("getText").withoutArgs();
final HtmlOutputText t = new HtmlOutputText();
t.setValue(text);
child.getChildren().add(t);
} catch (final DisplayNotFoundException ex) {
CurrentCockpitBean.LOG.warn("Display not found.", ex);
} catch (final MirrorException ex) {
CurrentCockpitBean.LOG.warn("Reflection exception.", ex);
} catch (final InvalidAnalysisStateException ex) {
CurrentCockpitBean.LOG.info("Project is in invalid state.", ex);
}
private void clearDashboard() {
// Run through all columns of the dashboard and remove the items
final List<DashboardColumn> columns = this.dashboard.getModel().getColumns();
for (final DashboardColumn column : columns) {
column.getWidgets().clear();
}
// Now clear the dashboard itself
this.dashboard.getChildren().clear();
}
/**
* Delivers the current content for the given display as html text.
*
* @return Currently this method returns only N/A.
*/
public String updateHtmlTextDisplay() {
return "N/A";
private Panel createPanelFromDisplayConnector(final MIDisplayConnector connector) {
final FacesContext facesContext = FacesContext.getCurrentInstance();
final Application application = facesContext.getApplication();
// Create the Primefaces panel component
final Panel panel = (Panel) application.createComponent(facesContext, "org.primefaces.component.Panel", "org.primefaces.component.PanelRenderer");
// Set the usual properties of the panel
panel.setId(this.displayConnectorToID(connector));
panel.setHeader(connector.getName());
panel.setClosable(false);
panel.setToggleable(false);
return panel;
}
/**
* Delivers the current content for the given display as Image link.
*
* @return Currently this method returns only N/A.
*/
public String updateImageDisplay() {
return "N/A";
private String displayConnectorToID(final MIDisplayConnector displayConnector) {
return PANEL_ID_PREFIX + this.displayConnectors.get(displayConnector);
}
public MIView getActiveView() {
return this.activeView;
private void updateDisplayWithDefaultContent(final UIComponent component) {
component.getChildren().clear();
final HtmlOutputText htmlOutputText = new HtmlOutputText();
htmlOutputText.setValue("N/A");
component.getChildren().add(htmlOutputText);
}
/**
* Sets the active view to a new value.
*
* @param activeView
* The new active view.
*/
public void setActiveView(final MIView activeView) {
this.activeView = activeView;
private void updateHTMLTextDisplay(final UIComponent component, final String displayConnectorName) { // NOPMD (Not implemented yet)
// Not implemented yet
this.updateDisplayWithDefaultContent(component);
}
this.fillDashboard();
private void updateImageDisplay(final UIComponent component, final String displayConnectorName) { // NOPMD (Not implemented yet)
// Not implemented yet
this.updateDisplayWithDefaultContent(component);
}
public Dashboard getDashboard() {
return this.dashboard;
private void updatePlainTextDisplay(final UIComponent component, final String displayConnectorName) {
try {
component.getChildren().clear();
final Object displayObject = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayConnectorName);
final String text = (String) new Mirror().on(displayObject).invoke().method("getText").withoutArgs();
final HtmlOutputText htmlOutputText = new HtmlOutputText();
htmlOutputText.setValue(text);
component.getChildren().add(htmlOutputText);
} catch (final DisplayNotFoundException ex) {
CurrentCockpitBean.LOG.warn("Display not found.", ex);
this.updateDisplayWithDefaultContent(component);
} catch (final MirrorException ex) {
CurrentCockpitBean.LOG.warn("Reflection exception.", ex);
this.updateDisplayWithDefaultContent(component);
} catch (final InvalidAnalysisStateException ex) {
CurrentCockpitBean.LOG.info("Project is in invalid state.", ex);
this.updateDisplayWithDefaultContent(component);
}
}
/**
* Setter for the property {@link CurrentCockpitEditorBean#dashboard}.
*
* @param dashboard
* The new value for the property.
*/
public void setDashboard(final Dashboard dashboard) {
this.dashboard = dashboard;
this.dashboard.setModel(this.dashboardModel);
@SuppressWarnings("unchecked")
private void updatePlotDisplay(final UIComponent component, final String displayConnectorName) {
try {
component.getChildren().clear();
final FacesContext facesContext = FacesContext.getCurrentInstance();
final Application application = facesContext.getApplication();
final Object displayObj = this.projectService.getDisplay(this.projectName, this.activeView.getName(), displayConnectorName);
final Collection<Long> entries = (Collection<Long>) new Mirror().on(displayObj).invoke().method("getEntries").withoutArgs();
// Create the Primefaces chart component
final LineChart lineChart = (LineChart) application.createComponent(facesContext, "org.primefaces.component.chart.LineChart",
"org.primefaces.component.chart.LineChartRenderer");
lineChart.setTitle(displayConnectorName);
// Add the corresponding model
final CartesianChartModel linearModel = new CartesianChartModel();
final LineChartSeries series = new LineChartSeries();
series.setLabel("Series");
if (entries.isEmpty()) {
series.set(0, 0);
} else {
int x = 0;
for (final Long entry : entries) {
series.set(x++, entry);
}
}
linearModel.addSeries(series);
lineChart.setValue(linearModel);
component.getChildren().add(lineChart);
} catch (final DisplayNotFoundException ex) {
CurrentCockpitBean.LOG.warn("Display not found.", ex);
this.updateDisplayWithDefaultContent(component);
} catch (final MirrorException ex) {
CurrentCockpitBean.LOG.warn("Reflection exception.", ex);
this.updateDisplayWithDefaultContent(component);
} catch (final InvalidAnalysisStateException ex) {
CurrentCockpitBean.LOG.info("Project is in invalid state.", ex);
this.updateDisplayWithDefaultContent(component);
}
}
}
......@@ -61,7 +61,6 @@ import org.primefaces.component.dashboard.Dashboard;
import org.primefaces.component.panel.Panel;
import org.primefaces.context.RequestContext;
import org.primefaces.event.DashboardReorderEvent;
import org.primefaces.event.TabChangeEvent;
import org.primefaces.model.DashboardColumn;
import org.primefaces.model.DashboardModel;
import org.primefaces.model.DefaultDashboardColumn;
......@@ -72,7 +71,9 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* The {@link CurrentCockpitEditorBean} contains the necessary data behind an instance of the cockpit editor.
* The {@link CurrentCockpitEditorBean} contains the necessary data behind an instance of the cockpit editor.<br>
* </br>
*
* The class is a Spring managed bean with view scope to make sure that one user (even in one session) can open multiple projects at a time without causing any
* problems.
*
......@@ -84,34 +85,35 @@ public class CurrentCockpitEditorBean {
private static final Log LOG = LogFactory.getLog(CurrentCockpitEditorBean.class);
private static final String ID_PREFIX = "displayConnector_";
private static final int NUMBER_COLUMNS = 2;
private static final String DASHBOARD_ID = "dashboard";
private static final String PANEL_ID_PREFIX = "displayConnector_";
private static final int NUMBER_OF_COCKPIT_COLUMNS = 2;
private final Registry<MIDisplayConnector> displayConnectors = new Registry<MIDisplayConnector>();
private final MIAnalysisMetaModelFactory factory = MAnalysisMetaModelFactory.eINSTANCE;
@Autowired
private IProjectService projectService;
private ComponentListContainer availableComponents;
private long currId;
private long timeStamp;
private CockpitLayout cockpitLayout;
private boolean unsavedModifications;
private String projectName;
private MIProject project;
private boolean unsavedModifications;
private long timeStampSinceLastSaving;
private MIDisplayConnector selectedNode;
private MIView activeView;
private Dashboard dashboard;
private DashboardModel dashboardModel;
@Autowired
private ProjectsBean projectsBean;
private Dashboard dashboard;
@Autowired
private GlobalPropertiesBean globalPropertiesBean;
@Autowired
private IProjectService projectService;
@Autowired
private ProjectsBean projectsBean;
@Autowired
private UserBean userBean;
private MIDisplayConnector selectedNode = null;
private final Registry<MIDisplayConnector> displayConnectors = new Registry<MIDisplayConnector>();
private CockpitLayout cockpitLayout;
/**
* Creates a new instance of this class. <b>Do not call this constructor manually. It will only be accessed by Spring.</b>
*/
......@@ -128,15 +130,14 @@ public class CurrentCockpitEditorBean {
try {
// Make sure that the initialization will only be done for the init request.
if (!FacesContext.getCurrentInstance().isPostback()) {
// Remember the given parameters
this.project = this.projectsBean.openProject(this.projectName);
this.loadProject();
if (this.project != null) {
// Remember the current time! This is important for the later comparison of the time stamps.
this.resetTimeStamp();
this.reloadComponents();
this.reloadAvailableComponents();
this.createDashboard();
this.cockpitLayout = new CockpitLayout(this.project, this.projectService.getCockpitLayout(this.projectName), NUMBER_COLUMNS);
this.createDashboardComponent();
this.loadCockpitLayout();
}
this.unsavedModifications = false;
......@@ -150,37 +151,132 @@ public class CurrentCockpitEditorBean {
}
}
public boolean isUnsavedModification() {
return this.unsavedModifications;
}
private void loadCockpitLayout() {
this.cockpitLayout = new CockpitLayout(this.project, this.projectService.getCockpitLayout(this.projectName), NUMBER_OF_COCKPIT_COLUMNS);
}
private void loadProject() throws ProjectLoadException {
this.project = this.projectsBean.openProject(this.projectName);
}
/**
* Delivers the currently selected display connector.
* This is a dummy method returning just a collection of null objects. This is necessary due to Primefaces.
*
* @return The selected connector.
* @return A collection with three null objects.
*/
public MIDisplayConnector getSelectedNode() {
return this.selectedNode;
public Collection<Object> getProperties() {
return Collections.nCopies(3, null);
}
/**
* Creates the initial dashboard object.
* This method sets the time stamp to the current system time.
*/
private void createDashboard() {
final FacesContext fc = FacesContext.getCurrentInstance();
final Application application = fc.getApplication();
public void resetTimeStamp() {
this.timeStampSinceLastSaving = System.currentTimeMillis();
}
public MIView getActiveView() {
return this.activeView;
}
/**
* Sets the active view and updates the dashboard.
*
* @param view
* The new view.
*/
public void setActiveView(final MIView view) {
this.activeView = view;
this.fillDashboard();
}
/**
* Deletes the given view from the model.
*
* @param view
* The view to be removed.
*
*/
public void deleteView(final MIView view) {
this.project.getViews().remove(view);
this.cockpitLayout.removeView(view);
// Create the Primefaces dashboard
this.dashboard = (Dashboard) application.createComponent(fc, "org.primefaces.component.Dashboard", "org.primefaces.component.DashboardRenderer");
this.dashboard.setId("dashboard");
this.setModificationsFlag();
}
// Create the model and add the columns
this.dashboardModel = new DefaultDashboardModel();
for (int i = 0; i < NUMBER_COLUMNS; i++) {
final DashboardColumn column = new DefaultDashboardColumn();
this.dashboardModel.addColumn(column);
/**
* This method adds a new view to the project.
*
* @param viewName
* The name of the new view.
*/
public void addView(final String viewName) {
if (this.project != null) {
// Create the view and add it to our project
final MIView view = this.factory.createView();
view.setName(viewName);
view.setDescription("No description available.");
this.project.getViews().add(view);
this.cockpitLayout.addView(view);
this.setModificationsFlag();
}
}
public Dashboard getDashboard() {
return this.dashboard;
}
/**
* Setter for the property {@link CurrentCockpitEditorBean#dashboard}.
*
* @param dashboard
* The new value for the property.
*/
public void setDashboard(final Dashboard dashboard) {
this.dashboard = dashboard;
this.dashboard.setModel(this.dashboardModel);
}
public boolean isUnsavedModification() {
return this.unsavedModifications;
public MIProject getProject() {
return this.project;
}
public void setProjectName(final String newName) {
this.projectName = newName;
}
public String getProjectName() {
return this.projectName;
}
public MIDisplayConnector getSelectedNode() {
return this.selectedNode;
}
private void createDashboardComponent() {
final FacesContext facesContext = FacesContext.getCurrentInstance();
final Application application = facesContext.getApplication();
// Create the Primefaces dashboard component
this.dashboard = (Dashboard) application.createComponent(facesContext, "org.primefaces.component.Dashboard", "org.primefaces.component.DashboardRenderer");
this.dashboard.setId(DASHBOARD_ID);
// Create the corresponding model with the correct number of columns
this.dashboard.setModel(new DefaultDashboardModel());
for (int i = 0; i < NUMBER_OF_COCKPIT_COLUMNS; i++) {
this.dashboard.getModel().addColumn(new DefaultDashboardColumn());
}
// Remember the dashboard model
this.dashboardModel = this.dashboard.getModel();
}
/**
......@@ -195,7 +291,7 @@ public class CurrentCockpitEditorBean {
final List<List<MIDisplayConnector>> layout = this.cockpitLayout.getCurrentLayout(this.activeView);
for (int col = 0; col < NUMBER_COLUMNS; col++) {
for (int col = 0; col < NUMBER_OF_COCKPIT_COLUMNS; col++) {
final DashboardColumn column = this.dashboard.getModel().getColumn(col);
for (final MIDisplayConnector displayConnector : layout.get(col)) {
......@@ -208,29 +304,26 @@ public class CurrentCockpitEditorBean {
}
}
private void reloadComponents() {
this.availableComponents = this.projectService.getAvailableComponents(this.projectName);
}
public MIProject getProject() {
return this.project;
}
/**
* This is a dummy method returning just a collection of null objects. This is necessary due to Primefaces.
*
* @return A collection with two null objects.
* This method sets the property {@link CurrentCockpitEditorBean#unsavedModifications} to false and refreshes the necessary components within the editor to make
* this visible.
*/
public Collection<Object> getProperties() {
return Collections.nCopies(3, null);
private void clearModificationsFlag() {
this.unsavedModifications = false;
RequestContext.getCurrentInstance().update("menuForm");
}
public void setProjectName(final String newName) {
this.projectName = newName;
/**
* This method sets the property {@link CurrentCockpitEditorBean#unsavedModifications} to true and refreshes the necessary components within the editor
* to make this visible.
*/
private void setModificationsFlag() {
this.unsavedModifications = true;
RequestContext.getCurrentInstance().update("menuForm");
}
public String getProjectName() {
return this.projectName;
private void reloadAvailableComponents() {
this.availableComponents = this.projectService.getAvailableComponents(this.projectName);
}
/**
......@@ -277,7 +370,7 @@ public class CurrentCockpitEditorBean {
*/
public void saveProject(final boolean overwriteNewerProject) {
try {
this.projectService.saveProject(this.projectName, this.project, this.timeStamp, overwriteNewerProject, this.userBean.getUsername(), null,
this.projectService.saveProject(this.projectName, this.project, this.timeStampSinceLastSaving, overwriteNewerProject, this.userBean.getUsername(), null,
this.cockpitLayout.serializeToString());
GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, this.globalPropertiesBean.getMsgProjectSaved());
// Update the time stamp!
......@@ -298,81 +391,6 @@ public class CurrentCockpitEditorBean {
}
}
/**
* This method sets the property {@link CurrentCockpitEditorBean#unsavedModifications} to false and refreshes the necessary components within the editor to make
* this visible.
*/
private void clearModificationsFlag() {
this.unsavedModifications = false;
RequestContext.getCurrentInstance().update("menuForm");
}
/**
* This method sets the property {@link CurrentCockpitEditorBean#unsavedModifications} to true and refreshes the necessary components within the editor
* to make this visible.
*/
private void setModificationsFlag() {
this.unsavedModifications = true;
RequestContext.getCurrentInstance().update("menuForm");
}
/**
* This method sets the time stamp to the current system time.
*/
public void resetTimeStamp() {
this.timeStamp = System.currentTimeMillis();
}
/**
* This method adds a new view to the project.
*
* @param viewName
* The name of the new view.
*/
public void addView(final String viewName) {
if (this.project != null) {
// Create the view and add it to our project
final MIView view = this.factory.createView();
view.setName(viewName);
view.setDescription("No description available.");
this.project.getViews().add(view);
this.cockpitLayout.addView(view);
this.setModificationsFlag();
}
}
public MIView getActiveView() {
return this.activeView;
}
/**
* Sets the active view and updates the dashboard.
*
* @param view
* The new view.
*/
public void setActiveView(final MIView view) {
this.activeView = view;
this.fillDashboard();
}
/**
* Deletes the given view from the model.
*
* @param view
* The view to be removed.
*
*/
public void deleteView(final MIView view) {
this.project.getViews().remove(view);
this.cockpitLayout.removeView(view);
this.setModificationsFlag();
}
private Panel createPanelFromDisplayConnector(final MIDisplayConnector connector) {
final FacesContext fc = FacesContext.getCurrentInstance();
final Application application = fc.getApplication();
......@@ -414,6 +432,8 @@ public class CurrentCockpitEditorBean {
this.activeView.getDisplayConnectors().remove(connector);
this.cockpitLayout.removeDisplayConnector(this.activeView, connector);
this.setModificationsFlag();
}
}
......@@ -427,7 +447,7 @@ public class CurrentCockpitEditorBean {
if (this.activeView != null) {
final MIDisplayConnector connector = this.factory.createDisplayConnector();
connector.setDisplay(display);
connector.setName("Display " + this.currId);
connector.setName("Display " + this.displayConnectors.getSize() + 1);
this.activeView.getDisplayConnectors().add(connector);
// Now add it to the dashboard as well
......@@ -443,6 +463,12 @@ public class CurrentCockpitEditorBean {
}
}
/**
* This handler should be executed when the user moves an element within the dashboard.
*
* @param event
* The move event.
*/
public void handleReorder(final DashboardReorderEvent event) {
final MIDisplayConnector connector = this.idToDisplayConnector(event.getWidgetId());
......@@ -455,6 +481,8 @@ public class CurrentCockpitEditorBean {
}
this.cockpitLayout.moveDisplayConnector(this.activeView, connector, senderIndex, event.getColumnIndex(), event.getItemIndex());
this.setModificationsFlag();
}
/**
......@@ -474,18 +502,6 @@ public class CurrentCockpitEditorBean {
}
}
/**
* This event is used if the currently selected tab changes. It modifies the active view property within this bean.
*
* @param event
* The onChange-event.
*/
public void onChange(final TabChangeEvent event) {
if (event.getData() instanceof MIView) {
this.setActiveView((MIView) event.getData());
}
}
/**
* This is the event if a node has been clicked and should be selected.
*/
......@@ -501,26 +517,6 @@ public class CurrentCockpitEditorBean {
}
}
/**
* Getter for the property {@link CurrentCockpitEditorBean#dashboard}.
*
* @return The current value of the property.
*/
public Dashboard getDashboard() {
return this.dashboard;
}
/**
* Setter for the property {@link CurrentCockpitEditorBean#dashboard}.
*
* @param dashboard
* The new value for the property.
*/
public void setDashboard(final Dashboard dashboard) {
this.dashboard = dashboard;
this.dashboard.setModel(this.dashboardModel);
}
/**
* This method checks whether a display connector with the given name exists already.
*
......@@ -553,16 +549,17 @@ public class CurrentCockpitEditorBean {
for (final DashboardColumn column : columns) {
column.getWidgets().clear();
}
// Now remove the items from the dashboard
this.dashboard.getChildren().clear();
}
private String displayConnectorToID(final MIDisplayConnector displayConnector) {
return ID_PREFIX + this.displayConnectors.get(displayConnector);
return PANEL_ID_PREFIX + this.displayConnectors.get(displayConnector);
}
private MIDisplayConnector idToDisplayConnector(final String id) {
final String shortID = id.substring(ID_PREFIX.length());
final String shortID = id.substring(PANEL_ID_PREFIX.length());
final int intID = Integer.valueOf(shortID);
return this.displayConnectors.get(intID);
......
......@@ -60,7 +60,6 @@
<ui:define name="furtherLayoutUnits">
<p:layoutUnit position="west" size="300" header="Views" resizable="true" collapsible="true">
<h:form id="viewForm">
<p:poll interval="1" listener="#{currentCockpitBean.updateDisplays()}" update=":centerForm"/>
<p:dataList value="#{currentCockpitBean.project.views}" var="currView">
<p:commandLink style="#{currView == currentCockpitBean.activeView ? 'font-weight:bold' : ''}" value="#{currView.name}" action="#{currentCockpitBean.setActiveView(currView)}" id="viewLink" update=":viewForm"/>
<p:tooltip for="viewLink">
......@@ -98,8 +97,13 @@
<h:outputText value="#{localizedMessages.stateFailed}"/>
</h:panelGrid>
</h:form>
<h:form>
<p:poll interval="1" listener="#{currentCockpitBean.updateDisplaysOfActiveView()}" update=":centerForm :ledsForm"/>
</h:form>
</div>
</p:layoutUnit>
</ui:define>
</ui:composition>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment