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

Added dialogs for renaming, copying and deleting projects; Fixed some bugs;...

Added dialogs for renaming, copying and deleting projects; Fixed some bugs; Added code to get the available views; Plugins can now be renamed within a project
parent 3b865fd1
Branches
Tags
No related merge requests found
Showing with 253 additions and 12 deletions
......@@ -111,6 +111,16 @@ public final class ProjectsBean {
}
}
public void renameProject(final String projectName, final String newName) {
try {
FSManager.getInstance().renameProject(projectName, newName);
} catch (final IOException ex) {
ProjectsBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while renaming the project.");
} catch (final ProjectAlreadyExistingException ex) {
ProjectsBean.showMessage(FacesMessage.SEVERITY_WARN, "A project with the same name exists already.");
}
}
/**
* This method can be used to get the current time stamp of a given project as a human readable date. If the project doesn't exist or the time stamp would be
* invalid, the date of 0 is returned.
......
......@@ -20,9 +20,18 @@
package kieker.webgui.beans.session;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import kieker.webgui.common.FSManager;
import org.primefaces.model.DashboardColumn;
import org.primefaces.model.DashboardModel;
import org.primefaces.model.DefaultDashboardColumn;
import org.primefaces.model.DefaultDashboardModel;
/**
* This bean contains the project of the current (session) user for the analysis cockpit.
*
......@@ -45,12 +54,30 @@ public class CurrentAnalysisCockpitProjectBean {
* This is the name of the stored project. It can be used as an identifier within the FS-Manager
*/
private String projectName;
private DashboardModel model;
/**
* Creates a new instance of this class.
*/
public CurrentAnalysisCockpitProjectBean() {
// No code necessary
// This code is just for test purposes
this.model = new DefaultDashboardModel();
final DashboardColumn column1 = new DefaultDashboardColumn();
column1.addWidget("panel1");
column1.addWidget("panel2");
this.model.addColumn(column1);
}
public DashboardModel getModel() {
return this.model;
}
public void setModel(final DashboardModel model) {
this.model = model;
}
/**
......@@ -85,4 +112,8 @@ public class CurrentAnalysisCockpitProjectBean {
return CurrentAnalysisCockpitProjectBean.PAGE_PROJECT_OVERVIEW;
}
public List<String> getViews() {
return FSManager.getInstance().getAllViews(this.projectName);
}
}
/***************************************************************************
* Copyright 2012 by
* + Christian-Albrechts-University of Kiel
* + Department of Computer Science
* + Software Engineering Group
* and others.
*
* 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.beans.view;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
/**
*
* @author Nils Christian Ehmke
*/
@ManagedBean
@ViewScoped
public class CurrentProjectOverviewBean {
private String projectName;
public CurrentProjectOverviewBean() {
// No code necessary
}
public String getProjectName() {
return this.projectName;
}
public void setProjectName(final String projectName) {
this.projectName = projectName;
}
}
......@@ -198,9 +198,13 @@ public class ACManager {
*
* @param project
* The project whose state should be delivered.
* @return The current state of the corresponding {@link AnalysisController} if it exists, 'N/A' otherwise.
* @return The current state of the corresponding {@link AnalysisController} if it exists, null otherwise.
*/
public STATE getAnalysisControllerState(final String project) {
// If the given project is null, we return a null-state.
if (project == null) {
return null;
}
final Pair<AnalysisController, Thread> controller = this.analysisController.get(project);
final STATE controllerState;
......
......@@ -57,6 +57,9 @@ import org.primefaces.model.UploadedFile;
* This class uses also a fine grained synchronization to handle the access to the projects.
*
* @author Nils Christian Ehmke
*
* TODO Projects have to check their lock once they entered the synchronized block in order to make sure that they have still the valid one (and not a
* removed one from an older project)
*/
public final class FSManager {
......@@ -202,7 +205,7 @@ public final class FSManager {
// Load it atomically
synchronized (lock) {
return AnalysisController.loadFromFile(kaxFile);
return AnalysisController.loadFromFile(kaxFile.getAbsoluteFile());// /kaxFile);
}
}
......@@ -242,6 +245,87 @@ public final class FSManager {
}
}
public void renameProject(final String projectName, final String newName) throws IOException, ProjectAlreadyExistingException {
if (projectName.equals(newName)) {
throw new ProjectAlreadyExistingException("A project with the name '" + newName + "' exists already.");
}
// Get both locks
final Object lockOld = this.getLock(projectName);
final Object lockNew = this.getLock(newName);
// We cannot risk just using two synchronized-blocks as such a thing could block the application. We therefore have to sort the locks by name in order to
// make sure that two methods would use the same order to access (if project A has to be renamed to B and B has to be renamed to A, we would always
// synchronize on A before synchronizing on B).
final Object lockFst = (projectName.compareTo(newName)) < 0 ? lockOld : lockNew;
final Object lockSnd = (projectName.compareTo(newName)) < 0 ? lockNew : lockOld;
// Access the projects atomically
synchronized (lockFst) {
synchronized (lockSnd) {
// Check whether the project exists already!
if (this.projectExists(newName)) {
throw new ProjectAlreadyExistingException("A project with the name '" + newName + "' exists already.");
}
// Otherwise copy the project and delete the old one
this.copyProject(projectName, newName);
this.deleteProject(projectName);
}
}
}
private void deleteProject(final String projectName) {
// TODO Delete
}
private void copyProject(final String projectName, final String newName) throws ProjectAlreadyExistingException, IOException {
if (projectName.equals(newName)) {
throw new ProjectAlreadyExistingException("A project with the name '" + newName + "' exists already.");
}
// Get both locks
final Object lockOld = this.getLock(projectName);
final Object lockNew = this.getLock(newName);
// We cannot risk just using two synchronized-blocks as such a thing could block the application. We therefore have to sort the locks by name in order to
// make sure that two methods would use the same order to access.
final Object lockFst = (projectName.compareTo(newName)) < 0 ? lockOld : lockNew;
final Object lockSnd = (projectName.compareTo(newName)) < 0 ? lockNew : lockOld;
// Access the projects atomically
synchronized (lockFst) {
synchronized (lockSnd) {
// Check whether the project exists already!
if (this.projectExists(newName)) {
throw new ProjectAlreadyExistingException("A project with the name '" + newName + "' exists already.");
}
// TODO Copy all files
}
}
}
public List<String> getAllViews(final String project) {
final List<String> result = new ArrayList<String>();
// Get all files within the view-dir
final File[] files = new File(FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + FSManager.VIEW_DIRECTORY).listFiles();
for (final File file : files) {
if (file.isFile()) {
result.add(file.getName());
}
}
return result;
}
private boolean projectExists(final String project) {
// Assemble the path to the given project
final String fileName = FSManager.ROOT_DIRECTORY + File.separator + project;
final File file = new File(fileName);
return file.exists();
}
/**
* Returns a list containing all available projects on the FS as a string.
*
......
......@@ -41,12 +41,22 @@
<p:layoutUnit position="center" id="centerLayout">
<p:dashboard id="board" model="#{currentAnalysisCockpitProjectBean.model}">
<p:panel id="panel1" header="N/A">
<h:outputText value="N/A" />
</p:panel>
<p:panel id="panel2" header="N/A">
<h:outputText value="N/A" />
</p:panel>
</p:dashboard>
</p:layoutUnit>
<p:layoutUnit position="west" size="300" header="Views" resizable="true" collapsible="true">
<h:form id="viewsForm">
<p:accordionPanel multiple="true" activeIndex="">
<p:accordionPanel multiple="true" activeIndex="" value="#{currentAnalysisCockpitProjectBean.views}" var="currView">
<p:tab title="#{currView}">
<h:outputText value="Some description here."/>
</p:tab>
</p:accordionPanel>
</h:form>
</p:layoutUnit>
......
......@@ -46,23 +46,23 @@
<h:outputText value="#{project}" />
</p:column>
<p:column headerText="Owner">
<p:column headerText="Owner" style="text-align: center">
<h:outputText value="N/A" />
</p:column>
<p:column headerText="Last Modification" sortBy="#{projectsBean.getCurrTimeStamp(project)}">
<p:column headerText="Last Modification" sortBy="#{projectsBean.getCurrTimeStamp(project)}" style="text-align: center">
<h:outputText value="#{projectsBean.getCurrTimeStamp(project)}" />
</p:column>
<p:column headerText="Analysis" style="text-align: center">
<p:column headerText="Analysis" style="text-align: center" sortBy="#{projectsBean.getAnalysisControllerState(project)}">
<h:outputText value="#{projectsBean.getAnalysisControllerState(project)}"/>
</p:column>
<p:column headerText="Options" style="text-align: center; width: 280px">
<p:commandButton id="openButton" ajax="false" action="#{currentWorkSpaceProjectBean.setProject(projectsBean.openProject(project), project)}" icon="ui-icon-folder-open"/>
<p:commandButton id="copyButton" icon="ui-icon-copy"/>
<p:commandButton id="renameButton" icon="ui-icon-pencil"/>
<p:commandButton id="deleteButton" icon="ui-icon-trash"/>
<p:commandButton id="copyButton" icon="ui-icon-copy" action="#{currentProjectOverviewBean.setProjectName(project)}" onclick="copyProjectDialog.show()"/>
<p:commandButton id="renameButton" icon="ui-icon-pencil" action="#{currentProjectOverviewBean.setProjectName(project)}" onclick="renameProjectDialog.show()"/>
<p:commandButton id="deleteButton" icon="ui-icon-trash" action="#{currentProjectOverviewBean.setProjectName(project)}" onclick="deleteProjectDialog.show()"/>
<p:spacer height="0" width="10"/>
<p:commandButton id="controlAnalysis" ajax="false" action="#{currentAnalysisControllerProjectBean.setProject(project)}" icon="ui-icon-wrench"/>
<p:commandButton id="editAnalysisViews" icon="ui-icon-pencil"/>
......
......@@ -87,11 +87,11 @@
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{property.value}" rendered="#{not stringBean.checkString(property)}"/>
<h:outputText value="#{selectedPluginBean.plugin.name}" rendered="#{stringBean.checkString(property)}"/>
<h:outputText value="#{currentWorkSpaceProjectBean.selectedPlugin.name}" rendered="#{stringBean.checkString(property)}"/>
</f:facet>
<f:facet name="input">
<h:inputText value="#{property.value}" rendered="#{not stringBean.checkString(property)}"/>
<h:inputText value="#{selectedPluginBean.plugin.name}" rendered="#{stringBean.checkString(property)}"/>
<h:inputText value="#{currentWorkSpaceProjectBean.selectedPlugin.name}" rendered="#{stringBean.checkString(property)}"/>
</f:facet>
</p:cellEditor>
</p:column>
......
......@@ -27,4 +27,58 @@
</h:form>
</p:dialog>
<!-- ******************************************************************************** -->
<p:dialog id="renameProjectDialog" header="Rename Project" resizable="false" modal="true" widgetVar="renameProjectDialog">
<!-- Make sure that closing of the dialog also clears the input field. -->
<p:ajax event="close" update="renameProjectDialogForm:renameProjectInputText" />
<h:form id="renameProjectDialogForm">
<div style="text-align: center">
<h:outputText value="New Name: " />
<p:inputText id="renameProjectInputText" value="#{stringBean.string}" />
</div>
<hr/>
<div style="text-align: right">
<p:commandButton value="Ok" action="#{projectsBean.renameProject(currentProjectOverviewBean.projectName, stringBean.string)}" update=":projectsListForm :messages" oncomplete="renameProjectDialog.hide()" />
<p:spacer width="10px" height="10" />
<p:commandButton value="Cancel" onclick="renameProjectDialog.hide()" />
</div>
</h:form>
</p:dialog>
<p:dialog id="deleteProjectDialog" header="Delete Project" resizable="false" modal="true" widgetVar="deleteProjectDialog">
<h:form id="deleteProjectDialogForm">
<div style="text-align: center">
<h:outputText value="Do you really want to delete the selected project?" />
</div>
<hr/>
<div style="text-align: right">
<p:commandButton value="Ok" action="#{projectsBean.deleteProject(currentProjectOverviewBean.projectName)}" update=":projectsListForm :messages" oncomplete="deleteProjectDialog.hide()" />
<p:spacer width="10px" height="10" />
<p:commandButton value="Cancel" onclick="deleteProjectDialog.hide()" />
</div>
</h:form>
</p:dialog>
<p:dialog id="copyProjectDialog" header="Copy Project" resizable="false" modal="true" widgetVar="copyProjectDialog">
<!-- Make sure that closing of the dialog also clears the input field. -->
<p:ajax event="close" update="copyProjectDialogForm:copyProjectDialogInputText" />
<h:form id="copyProjectDialogForm">
<div style="text-align: center">
<h:outputText value="Name: " />
<p:inputText id="copyProjectDialogInputText" value="#{stringBean.string}" />
</div>
<hr/>
<div style="text-align: right">
<p:commandButton value="Ok" action="#{projectsBean.copyProject(currentProjectOverviewBean.projectName, stringBean.string)}" update=":projectsListForm :messages" oncomplete="copyProjectDialog.hide()" />
<p:spacer width="10px" height="10" />
<p:commandButton value="Cancel" onclick="copyProjectDialog.hide()" />
</div>
</h:form>
</p:dialog>
</ui:composition>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment