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
No related branches found
No related tags found
No related merge requests found
Showing with 253 additions and 12 deletions
...@@ -111,6 +111,16 @@ public final class ProjectsBean { ...@@ -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 * 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. * invalid, the date of 0 is returned.
......
...@@ -20,9 +20,18 @@ ...@@ -20,9 +20,18 @@
package kieker.webgui.beans.session; package kieker.webgui.beans.session;
import java.util.List;
import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped; 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. * This bean contains the project of the current (session) user for the analysis cockpit.
* *
...@@ -45,12 +54,30 @@ public class CurrentAnalysisCockpitProjectBean { ...@@ -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 * This is the name of the stored project. It can be used as an identifier within the FS-Manager
*/ */
private String projectName; private String projectName;
private DashboardModel model;
/** /**
* Creates a new instance of this class. * Creates a new instance of this class.
*/ */
public CurrentAnalysisCockpitProjectBean() { public CurrentAnalysisCockpitProjectBean() {
// No code necessary // 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 { ...@@ -85,4 +112,8 @@ public class CurrentAnalysisCockpitProjectBean {
return CurrentAnalysisCockpitProjectBean.PAGE_PROJECT_OVERVIEW; 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 { ...@@ -198,9 +198,13 @@ public class ACManager {
* *
* @param project * @param project
* The project whose state should be delivered. * 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) { 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 Pair<AnalysisController, Thread> controller = this.analysisController.get(project);
final STATE controllerState; final STATE controllerState;
......
...@@ -57,6 +57,9 @@ import org.primefaces.model.UploadedFile; ...@@ -57,6 +57,9 @@ import org.primefaces.model.UploadedFile;
* This class uses also a fine grained synchronization to handle the access to the projects. * This class uses also a fine grained synchronization to handle the access to the projects.
* *
* @author Nils Christian Ehmke * @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 { public final class FSManager {
...@@ -202,7 +205,7 @@ public final class FSManager { ...@@ -202,7 +205,7 @@ public final class FSManager {
// Load it atomically // Load it atomically
synchronized (lock) { synchronized (lock) {
return AnalysisController.loadFromFile(kaxFile); return AnalysisController.loadFromFile(kaxFile.getAbsoluteFile());// /kaxFile);
} }
} }
...@@ -242,6 +245,87 @@ public final class FSManager { ...@@ -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. * Returns a list containing all available projects on the FS as a string.
* *
......
...@@ -41,12 +41,22 @@ ...@@ -41,12 +41,22 @@
<p:layoutUnit position="center" id="centerLayout"> <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>
<p:layoutUnit position="west" size="300" header="Views" resizable="true" collapsible="true"> <p:layoutUnit position="west" size="300" header="Views" resizable="true" collapsible="true">
<h:form id="viewsForm"> <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> </p:accordionPanel>
</h:form> </h:form>
</p:layoutUnit> </p:layoutUnit>
......
...@@ -46,23 +46,23 @@ ...@@ -46,23 +46,23 @@
<h:outputText value="#{project}" /> <h:outputText value="#{project}" />
</p:column> </p:column>
<p:column headerText="Owner"> <p:column headerText="Owner" style="text-align: center">
<h:outputText value="N/A" /> <h:outputText value="N/A" />
</p:column> </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)}" /> <h:outputText value="#{projectsBean.getCurrTimeStamp(project)}" />
</p:column> </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)}"/> <h:outputText value="#{projectsBean.getAnalysisControllerState(project)}"/>
</p:column> </p:column>
<p:column headerText="Options" style="text-align: center; width: 280px"> <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="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="copyButton" icon="ui-icon-copy" action="#{currentProjectOverviewBean.setProjectName(project)}" onclick="copyProjectDialog.show()"/>
<p:commandButton id="renameButton" icon="ui-icon-pencil"/> <p:commandButton id="renameButton" icon="ui-icon-pencil" action="#{currentProjectOverviewBean.setProjectName(project)}" onclick="renameProjectDialog.show()"/>
<p:commandButton id="deleteButton" icon="ui-icon-trash"/> <p:commandButton id="deleteButton" icon="ui-icon-trash" action="#{currentProjectOverviewBean.setProjectName(project)}" onclick="deleteProjectDialog.show()"/>
<p:spacer height="0" width="10"/> <p:spacer height="0" width="10"/>
<p:commandButton id="controlAnalysis" ajax="false" action="#{currentAnalysisControllerProjectBean.setProject(project)}" icon="ui-icon-wrench"/> <p:commandButton id="controlAnalysis" ajax="false" action="#{currentAnalysisControllerProjectBean.setProject(project)}" icon="ui-icon-wrench"/>
<p:commandButton id="editAnalysisViews" icon="ui-icon-pencil"/> <p:commandButton id="editAnalysisViews" icon="ui-icon-pencil"/>
......
...@@ -87,11 +87,11 @@ ...@@ -87,11 +87,11 @@
<p:cellEditor> <p:cellEditor>
<f:facet name="output"> <f:facet name="output">
<h:outputText value="#{property.value}" rendered="#{not stringBean.checkString(property)}"/> <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>
<f:facet name="input"> <f:facet name="input">
<h:inputText value="#{property.value}" rendered="#{not stringBean.checkString(property)}"/> <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> </f:facet>
</p:cellEditor> </p:cellEditor>
</p:column> </p:column>
......
...@@ -27,4 +27,58 @@ ...@@ -27,4 +27,58 @@
</h:form> </h:form>
</p:dialog> </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> </ui:composition>
\ No newline at end of file
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