From f7243b4c1fe2a788c17244d21cf4e41c8678ab82 Mon Sep 17 00:00:00 2001 From: Nils Christian Ehmke <nie@informatik.uni-kiel.de> Date: Fri, 18 May 2012 19:34:04 +0200 Subject: [PATCH] Started with an improved version of the GUI, including a multi user mode; Updated also the Kieker-jar. --- Kieker.WebGUI/.classpath | 1 - Kieker.WebGUI/.project | 2 +- .../.settings/edu.umd.cs.findbugs.core.prefs | 131 +++++ .../org.eclipse.core.resources.prefs | 1 - .../.settings/org.eclipse.jdt.core.prefs | 18 +- .../.settings/org.eclipse.jdt.ui.prefs | 23 +- .../.settings/org.eclipse.m2e.core.prefs | 1 - Kieker.WebGUI/README | 7 - Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar | Bin 2029684 -> 2029058 bytes Kieker.WebGUI/nb-configuration.xml | 4 +- Kieker.WebGUI/nbactions.xml | 1 - Kieker.WebGUI/pom.xml | 22 +- .../beans/application/DependenciesBean.java | 122 ---- .../beans/application/ProjectsBean.java | 293 +++------- .../beans/application/ThemeSwitcherBean.java | 12 +- .../beans/application/package-info.java | 25 - .../request/SelectedDependenciesBean.java | 125 ----- .../webgui/beans/request/StringBean.java | 15 +- .../webgui/beans/request/package-info.java | 25 - .../beans/session/AnalysisControllerBean.java | 158 ------ .../CurrentAnalysisCockpitProjectBean.java | 88 +++ .../CurrentAnalysisControllerProjectBean.java | 88 +++ ...rrentAnalysisViewWorkSpaceProjectBean.java | 88 +++ .../beans/session/CurrentThemeBean.java | 22 +- .../session/CurrentWorkSpaceProjectBean.java | 352 ++++++++++++ .../webgui/beans/session/DashboardBean.java | 161 ------ .../beans/session/DependencyUploadBean.java | 87 --- .../session/SelectedMainProjectBean.java | 531 ------------------ .../beans/session/SelectedPluginBean.java | 140 ----- .../beans/session/SelectedProjectBean.java | 147 ----- .../{package-info.java => UserBean.java} | 38 +- .../java/kieker/webgui/common/Connection.java | 168 ------ .../java/kieker/webgui/common/FSManager.java | 437 ++++++++++++++ .../kieker/webgui/common/FileManager.java | 376 ------------- .../java/kieker/webgui/common/LRUCache.java | 110 ---- .../main/java/kieker/webgui/common/Pair.java | 103 ++++ .../webgui/common/PluginClassLoader.java | 143 ----- .../kieker/webgui/common/PluginFinder.java | 99 ++-- .../LibraryAlreadyExistingException.java} | 28 +- .../ProjectAlreadyExistingException.java} | 26 +- .../kieker/webgui/common/package-info.java | 25 - .../converter/ClassToStringConverter.java | 67 --- .../MIDependencyToCountPluginsConverter.java | 122 ---- .../MIDependencyToSizeConverter.java | 96 ---- .../MIDependencyToStringConverter.java | 99 ---- .../converter/MIPluginToStringConverter.java | 67 --- .../converter/MIPortToStringConverter.java | 65 --- .../converter/MIProjectToStringConverter.java | 90 --- .../src/main/webapp/AnalysisCockpit.xhtml | 64 +++ .../src/main/webapp/AnalysisController.xhtml | 79 +++ .../main/webapp/AnalysisViewWorkSpace.xhtml | 18 + .../src/main/webapp/META-INF/context.xml | 2 - .../src/main/webapp/ProjectOverview.xhtml | 96 ++++ .../src/main/webapp/ProjectWorkSpace.xhtml | 100 ++++ .../src/main/webapp/WEB-INF/beans.xml | 5 - .../src/main/webapp/WEB-INF/pretty-config.xml | 38 +- Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml | 50 +- .../src/main/webapp/css/AnalysisCockpit.css | 0 .../main/webapp/css/AnalysisController.css | 0 .../main/webapp/css/AnalysisViewWorkSpace.css | 0 .../main/webapp/{main.css => css/Common.css} | 25 +- .../src/main/webapp/css/ProjectOverview.css | 5 + .../src/main/webapp/css/ProjectWorkSpace.css | 0 .../src/main/webapp/{ => css}/js-graph-it.css | 0 .../{main => dialogs}/aboutDialog.xhtml | 3 - .../webapp/dialogs/connectionDialog.xhtml | 15 + .../dialogs/manageLibrariesDialog.xhtml | 46 ++ .../main/webapp/dialogs/projectDialogs.xhtml | 30 + .../{main => dialogs}/settingsDialog.xhtml | 3 - .../src/main/webapp/handleAnalysis.css | 37 -- .../src/main/webapp/handleAnalysis.xhtml | 101 ---- .../src/main/webapp/img/Icon_LED_Gray.png | Bin 0 -> 5565 bytes .../src/main/webapp/img/Icon_LED_Green.png | Bin 0 -> 8922 bytes .../src/main/webapp/img/Icon_LED_Red.png | Bin 0 -> 7146 bytes .../src/main/webapp/img/Icon_LED_Yellow.png | Bin 0 -> 9564 bytes .../src/main/webapp/{main => img}/arrow.gif | Bin .../src/main/webapp/{main => img}/arrow_d.gif | Bin .../src/main/webapp/{main => img}/arrow_l.gif | Bin .../src/main/webapp/{main => img}/arrow_r.gif | Bin .../src/main/webapp/{main => img}/arrow_u.gif | Bin .../src/main/webapp/{ => js}/js-graph-it.js | 0 Kieker.WebGUI/src/main/webapp/main.xhtml | 223 -------- .../main/webapp/main/connectionDialog.xhtml | 96 ---- .../src/main/webapp/main/projectDialogs.xhtml | 66 --- .../src/main/webapp/manageDependencies.css | 30 - .../src/main/webapp/manageDependencies.xhtml | 97 ---- .../src/main/webapp/projectDependencies.css | 26 - .../src/main/webapp/projectDependencies.xhtml | 65 --- .../kieker/webgui/common/LRUCacheTest.java | 70 --- .../webgui/common/PluginFinderTest.java | 59 -- 90 files changed, 2073 insertions(+), 4225 deletions(-) create mode 100644 Kieker.WebGUI/.settings/edu.umd.cs.findbugs.core.prefs delete mode 100644 Kieker.WebGUI/README delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/DependenciesBean.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/package-info.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/SelectedDependenciesBean.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/package-info.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/AnalysisControllerBean.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DashboardBean.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DependencyUploadBean.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedMainProjectBean.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedPluginBean.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedProjectBean.java rename Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/{package-info.java => UserBean.java} (53%) delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/Connection.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/FileManager.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/LRUCache.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/Pair.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginClassLoader.java rename Kieker.WebGUI/src/main/java/kieker/webgui/{beans/request/StringToIDBean.java => common/exception/LibraryAlreadyExistingException.java} (60%) rename Kieker.WebGUI/src/main/java/kieker/webgui/{converter/package-info.java => common/exception/ProjectAlreadyExistingException.java} (63%) delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/package-info.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/ClassToStringConverter.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToCountPluginsConverter.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToSizeConverter.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToStringConverter.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginToStringConverter.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortToStringConverter.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIProjectToStringConverter.java create mode 100644 Kieker.WebGUI/src/main/webapp/AnalysisCockpit.xhtml create mode 100644 Kieker.WebGUI/src/main/webapp/AnalysisController.xhtml create mode 100644 Kieker.WebGUI/src/main/webapp/AnalysisViewWorkSpace.xhtml delete mode 100644 Kieker.WebGUI/src/main/webapp/META-INF/context.xml create mode 100644 Kieker.WebGUI/src/main/webapp/ProjectOverview.xhtml create mode 100644 Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml delete mode 100644 Kieker.WebGUI/src/main/webapp/WEB-INF/beans.xml create mode 100644 Kieker.WebGUI/src/main/webapp/css/AnalysisCockpit.css create mode 100644 Kieker.WebGUI/src/main/webapp/css/AnalysisController.css create mode 100644 Kieker.WebGUI/src/main/webapp/css/AnalysisViewWorkSpace.css rename Kieker.WebGUI/src/main/webapp/{main.css => css/Common.css} (80%) create mode 100644 Kieker.WebGUI/src/main/webapp/css/ProjectOverview.css create mode 100644 Kieker.WebGUI/src/main/webapp/css/ProjectWorkSpace.css rename Kieker.WebGUI/src/main/webapp/{ => css}/js-graph-it.css (100%) rename Kieker.WebGUI/src/main/webapp/{main => dialogs}/aboutDialog.xhtml (82%) create mode 100644 Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml create mode 100644 Kieker.WebGUI/src/main/webapp/dialogs/manageLibrariesDialog.xhtml create mode 100644 Kieker.WebGUI/src/main/webapp/dialogs/projectDialogs.xhtml rename Kieker.WebGUI/src/main/webapp/{main => dialogs}/settingsDialog.xhtml (80%) delete mode 100644 Kieker.WebGUI/src/main/webapp/handleAnalysis.css delete mode 100644 Kieker.WebGUI/src/main/webapp/handleAnalysis.xhtml create mode 100644 Kieker.WebGUI/src/main/webapp/img/Icon_LED_Gray.png create mode 100644 Kieker.WebGUI/src/main/webapp/img/Icon_LED_Green.png create mode 100644 Kieker.WebGUI/src/main/webapp/img/Icon_LED_Red.png create mode 100644 Kieker.WebGUI/src/main/webapp/img/Icon_LED_Yellow.png rename Kieker.WebGUI/src/main/webapp/{main => img}/arrow.gif (100%) rename Kieker.WebGUI/src/main/webapp/{main => img}/arrow_d.gif (100%) rename Kieker.WebGUI/src/main/webapp/{main => img}/arrow_l.gif (100%) rename Kieker.WebGUI/src/main/webapp/{main => img}/arrow_r.gif (100%) rename Kieker.WebGUI/src/main/webapp/{main => img}/arrow_u.gif (100%) rename Kieker.WebGUI/src/main/webapp/{ => js}/js-graph-it.js (100%) delete mode 100644 Kieker.WebGUI/src/main/webapp/main.xhtml delete mode 100644 Kieker.WebGUI/src/main/webapp/main/connectionDialog.xhtml delete mode 100644 Kieker.WebGUI/src/main/webapp/main/projectDialogs.xhtml delete mode 100644 Kieker.WebGUI/src/main/webapp/manageDependencies.css delete mode 100644 Kieker.WebGUI/src/main/webapp/manageDependencies.xhtml delete mode 100644 Kieker.WebGUI/src/main/webapp/projectDependencies.css delete mode 100644 Kieker.WebGUI/src/main/webapp/projectDependencies.xhtml delete mode 100644 Kieker.WebGUI/src/test/java/kieker/webgui/common/LRUCacheTest.java delete mode 100644 Kieker.WebGUI/src/test/java/kieker/webgui/common/PluginFinderTest.java diff --git a/Kieker.WebGUI/.classpath b/Kieker.WebGUI/.classpath index e61646ee..595a5bf4 100644 --- a/Kieker.WebGUI/.classpath +++ b/Kieker.WebGUI/.classpath @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" output="target/classes" path="src/main/java"/> - <classpathentry kind="src" path="src/test/java"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/> <classpathentry kind="output" path="target/classes"/> diff --git a/Kieker.WebGUI/.project b/Kieker.WebGUI/.project index b6096236..5fe3174c 100644 --- a/Kieker.WebGUI/.project +++ b/Kieker.WebGUI/.project @@ -17,7 +17,7 @@ </buildCommand> </buildSpec> <natures> - <nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> </natures> </projectDescription> diff --git a/Kieker.WebGUI/.settings/edu.umd.cs.findbugs.core.prefs b/Kieker.WebGUI/.settings/edu.umd.cs.findbugs.core.prefs new file mode 100644 index 00000000..0073ac05 --- /dev/null +++ b/Kieker.WebGUI/.settings/edu.umd.cs.findbugs.core.prefs @@ -0,0 +1,131 @@ +#FindBugs User Preferences +#Fri May 18 17:56:48 CEST 2012 +cloud_id=edu.umd.cs.findbugs.cloud.doNothingCloud +detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true +detectorAtomicityProblem=AtomicityProblem|true +detectorBadAppletConstructor=BadAppletConstructor|false +detectorBadResultSetAccess=BadResultSetAccess|true +detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true +detectorBadUseOfReturnValue=BadUseOfReturnValue|true +detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true +detectorBooleanReturnNull=BooleanReturnNull|true +detectorCallToUnsupportedMethod=CallToUnsupportedMethod|false +detectorCheckExpectedWarnings=CheckExpectedWarnings|false +detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true +detectorCheckTypeQualifiers=CheckTypeQualifiers|true +detectorCloneIdiom=CloneIdiom|true +detectorComparatorIdiom=ComparatorIdiom|true +detectorConfusedInheritance=ConfusedInheritance|true +detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true +detectorCrossSiteScripting=CrossSiteScripting|true +detectorDefaultEncodingDetector=DefaultEncodingDetector|true +detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true +detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true +detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true +detectorDontUseEnum=DontUseEnum|true +detectorDroppedException=DroppedException|true +detectorDumbMethodInvocations=DumbMethodInvocations|true +detectorDumbMethods=DumbMethods|true +detectorDuplicateBranches=DuplicateBranches|true +detectorEmptyZipFileEntry=EmptyZipFileEntry|true +detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true +detectorExplicitSerialization=ExplicitSerialization|true +detectorFinalizerNullsFields=FinalizerNullsFields|true +detectorFindBadCast2=FindBadCast2|true +detectorFindBadForLoop=FindBadForLoop|true +detectorFindCircularDependencies=FindCircularDependencies|false +detectorFindDeadLocalStores=FindDeadLocalStores|true +detectorFindDoubleCheck=FindDoubleCheck|true +detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true +detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true +detectorFindFinalizeInvocations=FindFinalizeInvocations|true +detectorFindFloatEquality=FindFloatEquality|true +detectorFindHEmismatch=FindHEmismatch|true +detectorFindInconsistentSync2=FindInconsistentSync2|true +detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true +detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true +detectorFindMaskedFields=FindMaskedFields|true +detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true +detectorFindNakedNotify=FindNakedNotify|true +detectorFindNonShortCircuit=FindNonShortCircuit|true +detectorFindNullDeref=FindNullDeref|true +detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true +detectorFindOpenStream=FindOpenStream|true +detectorFindPuzzlers=FindPuzzlers|true +detectorFindRefComparison=FindRefComparison|true +detectorFindReturnRef=FindReturnRef|true +detectorFindRunInvocations=FindRunInvocations|true +detectorFindSelfComparison=FindSelfComparison|true +detectorFindSelfComparison2=FindSelfComparison2|true +detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true +detectorFindSpinLoop=FindSpinLoop|true +detectorFindSqlInjection=FindSqlInjection|true +detectorFindTwoLockWait=FindTwoLockWait|true +detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true +detectorFindUnconditionalWait=FindUnconditionalWait|true +detectorFindUninitializedGet=FindUninitializedGet|true +detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true +detectorFindUnreleasedLock=FindUnreleasedLock|true +detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true +detectorFindUnsyncGet=FindUnsyncGet|true +detectorFindUseOfNonSerializableValue=FindUseOfNonSerializableValue|true +detectorFindUselessControlFlow=FindUselessControlFlow|true +detectorFormatStringChecker=FormatStringChecker|true +detectorHugeSharedStringConstants=HugeSharedStringConstants|true +detectorIDivResultCastToDouble=IDivResultCastToDouble|true +detectorIncompatMask=IncompatMask|true +detectorInconsistentAnnotations=InconsistentAnnotations|true +detectorInefficientMemberAccess=InefficientMemberAccess|false +detectorInefficientToArray=InefficientToArray|true +detectorInfiniteLoop=InfiniteLoop|true +detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true +detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true +detectorInitializationChain=InitializationChain|true +detectorInstantiateStaticClass=InstantiateStaticClass|true +detectorIntCast2LongAsInstant=IntCast2LongAsInstant|true +detectorInvalidJUnitTest=InvalidJUnitTest|true +detectorIteratorIdioms=IteratorIdioms|true +detectorLazyInit=LazyInit|true +detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true +detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true +detectorMethodReturnCheck=MethodReturnCheck|true +detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true +detectorMutableLock=MutableLock|true +detectorMutableStaticFields=MutableStaticFields|true +detectorNaming=Naming|true +detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true +detectorNumberConstructor=NumberConstructor|true +detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true +detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true +detectorPublicSemaphores=PublicSemaphores|false +detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true +detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true +detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true +detectorRedundantInterfaces=RedundantInterfaces|true +detectorRepeatedConditionals=RepeatedConditionals|true +detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true +detectorSerializableIdiom=SerializableIdiom|true +detectorStartInConstructor=StartInConstructor|true +detectorStaticCalendarDetector=StaticCalendarDetector|true +detectorStringConcatenation=StringConcatenation|true +detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true +detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true +detectorSwitchFallthrough=SwitchFallthrough|true +detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true +detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true +detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true +detectorURLProblems=URLProblems|true +detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true +detectorUnnecessaryMath=UnnecessaryMath|true +detectorUnreadFields=UnreadFields|true +detectorUselessSubclassMethod=UselessSubclassMethod|false +detectorVarArgsProblems=VarArgsProblems|true +detectorVolatileUsage=VolatileUsage|true +detectorWaitInLoop=WaitInLoop|true +detectorWrongMapIterator=WrongMapIterator|true +detectorXMLFactoryBypass=XMLFactoryBypass|true +detector_threshold=2 +effort=default +filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,MT_CORRECTNESS,PERFORMANCE,STYLE|false|15 +filter_settings_neg=MALICIOUS_CODE,NOISE,I18N,SECURITY,EXPERIMENTAL| +run_at_full_build=false diff --git a/Kieker.WebGUI/.settings/org.eclipse.core.resources.prefs b/Kieker.WebGUI/.settings/org.eclipse.core.resources.prefs index f8e2785f..e9441bb1 100644 --- a/Kieker.WebGUI/.settings/org.eclipse.core.resources.prefs +++ b/Kieker.WebGUI/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,3 @@ -#Fri Feb 03 16:06:50 CET 2012 eclipse.preferences.version=1 encoding//src/main/java=UTF-8 encoding/<project>=UTF-8 diff --git a/Kieker.WebGUI/.settings/org.eclipse.jdt.core.prefs b/Kieker.WebGUI/.settings/org.eclipse.jdt.core.prefs index 0cc6f704..12177523 100644 --- a/Kieker.WebGUI/.settings/org.eclipse.jdt.core.prefs +++ b/Kieker.WebGUI/.settings/org.eclipse.jdt.core.prefs @@ -1,14 +1,16 @@ -#Fri Feb 03 21:01:28 CET 2012 eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes= +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=1.6 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false diff --git a/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs b/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs index 36d8a56b..a7532b33 100644 --- a/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs +++ b/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs @@ -1,4 +1,3 @@ -#Fri Feb 03 21:03:00 CET 2012 cleanup.add_default_serial_version_id=true cleanup.add_generated_serial_version_id=false cleanup.add_missing_annotations=true @@ -56,6 +55,10 @@ eclipse.preferences.version=1 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true formatter_profile=_Kieker - Profile formatter_settings_version=12 +org.eclipse.jdt.ui.exception.name=e +org.eclipse.jdt.ui.gettersetter.use.is=true +org.eclipse.jdt.ui.keywordthis=false +org.eclipse.jdt.ui.overrideannotation=true sp_cleanup.add_default_serial_version_id=true sp_cleanup.add_generated_serial_version_id=false sp_cleanup.add_missing_annotations=true @@ -66,10 +69,10 @@ sp_cleanup.add_missing_override_annotations=true sp_cleanup.add_missing_override_annotations_interface_methods=true sp_cleanup.add_serial_version_id=false sp_cleanup.always_use_blocks=true -sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_parentheses_in_expressions=true sp_cleanup.always_use_this_for_non_static_field_access=true sp_cleanup.always_use_this_for_non_static_method_access=true -sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.convert_to_enhanced_for_loop=true sp_cleanup.correct_indentation=true sp_cleanup.format_source_code=true sp_cleanup.format_source_code_changes_only=false @@ -79,7 +82,7 @@ sp_cleanup.make_private_fields_final=true sp_cleanup.make_type_abstract_if_missing_method=false sp_cleanup.make_variable_declarations_final=true sp_cleanup.never_use_blocks=false -sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.never_use_parentheses_in_expressions=false sp_cleanup.on_save_use_additional_actions=true sp_cleanup.organize_imports=true sp_cleanup.qualify_static_field_accesses_with_declaring_class=true @@ -88,22 +91,22 @@ sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class= sp_cleanup.qualify_static_member_accesses_with_declaring_class=true sp_cleanup.qualify_static_method_accesses_with_declaring_class=true sp_cleanup.remove_private_constructors=true -sp_cleanup.remove_trailing_whitespaces=false +sp_cleanup.remove_trailing_whitespaces=true sp_cleanup.remove_trailing_whitespaces_all=true sp_cleanup.remove_trailing_whitespaces_ignore_empty=false sp_cleanup.remove_unnecessary_casts=true sp_cleanup.remove_unnecessary_nls_tags=false sp_cleanup.remove_unused_imports=true -sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_local_variables=true sp_cleanup.remove_unused_private_fields=true -sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_members=true sp_cleanup.remove_unused_private_methods=true sp_cleanup.remove_unused_private_types=true sp_cleanup.sort_members=false -sp_cleanup.sort_members_all=false -sp_cleanup.use_blocks=false +sp_cleanup.sort_members_all=true +sp_cleanup.use_blocks=true sp_cleanup.use_blocks_only_for_return_and_throw=false -sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_parentheses_in_expressions=true sp_cleanup.use_this_for_non_static_field_access=true sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false sp_cleanup.use_this_for_non_static_method_access=true diff --git a/Kieker.WebGUI/.settings/org.eclipse.m2e.core.prefs b/Kieker.WebGUI/.settings/org.eclipse.m2e.core.prefs index c13b7b31..f897a7f1 100644 --- a/Kieker.WebGUI/.settings/org.eclipse.m2e.core.prefs +++ b/Kieker.WebGUI/.settings/org.eclipse.m2e.core.prefs @@ -1,4 +1,3 @@ -#Sat Jan 21 18:45:30 CET 2012 activeProfiles= eclipse.preferences.version=1 resolveWorkspaceProjects=true diff --git a/Kieker.WebGUI/README b/Kieker.WebGUI/README deleted file mode 100644 index 986af16c..00000000 --- a/Kieker.WebGUI/README +++ /dev/null @@ -1,7 +0,0 @@ -The project "Kieker.WebGUI" can be started via Maven (3). Just use the command - -mvn jetty:run - -to pack the war-file, deploy it on jetty and start jetty. The web tool is then available at - -http://localhost:8080/Kieker.WebGUI/main \ No newline at end of file diff --git a/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar b/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar index 1226fc8a09fb8bb0570d5a8abf6d61b9fa8cd500..e1c53890f254d4bbc0f6c83f5811bbba6960533e 100644 GIT binary patch delta 66246 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 delta 67137 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 XU3;tG_^FkP)mk^H*xvglj5GfO5J(d8 diff --git a/Kieker.WebGUI/nb-configuration.xml b/Kieker.WebGUI/nb-configuration.xml index fb9db666..3486bc9d 100644 --- a/Kieker.WebGUI/nb-configuration.xml +++ b/Kieker.WebGUI/nb-configuration.xml @@ -13,8 +13,6 @@ You can copy and paste the single properties, into the pom.xml file and the IDE That way multiple projects can share the same settings (useful for formatting rules for example). Any value defined here will override the pom.xml file value but is only applicable to the current project. --> - <netbeans.checkstyle.format>true</netbeans.checkstyle.format> - <netbeans.hint.jdkPlatform>JDK_1.6</netbeans.hint.jdkPlatform> - <org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language> + <netbeans.compile.on.save>all</netbeans.compile.on.save> </properties> </project-shared-configuration> diff --git a/Kieker.WebGUI/nbactions.xml b/Kieker.WebGUI/nbactions.xml index 14cb2ebf..83c07bc9 100644 --- a/Kieker.WebGUI/nbactions.xml +++ b/Kieker.WebGUI/nbactions.xml @@ -5,7 +5,6 @@ <goals> <goal>jetty:run</goal> - </goals> </action> </actions> diff --git a/Kieker.WebGUI/pom.xml b/Kieker.WebGUI/pom.xml index 88232b47..67a39b48 100644 --- a/Kieker.WebGUI/pom.xml +++ b/Kieker.WebGUI/pom.xml @@ -15,6 +15,15 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <kieker.jar>kieker-1.6-SNAPSHOT_emf.jar</kieker.jar> </properties> + + <repositories> + <repository> + <id>prime-repo</id> + <name>PrimeFaces Maven Repository</name> + <url>http://repository.primefaces.org</url> + <layout>default</layout> + </repository> + </repositories> <dependencies> <dependency> @@ -201,7 +210,7 @@ <dependency> <groupId>kieker</groupId> <artifactId>kieker</artifactId> - <version>1.5-SNAPSHOT</version> + <version>1.6-SNAPSHOT</version> <scope>system</scope> <systemPath>${project.basedir}/lib/${kieker.jar}</systemPath> </dependency> @@ -217,15 +226,6 @@ </dependency> </dependencies> - <repositories> - <repository> - <id>prime-repo</id> - <name>PrimeFaces Maven Repository</name> - <url>http://repository.primefaces.org</url> - <layout>default</layout> - </repository> - </repositories> - <build> <plugins> <plugin> @@ -372,7 +372,5 @@ </plugin> </plugins> </build> - - </project> diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/DependenciesBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/DependenciesBean.java deleted file mode 100644 index 65e9f66d..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/DependenciesBean.java +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************** - * 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.application; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; - -import javax.faces.bean.ApplicationScoped; -import javax.faces.bean.ManagedBean; - -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.common.logging.Log; -import kieker.common.logging.LogFactory; -import kieker.webgui.common.FileManager; -import kieker.webgui.common.PluginClassLoader; - -import org.primefaces.model.UploadedFile; - -/** - * This bean manages all dependencies (libraries) within the application. The bean can be used to add and remove dependencies as well as to get all available - * dependencies. This bean doesn't modify other beans directly. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@ManagedBean -@ApplicationScoped -public class DependenciesBean { - - /** - * The logger within this class. - */ - private static final Log LOG = LogFactory.getLog(DependenciesBean.class); - /** - * The list containing the depenencies. - */ - private final List<MIDependency> dependencies; - - /** - * Creates a new instance of this class. - */ - public DependenciesBean() { - this.dependencies = FileManager.getInstance().loadAllDependencies(); - } - - /** - * Delivers the currently available dependencies as a list. The list must <b>not</b> be modified. - * - * @return All available dependencies. - */ - public List<MIDependency> getDependencies() { - return this.dependencies; - } - - /** - * Tries to upload a given file as a new dependency. If the dependency does already exist, it will be overwritten. If the dependencies has been uploaded - * successfully, the plugin class loader will get the lib as well. - * - * @param file - * The file to be uploaded. - */ - public void uploadDependency(final UploadedFile file) { - synchronized (this) { - final MIDependency dependency = FileManager.getInstance().uploadDependency(file); - if (dependency != null) { - // Is is possible that we already have a dependency with the same name and have to remove it first. - for (final MIDependency dep : this.dependencies) { - if (dep.getFilePath().equals(dependency.getFilePath())) { - this.dependencies.remove(dep); - break; - } - } - try { - PluginClassLoader.getInstance().addURL(new URL("file", "localhost", FileManager.getInstance().getFullPath(dependency))); - this.dependencies.add(dependency); - } catch (final MalformedURLException ex) { - DependenciesBean.LOG.error("Could not add the dependency to the ClassLoader.", ex); - } - } - } - } - - /** - * Tries to delete a given dependency. Once this has been done, the class loader cannot use the dependency any longer. - * - * @param dependency - * The dependency to be removed. - */ - public void deleteDependency(final MIDependency dependency) { - synchronized (this) { - final boolean result = FileManager.getInstance().deleteDependency(dependency); - if (result) { - this.dependencies.remove(dependency); - try { - PluginClassLoader.getInstance().removeURL(new URL("file", "localhost", dependency.getFilePath())); - this.dependencies.remove(dependency); - } catch (final MalformedURLException ex) { - DependenciesBean.LOG.error("Could not remove the dependency from the ClassLoader.", ex); - } - } - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java index 5968a7f3..c8808141 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java @@ -2,7 +2,7 @@ * Copyright 2012 by * + Christian-Albrechts-University of Kiel * + Department of Computer Science - * + Software Engineering Group + * + Software Engineering Group * and others. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,279 +17,160 @@ * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ + package kieker.webgui.beans.application; -import java.lang.reflect.Method; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; import java.util.List; -import java.util.Observable; +import java.util.concurrent.ConcurrentHashMap; +import javax.annotation.PostConstruct; import javax.faces.application.FacesMessage; +import javax.faces.application.FacesMessage.Severity; import javax.faces.bean.ApplicationScoped; import javax.faces.bean.ManagedBean; import javax.faces.context.FacesContext; -import kieker.analysis.display.HtmlText; -import kieker.analysis.display.Image; -import kieker.analysis.display.PlainText; -import kieker.analysis.display.annotation.Display; -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.analysis.model.analysisMetaModel.MIPlugin; +import kieker.analysis.AnalysisController; import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.analysis.model.analysisMetaModel.impl.MAnalysisMetaModelFactory; -import kieker.analysis.plugin.AbstractPlugin; -import kieker.analysis.plugin.annotation.Plugin; -import kieker.analysis.repository.AbstractRepository; -import kieker.webgui.common.FileManager; - -import org.primefaces.context.RequestContext; -import org.primefaces.model.DefaultTreeNode; -import org.primefaces.model.TreeNode; +import kieker.webgui.common.FSManager; +import kieker.webgui.common.exception.ProjectAlreadyExistingException; /** - * This bean can be used to handle all available projects within the program. It is like a blackboard for all other components when it comes to the actual projects - * <b>stored</b> on the file system. The properties of the projects, like the adding of dependencies the an actual existing project, can be done otherwise, but the - * storage is done via this bean. Other beans (like for the currently selected main project) are not modified directly by this bean. If the user removes the main - * project, the bean for the main project has to handle this. + * This bean contains all project and - for example - their corresponding instances of {@link AnalysisController}. It should be used to create new projects and + * similar things. The synchronization for the projects is done in the {@link FSManager} though. * * @author Nils Christian Ehmke * @version 1.0 */ @ManagedBean @ApplicationScoped -public class ProjectsBean extends Observable { +public final class ProjectsBean { /** - * A list containing all available projects. + * This is the list containing all projects. */ - private final List<MIProject> projects; + private final List<String> projects = Collections.synchronizedList(new ArrayList<String>()); /** - * The factory used to create new projects. + * This list contains the current analysis controllers. Not every project does have a controller, but every project can have maximal one. */ - private final MAnalysisMetaModelFactory factory; + private final ConcurrentHashMap<String, AnalysisController> analysisController = new ConcurrentHashMap<String, AnalysisController>(); /** * Creates a new instance of this class. */ public ProjectsBean() { - // Load all projects from the file system. - this.projects = FileManager.getInstance().loadAllProjects(); - this.factory = new MAnalysisMetaModelFactory(); + // No code necessary + } + + @SuppressWarnings("unused") + @PostConstruct + private void init() { + // Load a list with all available projects on the FS + this.projects.addAll(FSManager.getInstance().getAllProjects()); } /** - * Uses the given name to create a new project. If a project with the - * same name does already exist, nothing happens, but a message will inform the user. + * Adds a new project to this application if possible. It informs the current user (via the growl-component of PrimeFaces) whether the creation was successful or + * not. * - * @param projectName - * The name of the new project. + * @param project + * The name of the project to be added. */ - public final void addProject(final String projectName) { - // Create a new project. - final MIProject project = this.factory.createProject(); - project.setName(projectName); - - // The check for an existing project and the potential storage within our list has to be done atomically. - synchronized (this) { - // Try to save the project. If this fails, the project exists already. - if (FileManager.getInstance().saveNewProject(project)) { - FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "", "New Project: " + projectName)); - this.projects.add(project); - RequestContext.getCurrentInstance().addPartialUpdateTarget("projectsForm"); - } else { - // Inform the user about the fail. - FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "", "A project with this name exists already.")); - } + public void addProject(final String project) { + try { + // Try and use the FS-Manager to create the project atomically. + FSManager.getInstance().addProject(project); + // If there were no exception, everything went well. We can add the project to our list. + this.projects.add(project); + // Inform the user + ProjectsBean.showMessage(FacesMessage.SEVERITY_INFO, "Project created."); + } catch (final IOException ex) { + ProjectsBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while creating the project."); + } catch (final ProjectAlreadyExistingException ex) { + ProjectsBean.showMessage(FacesMessage.SEVERITY_WARN, "A project with the same name exists already."); } } /** - * Delivers the currently available projects as a tree root. + * This method can be used to open an existing project. This means that the current state of the project on the file system is loaded into an instance of {@link} + * MIProject}. This instance can be modified at will and for example later saved by the {@link FSManager}. * - * @return The root of the currently available projects. + * @param project + * The name of the project to be saved. + * @return Either the model instance if the loading was successful, null otherwise. In the latter case, the user will be informed via the growl-component. */ - public final TreeNode getProjectsRoot() { - synchronized (this) { - final TreeNode root = new DefaultTreeNode("Root", null); - - for (final MIProject project : this.projects) { - final TreeNode projectNode = new DefaultTreeNode("project", project, root); - final TreeNode dependenciesNode = new DefaultTreeNode("dependencies", "Dependencies", projectNode); - final TreeNode usedPluginsNode = new DefaultTreeNode("usedPlugins", "Used Plugins", projectNode); - - // Append the used plugins and dependencies. - for (final MIPlugin plugin : project.getPlugins()) { - new DefaultTreeNode("usedPlugin", plugin.getName(), usedPluginsNode); - } - - for (final MIDependency dependency : project.getDependencies()) { - new DefaultTreeNode("dependencies", dependency.getFilePath(), dependenciesNode); - } - } - - return root; + public MIProject openProject(final String project) { + try { + return FSManager.getInstance().openProject(project); + } catch (final IOException ex) { + ProjectsBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the project."); + return null; } } /** - * This method saved a given project on the file system. The project - * should already exist. + * 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. * * @param project - * The project to be saved. + * The project whose time stamp should be collected. + * @return The hum readable time stamp of the project. */ - public void saveProject(final MIProject project) { - synchronized (this) { - FileManager.getInstance().saveProject(project); - } + public String getCurrTimeStamp(final String project) { + // Get the current time stamp of the project... + final long timeStamp = FSManager.getInstance().getCurrTimeStamp(project); + // ...and make sure the user can read it. + final String dStr = new Date(timeStamp).toString(); + return dStr; + } /** - * Deletes a given project from the file system. + * This method delivers all available projects as a list of string. * - * @param project - * The project to be removed. + * @return All currently available projects. */ - public void deleteProject(final MIProject project) { - synchronized (this) { - final boolean result = FileManager.getInstance().deleteProject(project); - if (result) { - this.projects.remove(project); - // Notify the observers - this.setChanged(); - this.notifyObservers(new MsgProjectRemoved(project)); - } - } + public List<String> getProjects() { + return this.projects; } /** - * Reloads a given project from the file system. In other words: The - * state of the project is restored from the file system. + * This method delivers the corresponding analysis controller of the given project. * * @param project - * The project to be reloaded. + * The project whose analysis controller should be delivered. + * @return The corresponding instance of {@link AnalysisController} if it exists, null otherwise. */ - public void resetProject(final MIProject project) { - synchronized (this) { - final MIProject result = FileManager.getInstance().reloadProject(project); - if (result != null) { - this.projects.remove(project); - this.projects.add(result); - } - } + public AnalysisController getAnalysisController(final String project) { + return this.analysisController.get(project); } /** - * This method can be used to get the description of an {@link AbstractPlugin}- or an {@link AbstractRepository}-class. The description is read via the - * annotation. + * This method can be used to deliver the state of the analysis controller of the given project as a human readable string. * - * @param clazz - * The class whose description should be extracted. - * @return The description for the class or a substitute if none is available. + * @param project + * The project whose state should be delivered. + * @return The current state of the corresponding {@link AnalysisController} if it exists, 'N/A' otherwise. */ - public String getDescription(final Class<?> clazz) { - final Plugin annotation = clazz.getAnnotation(Plugin.class); - if (annotation == null || annotation.description().isEmpty()) { - return "No description available"; - } else { - return annotation.description(); - } - } - - public List<Widget> getWidgets(final Class<?> clazz) { - // TODO Cache - final List<Widget> widgets = new ArrayList<ProjectsBean.Widget>(); - if (clazz != null) { - // Run through all methods and check them - final Method[] methods = clazz.getMethods(); - for (final Method method : methods) { - // If the method does have the right annotation, we use it. - final Display displayAnnot = method.getAnnotation(Display.class); - if (displayAnnot != null) { - // Get the correct type of the method - final Class<?> returnType = method.getReturnType(); - final Widget.WidgetType type; - // TODO This should be done better. - if (returnType.isAssignableFrom(PlainText.class) && PlainText.class.isAssignableFrom(returnType)) { - type = Widget.WidgetType.PlainText; - } else { - if (returnType.isAssignableFrom(HtmlText.class) && HtmlText.class.isAssignableFrom(returnType)) { - type = Widget.WidgetType.HtmlText; - } else { - if (returnType.isAssignableFrom(Image.class) && Image.class.isAssignableFrom(returnType)) { - type = Widget.WidgetType.Image; - } else { - // Unknown type! - continue; - } - } - } - - final Widget widget = new Widget(method, type, displayAnnot.name()); - widgets.add(widget); - } - } - } - return widgets; - } - - public static class Widget { - private final Method widgetMethod; - private final WidgetType type; - private final String name; - - public static enum WidgetType { - PlainText, HtmlText, Image - } - - public Widget(final Method widgetMethod, final WidgetType type, final String name) { - this.widgetMethod = widgetMethod; - this.type = type; - this.name = name; - } - - public Method getWidgetMethod() { - return this.widgetMethod; - } + public String getAnalysisControllerState(final String project) { + final AnalysisController controller = this.analysisController.get(project); - public WidgetType getType() { - return this.type; - } - - public String getName() { - return this.name; - } + return (controller == null) ? "N/A" : controller.getState().toString(); } /** - * This helper class is a wrapper for a project and can be send to the observers as a message that a project just has been removed. It contains - * the removed project. + * This method shows the current user a message by using the growl-component of PrimeFaces. * - * @author Nils Christian Ehmke + * @param severity + * The severity of the message. + * @param msg + * The message itself. */ - public static class MsgProjectRemoved { - /** - * The stored project. - */ - private final MIProject project; - - /** - * Creates a new instance of this class using the given parameters. - * - * @param project - * The project to be stored within this class. - */ - public MsgProjectRemoved(final MIProject project) { - this.project = project; - } - - /** - * Delivers the stored project within this class. - * - * @return The instance of {@link MIProject}. - */ - public MIProject getProject() { - return this.project; - } + private static void showMessage(final Severity severity, final String msg) { + FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, "", msg)); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ThemeSwitcherBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ThemeSwitcherBean.java index 92891b7d..e4144671 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ThemeSwitcherBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ThemeSwitcherBean.java @@ -2,7 +2,7 @@ * Copyright 2012 by * + Christian-Albrechts-University of Kiel * + Department of Computer Science - * + Software Engineering Group + * + Software Engineering Group * and others. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,18 +36,18 @@ import javax.faces.bean.ManagedBean; */ @ManagedBean @ApplicationScoped -public class ThemeSwitcherBean { +public final class ThemeSwitcherBean { /** * A map containing all available themes. */ - private final Map<String, String> themes; + private final Map<String, String> themes = new TreeMap<String, String>(); /** * Creates a new instance of this class. */ public ThemeSwitcherBean() { - this.themes = new TreeMap<String, String>(); + // No code necessary } /** @@ -55,7 +55,7 @@ public class ThemeSwitcherBean { * * @return A map containing the user readable names of the themes as a key and the actual theme-names as the corresponding value. */ - public final Map<String, String> getThemes() { + public Map<String, String> getThemes() { return this.themes; } @@ -63,7 +63,7 @@ public class ThemeSwitcherBean { * Initializes the bean. If one wants to add new themes to the program, this is the right place. */ @PostConstruct - public final void init() { + public void init() { this.themes.put("Aristo", "aristo"); this.themes.put("Black-Tie", "black-tie"); this.themes.put("Blitzer", "blitzer"); diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/package-info.java deleted file mode 100644 index 4f845854..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * 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. - ***************************************************************************/ - -/** - * This package contains all beans with application scope. - */ -package kieker.webgui.beans.application; - diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/SelectedDependenciesBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/SelectedDependenciesBean.java deleted file mode 100644 index 8bb1d32d..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/SelectedDependenciesBean.java +++ /dev/null @@ -1,125 +0,0 @@ -/*************************************************************************** - * 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.request; - -import java.util.ArrayList; -import java.util.List; - -import javax.faces.application.FacesMessage; -import javax.faces.bean.ManagedBean; -import javax.faces.bean.RequestScoped; -import javax.faces.context.FacesContext; - -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.webgui.beans.application.DependenciesBean; -import kieker.webgui.beans.session.SelectedProjectBean; - -/** - * This bean contains the currently chosen dependencies. This has to be request scoped, because the bean fetches the currently selected project when created. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@ManagedBean -@RequestScoped -public class SelectedDependenciesBean { - - /** - * This list contains the currently selected dependencies. - */ - private List<MIDependency> dependencies; - /** - * This field contains the corresponding project, which will be modified by this bean. - */ - private final MIProject project; - - /** - * Creates a new instance of this class. - */ - public SelectedDependenciesBean() { - this.dependencies = new ArrayList<MIDependency>(); - - /* Try to get the currently selected project. */ - final FacesContext context = FacesContext.getCurrentInstance(); - - final SelectedProjectBean selProjBean = context.getApplication().evaluateExpressionGet(context, "#{selectedProjectBean}", - SelectedProjectBean.class); - final DependenciesBean depBean = context.getApplication().evaluateExpressionGet(context, "#{dependenciesBean}", - DependenciesBean.class); - - if (selProjBean != null) { - this.project = selProjBean.getSelectedProject(); - } else { - this.project = null; - } - - /* - * The adding of the already existing dependencies within the project is troublesome. As the names cannot be compared, we have to do this manually and - * use our "own" dependencies which we have to compare with the dependencies in the project. - */ - if (selProjBean != null && depBean != null) { - final List<MIDependency> availableDependencies = depBean.getDependencies(); - - for (final MIDependency dependency : this.project.getDependencies()) { - for (final MIDependency actDependency : availableDependencies) { - if (actDependency.getFilePath().equals(dependency.getFilePath())) { - this.dependencies.add(actDependency); - continue; - } - } - } - } - } - - /** - * Delivers the currently selected dependencies. - * - * @return The selected dependencies. - */ - public List<MIDependency> getDependencies() { - return this.dependencies; - } - - /** - * Sets the currently selected dependencies to a new value. - * - * @param dependencies - * The newly selected dependencies. - */ - public void setDependencies(final List<MIDependency> dependencies) { - this.dependencies = dependencies; - } - - /** - * This method should be called as an action. It clears the project's dependencies and adds all currently selected dependencies to this project. - */ - public void submit() { - if (this.project != null) { - this.project.getDependencies().clear(); - this.project.getDependencies().addAll(this.dependencies); - FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "", "Dependencies saved.")); - } else { - FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "", "No project selected.")); - } - } - -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/StringBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/StringBean.java index 0fd11aa5..babc86bb 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/StringBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/StringBean.java @@ -65,7 +65,8 @@ public class StringBean { } /** - * This method verifies whether the given object is an instance of {@link java.lang.String} or not. + * This method verifies whether the given object is an instance of {@link java.lang.String} or not. This is necessary due to the fact that the + * 'instanceof'-command has not yet been implemented in JSF. * * @param object * The object to be verified. @@ -74,4 +75,16 @@ public class StringBean { public boolean checkString(final Object object) { return object instanceof String; } + + /** + * Modifies the given string so that it can be used as an ID. In other words: It removes all space characters. It is usually used to convert the 'address' of an + * object into an unique ID. It is not guaranteed that the result will be a valid ID in other cases. + * + * @param string + * The string to be modified. + * @return The given string without space characters. + */ + public String stringToID(final String string) { + return string.replace(" ", ""); + } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/package-info.java deleted file mode 100644 index e4a52d8d..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * 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. - ***************************************************************************/ - -/** - * This package contains all beans with request scope. - */ -package kieker.webgui.beans.request; - diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/AnalysisControllerBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/AnalysisControllerBean.java deleted file mode 100644 index 1996b791..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/AnalysisControllerBean.java +++ /dev/null @@ -1,158 +0,0 @@ -/*************************************************************************** - * 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.session; - -import java.util.HashMap; -import java.util.Map; - -import javax.faces.bean.ManagedBean; -import javax.faces.bean.SessionScoped; - -import kieker.analysis.AnalysisController; -import kieker.analysis.exception.AnalysisConfigurationException; -import kieker.analysis.model.analysisMetaModel.MIPlugin; -import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.analysis.model.analysisMetaModel.MIRepository; -import kieker.analysis.plugin.AbstractPlugin; -import kieker.analysis.repository.AbstractRepository; -import kieker.common.logging.Log; -import kieker.common.logging.LogFactory; -import kieker.common.logging.LogImplWebguiLogging; -import kieker.webgui.common.PluginClassLoader; - -/** - * This bean contains an instance of {@link AnalysisController} and supplies methods to control the instance. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@ManagedBean -@SessionScoped -public class AnalysisControllerBean { - /** - * The logger within this class. - */ - private static final Log LOG = LogFactory.getLog(AnalysisControllerBean.class); - /** - * The controller instance stored within this bean. - */ - private AnalysisController controller; - private Map<MIPlugin, AbstractPlugin> pluginMap; - private Map<MIRepository, AbstractRepository> repositoryMap; - - /** - * Creates a new instance of this class. - */ - public AnalysisControllerBean() { - // No code necessary. - } - - public Map<MIPlugin, AbstractPlugin> getPluginMap() { - return this.pluginMap; - } - - public Map<MIRepository, AbstractRepository> getRepositoryMap() { - return this.repositoryMap; - } - - /** - * Delivers the controller stored within this bean. - * - * @return The current controller in this bean. - */ - public AnalysisController getController() { - return this.controller; - } - - /** - * Sets the controller stored within this bean to a new value. - * - * @param controller - * The new controller. - */ - public void setController(final AnalysisController controller) { - this.controller = controller; - } - - /** - * This method tries to instantiate a new controller using the given project. If the project is null, nothing happens. - * - * @param mProject - * The project used to create a new analysis controller. - */ - public void instantiate(final MIProject mProject) { - if (mProject != null) { - try { - // Try to create the controller. - final AnalysisController.AnalysisControllerWithMapping controllerAndMapping = AnalysisController.createAnalysisController(mProject, - PluginClassLoader.getInstance()); - // Extract everything that is necessary. - this.controller = controllerAndMapping.getController(); - this.pluginMap = controllerAndMapping.getPluginMap(); - this.repositoryMap = controllerAndMapping.getRepositoryMap(); - } catch (final NullPointerException ex) { - AnalysisControllerBean.LOG.error("Could not create analysis controller.", ex); - } catch (final AnalysisConfigurationException ex) { - AnalysisControllerBean.LOG.error("Could not create analysis controller.", ex); - } - } - } - - /** - * Starts asynchronously the analysis controller within this bean. - */ - public void start() { - final Thread thread = new Thread() { - @Override - public void run() { - try { - AnalysisControllerBean.this.controller.run(); - } catch (final IllegalStateException ex) { - AnalysisControllerBean.LOG.error("Could not start the analysis controller.", ex); - } catch (final AnalysisConfigurationException ex) { - AnalysisControllerBean.LOG.error("Could not start the analysis controller.", ex); - } - } - }; - thread.start(); - } - - /** - * Stops asynchronously the analysis controller within this bean. - */ - public void stop() { - final Thread thread = new Thread() { - @Override - public void run() { - AnalysisControllerBean.this.controller.terminate(); - } - }; - thread.start(); - } - - /** - * This method delivers all log entries of the class {@link AnalysisController}. - * - * @return All log entries of the analysis controller. - */ - public String[] getLogEntries() { - return LogImplWebguiLogging.getEntries(AnalysisController.class.getName()); - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java new file mode 100644 index 00000000..1b5db7db --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java @@ -0,0 +1,88 @@ +/*************************************************************************** + * 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.session; + +import javax.faces.bean.ManagedBean; +import javax.faces.bean.SessionScoped; + +/** + * This bean contains the project of the current (session) user for the analysis cockpit. + * + * @author Nils Christian Ehmke + * @version 1.0 + */ +@ManagedBean +@SessionScoped +public class CurrentAnalysisCockpitProjectBean { + + /** + * This is the page used for the redirecting during setting the current project of the user. + */ + private static final String PAGE_ANALYSIS_COCKPIT = "AnalysisCockpit.xhtml"; + /** + * This is the page used for the redirecting during closing the cockpit. + */ + private static final String PAGE_PROJECT_OVERVIEW = "ProjectOverview.xhtml"; + /** + * This is the name of the stored project. It can be used as an identifier within the FS-Manager + */ + private String projectName; + + /** + * Creates a new instance of this class. + */ + public CurrentAnalysisCockpitProjectBean() { + // No code necessary + } + + /** + * This method sets the project stored within this bean and returns the new page for the navigation. + * + * @param projectName + * The name of the project. + * @return The name of the page for the analysis cockpit. + */ + public String setProject(final String projectName) { + this.projectName = projectName; + + return CurrentAnalysisCockpitProjectBean.PAGE_ANALYSIS_COCKPIT; + } + + /** + * This method delivers the project name stored in this bean. + * + * @return The project name for this user. + */ + public String getProjectName() { + return this.projectName; + } + + /** + * This method clears the bean. In other words: The stored project is set to null and it will return the page of the project overview for navigation purposes. + * + * @return The name of the page of the project overview. + */ + public String clearProject() { + this.projectName = null; + + return CurrentAnalysisCockpitProjectBean.PAGE_PROJECT_OVERVIEW; + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java new file mode 100644 index 00000000..f0cd345d --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java @@ -0,0 +1,88 @@ +/*************************************************************************** + * 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.session; + +import javax.faces.bean.ManagedBean; +import javax.faces.bean.SessionScoped; + +/** + * This bean contains the project of the current (session) user for the analysis controller page. + * + * @author Nils Christian Ehmke + * @version 1.0 + */ +@ManagedBean +@SessionScoped +public class CurrentAnalysisControllerProjectBean { + + /** + * This is the page used for the redirecting during setting the current project of the user. + */ + private static final String PAGE_ANALYSIS_CONTROLLER = "AnalysisController.xhtml"; + /** + * This is the page used for the redirecting during closing the controller. + */ + private static final String PAGE_PROJECT_OVERVIEW = "ProjectOverview.xhtml"; + /** + * This is the name of the stored project. It can be used as an identifier within the FS-Manager + */ + private String projectName; + + /** + * Creates a new instance of this class. + */ + public CurrentAnalysisControllerProjectBean() { + // No code necessary + } + + /** + * This method sets the project stored within this bean and returns the new page for the navigation. + * + * @param projectName + * The name of the project. + * @return The name of the page for the analysis controller. + */ + public String setProject(final String projectName) { + this.projectName = projectName; + + return CurrentAnalysisControllerProjectBean.PAGE_ANALYSIS_CONTROLLER; + } + + /** + * This method delivers the project name stored in this bean. + * + * @return The project name for this user. + */ + public String getProjectName() { + return this.projectName; + } + + /** + * This method clears the bean. In other words: The stored project is set to null and it will return the page of the project overview for navigation purposes. + * + * @return The name of the page of the project overview. + */ + public String clearProject() { + this.projectName = null; + + return CurrentAnalysisControllerProjectBean.PAGE_PROJECT_OVERVIEW; + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java new file mode 100644 index 00000000..c1c3d27e --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java @@ -0,0 +1,88 @@ +/*************************************************************************** + * 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.session; + +import javax.faces.bean.ManagedBean; +import javax.faces.bean.SessionScoped; + +/** + * This bean contains the project of the current (session) user for the analysis view work space. + * + * @author Nils Christian Ehmke + * @version 1.0 + */ +@ManagedBean +@SessionScoped +public class CurrentAnalysisViewWorkSpaceProjectBean { + + /** + * This is the page used for the redirecting during setting the current project of the user. + */ + private static final String PAGE_ANALYSIS_VIEW_WORK_SPACE = "AnalysisViewWorkSpace.xhtml"; + /** + * This is the page used for the redirecting during closing the work space. + */ + private static final String PAGE_PROJECT_OVERVIEW = "ProjectOverview.xhtml"; + /** + * This is the name of the stored project. It can be used as an identifier within the FS-Manager + */ + private String projectName; + + /** + * Creates a new instance of this class. + */ + public CurrentAnalysisViewWorkSpaceProjectBean() { + // No code necessary + } + + /** + * This method sets the project stored within this bean and returns the new page for the navigation. + * + * @param projectName + * The name of the project. + * @return The name of the page for the analysis view work space. + */ + public String setProject(final String projectName) { + this.projectName = projectName; + + return CurrentAnalysisViewWorkSpaceProjectBean.PAGE_ANALYSIS_VIEW_WORK_SPACE; + } + + /** + * This method delivers the project name stored in this bean. + * + * @return The project name for this user. + */ + public String getProjectName() { + return this.projectName; + } + + /** + * This method clears the bean. In other words: The stored project is set to null and it will return the page of the project overview for navigation purposes. + * + * @return The name of the page of the project overview. + */ + public String clearProject() { + this.projectName = null; + + return CurrentAnalysisViewWorkSpaceProjectBean.PAGE_PROJECT_OVERVIEW; + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentThemeBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentThemeBean.java index 58a90a81..23881d9e 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentThemeBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentThemeBean.java @@ -2,7 +2,7 @@ * Copyright 2012 by * + Christian-Albrechts-University of Kiel * + Department of Computer Science - * + Software Engineering Group + * + Software Engineering Group * and others. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,8 @@ import kieker.webgui.beans.application.ThemeSwitcherBean; /** * This bean can be used for a single session of a user and stores the currently used theme (look and feel) for this user. Currently the default value being used is - * the "glass-x"-theme, if none other value can be find within the parameters of the faces context. + * the "glass-x"-theme, if none other value can be find within the + * parameters of the faces context or in the cookies of the user. * * @author Nils Christian Ehmke * @@ -41,20 +42,20 @@ import kieker.webgui.beans.application.ThemeSwitcherBean; */ @ManagedBean @SessionScoped -public class CurrentThemeBean { +public final class CurrentThemeBean { /** * The default theme used for all users. */ private static final String DEFAULT_THEME = "glass-x"; - /** - * The key to identify the theme in the properties. - */ - private static final String KEY_THEME = "theme"; /** * The key to identify the theme in the cookie. */ private static final String KEY_COOKIE_THEME = "theme"; + /** + * The key to identify the theme in the properties. + */ + private static final String KEY_THEME = "theme"; /** * The current theme. */ @@ -100,9 +101,12 @@ public class CurrentThemeBean { public final void setTheme(final String theme) { this.theme = theme; - // Set the cookie theme. - final Cookie cookie = new Cookie("theme", theme); + // Set the theme cookie. + final Cookie cookie = new Cookie(CurrentThemeBean.KEY_COOKIE_THEME, theme); + // Try to save it for a year (maximum age) + cookie.setMaxAge(60 * 60 * 24 * 365); + // Deliver the cookie final HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse(); response.addCookie(cookie); } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java new file mode 100644 index 00000000..1582a283 --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java @@ -0,0 +1,352 @@ +/*************************************************************************** + * 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.session; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.faces.application.FacesMessage; +import javax.faces.application.FacesMessage.Severity; +import javax.faces.bean.ManagedBean; +import javax.faces.bean.SessionScoped; +import javax.faces.context.FacesContext; + +import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; +import kieker.analysis.model.analysisMetaModel.MIDependency; +import kieker.analysis.model.analysisMetaModel.MIProject; +import kieker.analysis.model.analysisMetaModel.impl.MAnalysisMetaModelFactory; +import kieker.analysis.plugin.AbstractPlugin; +import kieker.analysis.plugin.annotation.Plugin; +import kieker.analysis.plugin.filter.AbstractFilterPlugin; +import kieker.analysis.plugin.reader.AbstractReaderPlugin; +import kieker.analysis.repository.AbstractRepository; +import kieker.analysis.repository.annotation.Repository; +import kieker.webgui.common.FSManager; +import kieker.webgui.common.Pair; +import kieker.webgui.common.PluginFinder; +import kieker.webgui.common.exception.LibraryAlreadyExistingException; + +import org.primefaces.event.FileUploadEvent; +import org.primefaces.model.UploadedFile; + +/** + * This bean contains the project of the current (session) user for the project work space. + * + * @author Nils Christian Ehmke + * @version 1.0 + */ +@ManagedBean +@SessionScoped +public final class CurrentWorkSpaceProjectBean { + + /** + * This is the page used for the redirecting during setting the current project of the user. + */ + private static final String PAGE_PROJECT_WORK_SPACE = "ProjectWorkSpace.xhtml"; + /** + * This is the page used for the redirecting during closing the work space. + */ + private static final String PAGE_PROJECT_OVERVIEW = "ProjectOverview.xhtml"; + /** + * This is the factory which will be used to create new components for the project. + */ + private final MIAnalysisMetaModelFactory factory = new MAnalysisMetaModelFactory(); + /** + * This is the actual model instance. It is the in-memory-model of the current (session) user. + */ + private MIProject project; + /** + * This is the corresponding class loader to the project. It contains always the libraries within the lib-folder of the project. + */ + private ClassLoader classLoader; + /** + * This is the name of the stored project. It can be used as an identifier within the FS-Manager + */ + private String projectName; + /** + * This is the time stamp of the moment, the project was loaded or last saved. It can be used to check whether the project has been modified in the meanwhile. + */ + private long timeStamp; + /** + * This list contains the available repositories for the current project. + */ + private final List<Class<AbstractRepository>> availableRepositories = Collections.synchronizedList(new ArrayList<Class<AbstractRepository>>()); + /** + * This list contains the available filters for the current project. + */ + private final List<Class<AbstractFilterPlugin>> availableFilters = Collections.synchronizedList(new ArrayList<Class<AbstractFilterPlugin>>()); + /** + * This list contains the available readers for the current project. + */ + private final List<Class<AbstractReaderPlugin>> availableReaders = Collections.synchronizedList(new ArrayList<Class<AbstractReaderPlugin>>()); + + /** + * Creates a new instance of this class. + */ + public CurrentWorkSpaceProjectBean() { + // No code necessary + } + + /** + * This method delivers the project stored in this bean. + * + * @return The project for this user. + */ + public MIProject getProject() { + return this.project; + } + + /** + * This method sets the project stored within this bean and returns the new page for the navigation - depending on the given values. + * + * @param project + * The project to be stored within this bean. + * @param projectName + * The name of the project. + * @return The name of the page for the project work space, if the project has been accepted, '' if it is null. + */ + public String setProject(final MIProject project, final String projectName) { + // Remember the given parameters + this.project = project; + this.projectName = projectName; + // Remember the current time! This is important for the later comparison of the time stamps. + this.resetTimeStamp(); + // Update the class loader + this.reloadClassLoader(); + // Add the libraries within the lib-folder to the current model + this.addLibrariesToModel(); + // Load the available readers, filters and repositories + this.loadToolPalette(); + + // Now deliver the correct navigation page + return (this.project != null) ? CurrentWorkSpaceProjectBean.PAGE_PROJECT_WORK_SPACE : ""; + } + + /** + * This method loads the list of available readers, filters and repositories, using the current libraries within the model. + */ + private void loadToolPalette() { + // Clean our tool palette + this.availableFilters.clear(); + this.availableReaders.clear(); + this.availableRepositories.clear(); + + // Make sure there is a project. + if (this.project != null) { + // Run through all libraries + for (final MIDependency lib : this.project.getDependencies()) { + this.addToToolPalette(lib); + } + } + } + + /** + * This method adds all available readers, filters and repositories within the given library to the lists of this bean. + * + * @param lib + * The library used to load the plugins and repositories. + */ + private void addToToolPalette(final MIDependency lib) { + try { + final List<Class<AbstractRepository>> repositories = PluginFinder.getAllRepositoriesWithinJar(FSManager.getInstance().getURL(lib, this.projectName), + this.classLoader); + final List<Class<AbstractPlugin>> plugins = PluginFinder.getAllPluginsWithinJar(FSManager.getInstance().getURL(lib, this.projectName), + this.classLoader); + // Now run through the available classes and add all non-abstract classes to our lists + for (final Class<AbstractRepository> repository : repositories) { + if (!Modifier.isAbstract(repository.getModifiers())) { + this.availableRepositories.add(repository); + } + } + for (final Class<? extends AbstractPlugin> plugin : plugins) { + if (!Modifier.isAbstract(plugin.getModifiers())) { + if (AbstractFilterPlugin.class.isAssignableFrom(plugin)) { + this.availableFilters.add((Class<AbstractFilterPlugin>) plugin); + } else { + if (AbstractReaderPlugin.class.isAssignableFrom(plugin)) { + this.availableReaders.add((Class<AbstractReaderPlugin>) plugin); + } + } + } + } + } catch (final MalformedURLException ex) { + ex.printStackTrace(); + } + } + + /** + * This method takes all libraries from the lib-folder and adds them to the in-memory-model. + */ + private void addLibrariesToModel() { + final List<MIDependency> libs = FSManager.getInstance().getModelLibraries(this.projectName); + this.project.getDependencies().addAll(libs); + } + + /** + * This method reloads the class loader. In other words: The class loader will always be able to load classes from the jar-files within the lib-folder of the + * project. + */ + private void reloadClassLoader() { + this.classLoader = FSManager.getInstance().getClassLoader(this.projectName); + } + + /** + * This method sets the time stamp to the current system time. + */ + public void resetTimeStamp() { + this.timeStamp = System.currentTimeMillis(); + } + + /** + * This method delivers the project name stored in this bean. + * + * @return The project name for this user. + */ + public String getProjectName() { + return this.projectName; + } + + /** + * This method delivers the current time stamp. + * + * @return The time stamp for this user. + */ + public long getTimeStamp() { + return this.timeStamp; + } + + /** + * This method clears the bean. In other words: The stored project is set to null and it will return the page of the project overview for navigation purposes. + * + * @return The name of the page of the project overview. + */ + public String clearProject() { + this.project = null; + this.projectName = null; + this.timeStamp = 0; + + return CurrentWorkSpaceProjectBean.PAGE_PROJECT_OVERVIEW; + } + + /** + * This method can be used to get the description of an {@link AbstractPlugin}- or an {@link AbstractRepository}-class. The description is read via the + * annotation. + * + * @param clazz + * The class whose description should be extracted. + * @return The description for the class or a substitute if none is available. This is in either case human readable. + */ + public String getDescription(final Class<?> clazz) { + // Get the two potential annotations + final Plugin annotationPlugin = clazz.getAnnotation(Plugin.class); + final Repository annotationRepository = clazz.getAnnotation(Repository.class); + + // Now check which one of them is available + if ((annotationPlugin == null) || annotationPlugin.description().isEmpty()) { + if ((annotationRepository == null) || annotationRepository.description().isEmpty()) { + // None. Deliver a human readable substitute. + return "No description available"; + } else { + return annotationRepository.description(); + } + } else { + return annotationPlugin.description(); + } + } + + /** + * This method is the handler for the file upload. It tries to upload the given file and informs the user via the growl-component. + * + * @param event + * The upload event. + */ + public void handleFileUpload(final FileUploadEvent event) { + // Get the file from the event + final UploadedFile file = event.getFile(); + + try { + // Use the file system manager to upload the new file + final MIDependency lib = FSManager.getInstance().uploadLibrary(file, this.projectName); + CurrentWorkSpaceProjectBean.showMessage(FacesMessage.SEVERITY_INFO, "Libary uploaded."); + // As it seem to have worked, we can add the library to our model. + this.project.getDependencies().add(lib); + // Update our class loader + this.reloadClassLoader(); + } catch (final LibraryAlreadyExistingException ex) { + CurrentWorkSpaceProjectBean.showMessage(FacesMessage.SEVERITY_WARN, "A library with the same name exists already."); + } catch (final IOException ex) { + CurrentWorkSpaceProjectBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while uploading the library."); + } + } + + /** + * This method delivers the available libraries of this project as a pair of strings. The first element is the name of the library, the second one te size in + * MiBytes as human readable string. + * + * @return The available libraries. + */ + public List<Pair<String, String>> getLibraries() { + return FSManager.getInstance().getLibraries(this.projectName); + } + + /** + * This method delivers the available reader-plugins for the current main project. The delivered plugins are never abstract. + * + * @return A list with all readers. + */ + public final List<Class<AbstractReaderPlugin>> getAvailableReaders() { + return this.availableReaders; + } + + /** + * This method delivers the available filter-plugins for the current main project. The delivered plugins are never abstract. + * + * @return A list with all filter. + */ + public final List<Class<AbstractFilterPlugin>> getAvailableFilters() { + return this.availableFilters; + } + + /** + * This method delivers the available repositories for the current main project. The delivered repositories are never abstract. + * + * @return A list with all repositories. + */ + public final List<Class<AbstractRepository>> getAvailableRepositories() { + return this.availableRepositories; + } + + /** + * This method shows the current user a message by using the growl-component of PrimeFaces. + * + * @param severity + * The severity of the message. + * @param msg + * The message itself. + */ + private static void showMessage(final Severity severity, final String msg) { + FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, "", msg)); + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DashboardBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DashboardBean.java deleted file mode 100644 index 57c57af1..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DashboardBean.java +++ /dev/null @@ -1,161 +0,0 @@ -/*************************************************************************** - * 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.session; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import javax.annotation.PostConstruct; -import javax.faces.application.Application; -import javax.faces.bean.ManagedBean; -import javax.faces.bean.SessionScoped; -import javax.faces.component.html.HtmlOutputText; -import javax.faces.context.FacesContext; - -import kieker.webgui.beans.application.ProjectsBean; -import kieker.webgui.beans.application.ProjectsBean.Widget; - -import org.primefaces.component.dashboard.Dashboard; -import org.primefaces.component.panel.Panel; -import org.primefaces.event.DashboardReorderEvent; -import org.primefaces.model.DashboardModel; -import org.primefaces.model.DefaultDashboardColumn; -import org.primefaces.model.DefaultDashboardModel; - -/** - * This bean can be used to handle an instance of {@link Dashboard} including a list of {@code Widget}. It makes sure that new widget-instances can be added - * dynamically. - * - * @author Nils Christian Ehmke - */ -@SessionScoped -@ManagedBean -public class DashboardBean implements Serializable { - - /** - * This is the prefix used to the widgets within the component. - */ - private static final String WIDGET_ID_PREFIX = "widget_"; - - /** - * This is the dashboard to be controlled by this instance. - */ - private Dashboard dashboard; - /** - * This is the model used to fill the dasboard. - */ - private DashboardModel dashboardModel; - /** - * This is the list containing all widgets. - */ - private final List<Widget> widgets = new ArrayList<ProjectsBean.Widget>(); - - /** - * Creates a new instance of this class. - */ - public DashboardBean() { - // No code necessary. - } - - @PostConstruct - public void init() { - final FacesContext fc = FacesContext.getCurrentInstance(); - final Application application = fc.getApplication(); - - // Add three columns for the model - this.dashboardModel = new DefaultDashboardModel(); - this.dashboardModel.addColumn(new DefaultDashboardColumn()); - this.dashboardModel.addColumn(new DefaultDashboardColumn()); - this.dashboardModel.addColumn(new DefaultDashboardColumn()); - - this.dashboard = (Dashboard) application.createComponent(fc, "org.primefaces.component.Dashboard", "org.primefaces.component.DashboardRenderer"); - this.dashboard.setId("dashboard"); - this.dashboard.setModel(this.dashboardModel); - - this.addChildren(); - } - - /** - * This method can be used to update the UI children of the dashboard. - */ - private void addChildren() { - synchronized (this) { - // Clear the list with the children to avoid double IDs. - this.dashboard.getChildren().clear(); - - final FacesContext fc = FacesContext.getCurrentInstance(); - final Application application = fc.getApplication(); - - // Run through all widgets and add a panel for each of them. - for (int i = 0; i < this.widgets.size(); i++) { - final Panel panel = (Panel) application.createComponent(fc, "org.primefaces.component.Panel", "org.primefaces.component.PanelRenderer"); - panel.setId(DashboardBean.WIDGET_ID_PREFIX + i); - panel.setHeader(this.widgets.get(i).getName()); - panel.setClosable(true); - panel.setToggleable(true); - - this.dashboard.getChildren().add(panel); - - final HtmlOutputText text = new HtmlOutputText(); - text.setId("t" + DashboardBean.WIDGET_ID_PREFIX + i); - text.setValue(this.widgets.get(i).getType()); - panel.getChildren().add(text); - } - } - } - - /** - * Delivers the currently stored dashboard. - * - * @return The dashboard. - */ - public Dashboard getDashboard() { - this.addChildren(); - return this.dashboard; - } - - public void setDashboard(final Dashboard dashboard) { - this.dashboard = dashboard; - } - - /** - * Adds a new widget to the list. - * - * @param widget - * The widget to be add to the bean. - */ - public void addWidget(final Widget widget) { - // Add the widget and add it to the model as well. - synchronized (this) { - this.widgets.add(widget); - this.dashboardModel.getColumn(new Random().nextInt(3)).addWidget(DashboardBean.WIDGET_ID_PREFIX + (this.widgets.size() - 1)); - } - - // Update the UI - this.addChildren(); - } - - public void handleReorder(final DashboardReorderEvent event) { - // Nothing to do yet - this.addChildren(); - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DependencyUploadBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DependencyUploadBean.java deleted file mode 100644 index dd3714d7..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/DependencyUploadBean.java +++ /dev/null @@ -1,87 +0,0 @@ -/*************************************************************************** - * 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.session; - -import javax.faces.bean.ManagedBean; -import javax.faces.bean.SessionScoped; -import javax.faces.context.FacesContext; - -import kieker.webgui.beans.application.DependenciesBean; - -import org.primefaces.model.UploadedFile; - -/** - * This bean is a session bean and can be used to store and upload a new dependency. It accesses the application instance of <code>DependenciesBean</code> directly. - * - * @see DependenciesBean - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@ManagedBean -@SessionScoped -public class DependencyUploadBean { - - /** - * The file stored within this bean. - */ - private UploadedFile file; - - /** - * Creates a new instance of this class. - */ - public DependencyUploadBean() { - // No code necessary. - } - - /** - * Delivers the instance stored within this bean. - * - * @return The currently stored value within this bean. - */ - public UploadedFile getFile() { - return this.file; - } - - /** - * Sets the new value of the bean. - * - * @param file - * The file instance to be stored within this bean. - */ - public void setFile(final UploadedFile file) { - this.file = file; - } - - /** - * Tries to upload the currently stored value within this bean. - */ - public void upload() { - if (this.file != null) { - final FacesContext context = FacesContext.getCurrentInstance(); - final DependenciesBean bean = context.getApplication().evaluateExpressionGet(context, "#{dependenciesBean}", - DependenciesBean.class); - if (bean != null) { - bean.uploadDependency(this.file); - } - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedMainProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedMainProjectBean.java deleted file mode 100644 index 7342da33..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedMainProjectBean.java +++ /dev/null @@ -1,531 +0,0 @@ -/*************************************************************************** - * 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.session; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Observable; -import java.util.Observer; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.faces.application.FacesMessage; -import javax.faces.bean.ManagedBean; -import javax.faces.bean.SessionScoped; -import javax.faces.context.FacesContext; - -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.analysis.model.analysisMetaModel.MIFilter; -import kieker.analysis.model.analysisMetaModel.MIInputPort; -import kieker.analysis.model.analysisMetaModel.MIOutputPort; -import kieker.analysis.model.analysisMetaModel.MIPlugin; -import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.analysis.model.analysisMetaModel.MIProperty; -import kieker.analysis.model.analysisMetaModel.impl.MAnalysisMetaModelFactory; -import kieker.analysis.plugin.AbstractPlugin; -import kieker.analysis.plugin.filter.AbstractFilterPlugin; -import kieker.analysis.plugin.reader.AbstractReaderPlugin; -import kieker.analysis.repository.AbstractRepository; -import kieker.common.configuration.Configuration; -import kieker.common.logging.Log; -import kieker.common.logging.LogFactory; -import kieker.webgui.beans.application.ProjectsBean; -import kieker.webgui.common.Connection; -import kieker.webgui.common.FileManager; -import kieker.webgui.common.PluginClassLoader; -import kieker.webgui.common.PluginFinder; - -import org.eclipse.emf.common.util.EList; -import org.primefaces.context.RequestContext; - -/** - * This session bean stores the currently selected main project of the user and provides different methods to access and manipulate the properties of this project. - * It is possible that this bean accesses other beans directly. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@ManagedBean -@SessionScoped -public class SelectedMainProjectBean extends Observable implements Observer { - /** - * The logger within this class. - */ - private static final Log LOG = LogFactory.getLog(SelectedMainProjectBean.class); - /** - * The error message used if a plugin could not be instantiated for various reasons. - */ - private static final String ERR_MSG_LOAD_PLUGIN = "Could not instantiate plugin."; - /** - * The error message used if dependency could not loaded due to an invalid URL. - */ - private static final String ERR_MSG_INVALID_URL = "Invalid URL for dependency."; - /** - * This constant is used as the host for the dependencies. - */ - private static final String URL_LOCALHOST = "localhost"; - /** - * This constant is used as a protocol for the dependencies. - */ - private static final String URL_PROTOCOL_FILE = "file"; - - /** - * This collection contains all targets within the current view which will be updated when the selection of the main project changes. - */ - private static final Collection<String> UPDATE_TARGETS = Collections.unmodifiableCollection(Arrays.asList(new String[] { "projectsForm", "toolpalette", - "centerForm", })); - - /** - * The main project of the current user. - */ - private MIProject mainProject; - /** - * This list contains the connections (between the filters) within the current main project. - */ - private List<Connection> connections; - - private final ProjectsBean observableBean; - - /** - * Creates a new instance of this class. - */ - public SelectedMainProjectBean() { - // Make sure that the collection for the connection is not empty. This will make the iteration over the collection - this.connections = new ArrayList<Connection>(); - - // Try to get the projects bean. - final FacesContext context = FacesContext.getCurrentInstance(); - this.observableBean = context.getApplication().evaluateExpressionGet(context, "#{projectsBean}", ProjectsBean.class); - } - - /** - * Delivers the main project of the current user. It can be null. - * - * @return The user's main project. - */ - public final MIProject getMainProject() { - return this.mainProject; - } - - /** - * Sets the main project of the current user. - * - * @param mainProject - * The new main project of the current user. - */ - public final void setMainProject(final MIProject mainProject) { - // Overtake the main project and its connection. - this.mainProject = mainProject; - this.connections = this.getConnectionsFromProject(); - - // In the case we haven't set the main project to null, we inform the user about the change. - if (this.mainProject != null) { - FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "", "New main project: " + mainProject.getName())); - } - - // Inform the observers - this.setChanged(); - this.notifyObservers(new MsgMainProjectSelection(mainProject)); - - // Update the corresponding components - final RequestContext requestContext = RequestContext.getCurrentInstance(); - requestContext.addPartialUpdateTargets(SelectedMainProjectBean.UPDATE_TARGETS); - } - - /** - * This method delivers the available reader-plugins for the current main project. The delivered plugins are never abstract. - * - * @return A list with all readers. - */ - public final List<Class<AbstractReaderPlugin>> getAvailableReaders() { - final List<Class<AbstractReaderPlugin>> list = new ArrayList<Class<AbstractReaderPlugin>>(); - - // Make sure there is a main project. - if (this.mainProject != null) { - // Run through all libraries - for (final MIDependency lib : this.mainProject.getDependencies()) { - // Make sure the plugin class loader knows about the lib - try { - PluginClassLoader.getInstance().addURL( - new URL(SelectedMainProjectBean.URL_PROTOCOL_FILE, SelectedMainProjectBean.URL_LOCALHOST, FileManager.getInstance().getFullPath(lib))); - } catch (final MalformedURLException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_INVALID_URL, ex); - } - // Now try to find the plugins within the library and extract the readers. - try { - final List<Class<AbstractPlugin>> plugins = PluginFinder.getAllPluginsWithinJar(new URL(SelectedMainProjectBean.URL_PROTOCOL_FILE, - SelectedMainProjectBean.URL_LOCALHOST, FileManager.getInstance().getFullPath(lib))); - for (final Class<?> plugin : plugins) { - if (!Modifier.isAbstract(plugin.getModifiers()) && AbstractReaderPlugin.class.isAssignableFrom(plugin)) { - list.add((Class<AbstractReaderPlugin>) plugin); - } - } - } catch (final MalformedURLException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_INVALID_URL, ex); - } - } - } - - return list; - } - - /** - * This method delivers the available filter-plugins for the current main project. The delivered plugins are never abstract. - * - * @return A list with all filter. - */ - public final List<Class<AbstractFilterPlugin>> getAvailableFilters() { - final List<Class<AbstractFilterPlugin>> list = new ArrayList<Class<AbstractFilterPlugin>>(); - - if (this.mainProject != null) { - for (final MIDependency lib : this.mainProject.getDependencies()) { - try { - PluginClassLoader.getInstance().addURL( - new URL(SelectedMainProjectBean.URL_PROTOCOL_FILE, SelectedMainProjectBean.URL_LOCALHOST, FileManager.getInstance().getFullPath(lib))); - } catch (final MalformedURLException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_INVALID_URL, ex); - } - try { - final List<Class<AbstractPlugin>> plugins = PluginFinder.getAllPluginsWithinJar(new URL(SelectedMainProjectBean.URL_PROTOCOL_FILE, - SelectedMainProjectBean.URL_LOCALHOST, FileManager.getInstance().getFullPath(lib))); - for (final Class<?> plugin : plugins) { - if (!Modifier.isAbstract(plugin.getModifiers()) && AbstractFilterPlugin.class.isAssignableFrom(plugin)) { - list.add((Class<AbstractFilterPlugin>) plugin); - } - } - } catch (final MalformedURLException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_INVALID_URL, ex); - } - } - } - - return list; - - } - - /** - * This method delivers the available repositories for the current main project. The delivered repositories are never abstract. - * - * @return A list with all repositories. - */ - public final List<Class<AbstractRepository>> getAvailableRepositories() { - final List<Class<AbstractRepository>> list = new ArrayList<Class<AbstractRepository>>(); - - if (this.mainProject != null) { - for (final MIDependency lib : this.mainProject.getDependencies()) { - try { - PluginClassLoader.getInstance().addURL( - new URL(SelectedMainProjectBean.URL_PROTOCOL_FILE, SelectedMainProjectBean.URL_LOCALHOST, FileManager.getInstance().getFullPath(lib))); - } catch (final MalformedURLException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_INVALID_URL, ex); - } - try { - final List<Class<AbstractRepository>> repositories = PluginFinder.getAllRepositoriesWithinJar(new URL(SelectedMainProjectBean.URL_PROTOCOL_FILE, - SelectedMainProjectBean.URL_LOCALHOST, FileManager.getInstance().getFullPath(lib))); - for (final Class<AbstractRepository> repository : repositories) { - if (!Modifier.isAbstract(repository.getModifiers())) { - list.add(repository); - } - } - } catch (final MalformedURLException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_INVALID_URL, ex); - } - } - } - - return list; - - } - - /** - * This method uses the actual plugin to create the model configuration instances and add them to the model plugin instance. - * - * @param plugin - * The plugin whose configuration will be used. - * @param mPlugin - * The model plugin which will be modified. - */ - private static void addConfiguration(final AbstractPlugin plugin, final MIPlugin mPlugin) { - // Get the current configuration and use it to initialize the model plugin. - final Configuration configuration = plugin.getCurrentConfiguration(); - final MAnalysisMetaModelFactory factory = new MAnalysisMetaModelFactory(); - - // Run through all entries. - final Iterator<Map.Entry<Object, Object>> iterator = configuration.entrySet().iterator(); - while (iterator.hasNext()) { - final Map.Entry<Object, Object> entry = iterator.next(); - // Create a property object for the current entry. - final MIProperty property = factory.createProperty(); - property.setName(entry.getKey().toString()); - property.setValue(entry.getValue().toString()); - - mPlugin.getProperties().add(property); - } - } - - /** - * This method uses the actual plugin to create the model port instances and add them to the model plugin instance. - * - * @param plugin - * The plugin whose ports will be used. - * @param mPlugin - * The model plugin which will be modified. - */ - private static void addPorts(final AbstractPlugin plugin, final MIPlugin mPlugin) { - // Get the port and use them to initialize the model plugin. - final String[] inputPortNames = plugin.getAllInputPortNames(); - final String[] outputPortNames = plugin.getAllOutputPortNames(); - - final MAnalysisMetaModelFactory factory = new MAnalysisMetaModelFactory(); - - if (mPlugin instanceof MIFilter) { - for (final String inputPortName : inputPortNames) { - final MIInputPort mInputPort = factory.createInputPort(); - mInputPort.setName(inputPortName); - mInputPort.setParent((MIFilter) mPlugin); - } - } - - for (final String outputPortName : outputPortNames) { - final MIOutputPort mOutputPort = factory.createOutputPort(); - mOutputPort.setName(outputPortName); - mOutputPort.setParent(mPlugin); - } - } - - /** - * This method can be used to add a model plugin instance to the current main project using the given class. - * - * @param pluginClass - * The class which will be instantiated. - */ - public final void addPlugin(final Class<AbstractPlugin> pluginClass) { - final MAnalysisMetaModelFactory factory = new MAnalysisMetaModelFactory(); - - try { - final AbstractPlugin plugin = pluginClass.getConstructor(Configuration.class).newInstance(new Configuration()); - MIPlugin mPlugin; - - if (AbstractReaderPlugin.class.isAssignableFrom(pluginClass)) { - mPlugin = factory.createReader(); - } else { - mPlugin = factory.createFilter(); - } - - mPlugin.setClassname(pluginClass.getCanonicalName()); - mPlugin.setName(pluginClass.getSimpleName()); - SelectedMainProjectBean.addConfiguration(plugin, mPlugin); - SelectedMainProjectBean.addPorts(plugin, mPlugin); - - this.mainProject.getPlugins().add(mPlugin); - - } catch (final InstantiationException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_LOAD_PLUGIN, ex); - } catch (final NoSuchMethodException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_LOAD_PLUGIN, ex); - } catch (final SecurityException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_LOAD_PLUGIN, ex); - } catch (final IllegalAccessException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_LOAD_PLUGIN, ex); - } catch (final IllegalArgumentException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_LOAD_PLUGIN, ex); - } catch (final InvocationTargetException ex) { - SelectedMainProjectBean.LOG.warn(SelectedMainProjectBean.ERR_MSG_LOAD_PLUGIN, ex); - } - - } - - /** - * This method removes a given model plugin instance from the current main project. If this is the currently selected plugin from the user, it will be deselected - * as well. This means that this method accesses the <code>SelectedPluginBean</code> directly. - * - * @param plugin - * The project to be removed. - */ - public final void removePlugin(final MIPlugin plugin) { - // TODO Replace with an observer - this.mainProject.getPlugins().remove(plugin); - - // Get the currently selected plugin bean. - final SelectedPluginBean selectedPluginBean = (SelectedPluginBean) FacesContext.getCurrentInstance().getExternalContext() - .getSessionMap().get("selectedPluginBean"); - if (selectedPluginBean != null && selectedPluginBean.getPlugin() == plugin) { - selectedPluginBean.setPlugin((MIPlugin) null); - } - } - - /** - * This method extracts the connections between the filters from the current main project. - * - * @return A list with all connections available. - */ - private List<Connection> getConnectionsFromProject() { - final List<Connection> result = new ArrayList<Connection>(); - - if (this.mainProject != null) { - final EList<MIPlugin> mPlugins = this.mainProject.getPlugins(); - for (final MIPlugin mPlugin : mPlugins) { - final EList<MIOutputPort> mOutputPorts = mPlugin.getOutputPorts(); - for (final MIOutputPort mOutputPort : mOutputPorts) { - final EList<MIInputPort> mInputPorts = mOutputPort.getSubscribers(); - for (final MIInputPort mInputPort : mInputPorts) { - result.add(new Connection(mPlugin, mInputPort.getParent(), mInputPort, mOutputPort)); - } - } - } - } - - return result; - } - - /** - * Delivers the connections (between the filters) within the current main project. - * - * @return A list containing all available connections. - */ - public List<Connection> getConnections() { - return this.connections; - } - - /** - * Delivers the valid connections (between the filters) within the current main project. - * - * @return A list containing all available and valid connections. - */ - public List<Connection> getValidConnections() { - final List<Connection> validConnections = new ArrayList<Connection>(); - final List<Connection> availableConnections = this.getConnections(); - - for (final Connection connection : availableConnections) { - if (connection.isValid()) { - validConnections.add(connection); - } - } - - return validConnections; - } - - /** - * This method adds an empty connection to the current main project. - */ - public void addConnection() { - this.connections.add(new Connection(null, null, null, null)); - } - - /** - * This method "submits" the current connections to the main project (In other words: The connections will be stored within the main project). - */ - public void submitConnections() { - for (final Connection connection : this.connections) { - if (connection.isValid()) { - connection.getOutputPort().getSubscribers().add(connection.getInputPort()); - } - } - } - - /** - * This method returns all available filters of the current main project. In other words: It returns the same as mainProject.getPlugin() but only those which are - * really instances of {@link MIFilter}. - * - * @return A list with all filters of the main project. - */ - public List<MIFilter> getFilters() { - final List<MIFilter> result = new ArrayList<MIFilter>(); - final List<MIPlugin> plugins = this.mainProject.getPlugins(); - - for (final MIPlugin plugin : plugins) { - if (plugin instanceof MIFilter) { - result.add((MIFilter) plugin); - } - } - - return result; - } - - /** - * This method is used to initialize the object after creation. - */ - @PostConstruct - @SuppressWarnings("FinalPrivateMethod") - private final void postConstruct() { - // Register this instance as an observer - this.observableBean.addObserver(this); - } - - /** - * This method is used to finalize the object before destruction. - */ - @PreDestroy - @SuppressWarnings("FinalPrivateMethod") - private final void preDestroy() { - // Unregister this instance as an observer - this.observableBean.deleteObserver(this); - } - - @Override - public void update(final Observable o, final Object arg) { - // If the current main project has just been removed, we have to set the current main project to null. - if (arg instanceof ProjectsBean.MsgProjectRemoved && ((ProjectsBean.MsgProjectRemoved) arg).getProject() == this.mainProject) { - this.setMainProject(null); - } - } - - /** - * This helper class is a wrapper for a project and can be send to the observers as a message that the main project selection just has been changed. It contains - * the newly selected main project. - * - * @author Nils Christian Ehmke - */ - public static final class MsgMainProjectSelection { - /** - * The stored project. - */ - private final MIProject project; - - /** - * Creates a new instance of this class using the given parameters. - * - * @param project - * The project to be stored within this class. - */ - public MsgMainProjectSelection(final MIProject project) { - this.project = project; - } - - /** - * Delivers the stored project within this class. - * - * @return The instance of {@link MIProject}. - */ - public MIProject getProject() { - return this.project; - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedPluginBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedPluginBean.java deleted file mode 100644 index 75a92f88..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedPluginBean.java +++ /dev/null @@ -1,140 +0,0 @@ -/*************************************************************************** - * 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.session; - -import java.util.ArrayList; -import java.util.List; -import java.util.Observable; -import java.util.Observer; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.faces.bean.ManagedBean; -import javax.faces.bean.SessionScoped; -import javax.faces.context.FacesContext; - -import kieker.analysis.model.analysisMetaModel.MIPlugin; - -import org.primefaces.context.RequestContext; - -/** - * This bean can be used to save the currently selected plugin of the user. This bean registers to the user's instance of {@link SelectedMainProjectBean} as an - * observer. If the main project changes, the content of this bean changes as well. This bean also updates the properties form if the selection of the plugin - * changes. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@ManagedBean -@SessionScoped -public final class SelectedPluginBean implements Observer { - - /** - * This is the name of the target element to be updated when the plugin selection changes. - */ - private static final String UPDATE_TARGET = "propertiesForm"; - - /** - * This is the main project bean where this instance registers as an observer. - */ - private final SelectedMainProjectBean observableBean; - - /** - * The plugin which is stored by this container. - */ - private MIPlugin plugin; - - /** - * Creates a new instance of this class. - */ - public SelectedPluginBean() { - // Try to get the main project bean. - final FacesContext context = FacesContext.getCurrentInstance(); - this.observableBean = context.getApplication().evaluateExpressionGet(context, "#{selectedMainProjectBean}", SelectedMainProjectBean.class); - } - - /** - * This method is used to initialize the object after creation. - */ - @PostConstruct - @SuppressWarnings("FinalPrivateMethod") - private final void postConstruct() { - // Register this instance as an observer - this.observableBean.addObserver(this); - } - - /** - * This method is used to finalize the object before destruction. - */ - @PreDestroy - @SuppressWarnings("FinalPrivateMethod") - private final void preDestroy() { - // Unregister this instance as an observer - this.observableBean.deleteObserver(this); - } - - /** - * Delivers the stored plugin. - * - * @return The plugin within this container. - */ - public MIPlugin getPlugin() { - return this.plugin; - } - - /** - * Sets the plugin stored by this bean and updates (if possible) the corresponding element in the current context. - * - * @param plugin - * The new bean to be stored within this bean. - */ - public void setPlugin(final MIPlugin plugin) { - this.plugin = plugin; - - // Update the corresponding components - final RequestContext requestContext = RequestContext.getCurrentInstance(); - requestContext.addPartialUpdateTarget(SelectedPluginBean.UPDATE_TARGET); - } - - /** - * This method delivers a list containing all properties of the current plugin, but adds the name as a string to it. - * - * @return A list with all properties plus the name (as a string). If no plugin is selected, this method returns an empty list, never null. - */ - public List<Object> getAdvancedProperties() { - final List<Object> resultList = new ArrayList<Object>(); - - if (this.plugin != null) { - resultList.add(this.plugin.getName()); - resultList.addAll(this.plugin.getProperties()); - } - - return resultList; - } - - @Override - public void update(final Observable o, final Object arg) { - // If the main project has been newly selected, we have to set the current plugin to null - if (arg instanceof SelectedMainProjectBean.MsgMainProjectSelection) { - this.setPlugin(null); - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedProjectBean.java deleted file mode 100644 index 537a3e18..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/SelectedProjectBean.java +++ /dev/null @@ -1,147 +0,0 @@ -/*************************************************************************** - * 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.session; - -import java.util.Observable; -import java.util.Observer; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.faces.bean.ManagedBean; -import javax.faces.bean.SessionScoped; -import javax.faces.context.FacesContext; - -import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.webgui.beans.application.ProjectsBean; - -import org.primefaces.event.NodeSelectEvent; -import org.primefaces.model.TreeNode; - -/** - * This bean can be used to store the currently selected project and the current main project for the user within a session. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@ManagedBean -@SessionScoped -public class SelectedProjectBean implements Observer { - - /** - * The currently selected node of the current user. - */ - private TreeNode selectedNode; - /** - * The selected project of the current user. - */ - private MIProject selectedProject; - - private final ProjectsBean observableBean; - - /** - * Creates a new instance of this class. - */ - public SelectedProjectBean() { - // Try to get the projects bean. - final FacesContext context = FacesContext.getCurrentInstance(); - this.observableBean = context.getApplication().evaluateExpressionGet(context, "#{projectsBean}", ProjectsBean.class); - } - - /** - * Delivers the project currently selected by the user. It can be null. - * - * @return The user's currently selected project. - */ - public final MIProject getSelectedProject() { - return this.selectedProject; - } - - /** - * Sets the currently selected project within the bean. - * - * @param selectedProject - * The selected project. - */ - public final void setSelectedProject(final MIProject selectedProject) { - this.selectedProject = selectedProject; - } - - /** - * Delivers the currently selected node. - * - * @return The selected node. - */ - public final TreeNode getSelectedNode() { - return this.selectedNode; - } - - /** - * This event should be triggered once a new node is selected to make sure that the newly selected node is stored within this bean. - * - * @param event - * The event that a node has been selected by the user. - */ - public final void onNodeSelect(final NodeSelectEvent event) { - this.setSelectedNode(event.getTreeNode()); - } - - /** - * Sets the currently selected node to a new value. - * - * @param selectedNode - * The selected node. - */ - public final void setSelectedNode(final TreeNode selectedNode) { - this.selectedNode = selectedNode; - if (selectedNode != null && selectedNode.getData() instanceof MIProject) { - this.setSelectedProject((MIProject) selectedNode.getData()); - } else { - this.setSelectedProject(null); - } - } - - /** - * This method is used to initialize the object after creation. - */ - @PostConstruct - @SuppressWarnings("FinalPrivateMethod") - private final void postConstruct() { - // Register this instance as an observer - this.observableBean.addObserver(this); - } - - /** - * This method is used to finalize the object before destruction. - */ - @PreDestroy - @SuppressWarnings("FinalPrivateMethod") - private final void preDestroy() { - // Unregister this instance as an observer - this.observableBean.deleteObserver(this); - } - - @Override - public void update(final Observable o, final Object arg) { - // If the current main project has just been removed, we have to set the current main project to null. - if (arg instanceof ProjectsBean.MsgProjectRemoved && ((ProjectsBean.MsgProjectRemoved) arg).getProject() == this.selectedProject) { - this.setSelectedProject(null); - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/UserBean.java similarity index 53% rename from Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/package-info.java rename to Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/UserBean.java index 41ada39c..91895aad 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/package-info.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/UserBean.java @@ -2,7 +2,7 @@ * Copyright 2012 by * + Christian-Albrechts-University of Kiel * + Department of Computer Science - * + Software Engineering Group + * + Software Engineering Group * and others. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +18,40 @@ * limitations under the License. ***************************************************************************/ +package kieker.webgui.beans.session; + +import javax.faces.bean.ManagedBean; +import javax.faces.bean.SessionScoped; + /** - * This package contains all beans with session scope. + * This bean will later contain the informations about the user of this session (like user name and authorization). For the moment every user will be a guest user. + * + * @author Nils Christian Ehmke + * @version 1.0 */ -package kieker.webgui.beans.session; +@ManagedBean +@SessionScoped +public final class UserBean { + + /** + * This field contains the name of the user. + */ + private final String userName; + + /** + * Creates a new instance of this class. The user name is set to "Guest". + */ + public UserBean() { + this.userName = "Guest"; + } + + /** + * Returns the name of the user of the current session. + * + * @return The user name. + */ + public String getUserName() { + return this.userName; + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Connection.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Connection.java deleted file mode 100644 index 70a9ce18..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Connection.java +++ /dev/null @@ -1,168 +0,0 @@ -/*************************************************************************** - * 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.common; - -import kieker.analysis.model.analysisMetaModel.MIInputPort; -import kieker.analysis.model.analysisMetaModel.MIOutputPort; -import kieker.analysis.model.analysisMetaModel.MIPlugin; - -/** - * This class is a helper class containing a connection between two filters. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -public class Connection { - - /** - * The source filter. - */ - private MIPlugin source; - /** - * The destination filter. - */ - private MIPlugin destination; - /** - * The input port which will be used from the destination. - */ - private MIInputPort inputPort; - /** - * The output port which will be used from the source. - */ - private MIOutputPort outputPort; - - /** - * Creates a new instance of this class using the given parameters. - * - * @param source - * The source filter. - * @param destination - * The destination filter. - * @param inputPort - * The input port which will be used from the destination. - * @param outputPort - * The output port which will be used from the source. - */ - public Connection(final MIPlugin source, final MIPlugin destination, final MIInputPort inputPort, final MIOutputPort outputPort) { - this.source = source; - this.destination = destination; - this.inputPort = inputPort; - this.outputPort = outputPort; - } - - /** - * Delivers the current destination. - * - * @return The destination filter. - */ - public MIPlugin getDestination() { - return this.destination; - } - - /** - * Sets the new destination. - * - * @param destination - * The new destination filter. - */ - public void setDestination(final MIPlugin destination) { - this.destination = destination; - // Make sure that the output port is always valid - if necessary even null. - if (this.destination == null) { - this.outputPort = null; - } - } - - /** - * Delivers the current input port. - * - * @return The input port which will be used from the destination. - */ - public MIInputPort getInputPort() { - return this.inputPort; - } - - /** - * Sets the input port to a new value. - * - * @param inputPort - * The new input port which will be used from the destination. - */ - public void setInputPort(final MIInputPort inputPort) { - this.inputPort = inputPort; - } - - /** - * Delivers the current output port. - * - * @return The output port which will be used from the source. - */ - public MIOutputPort getOutputPort() { - return this.outputPort; - } - - /** - * Sets the new output port. - * - * @param outputPort - * The new output port which will be used from the source. - */ - public void setOutputPort(final MIOutputPort outputPort) { - this.outputPort = outputPort; - } - - /** - * Delivers the source filter. - * - * @return The source filter. - */ - public MIPlugin getSource() { - return this.source; - } - - /** - * Sets the source filter to a new value. - * - * @param source - * The new source filter. - */ - public void setSource(final MIPlugin source) { - this.source = source; - // Make sure that the input port is always valid - if necessary even null. - if (this.source == null) { - this.inputPort = null; - } - } - - /** - * Checks whether the current configuration is valid. The configuration is valid if and only if: All four components are not null, the ports exist and are - * compatible. - * - * @return true if and only if all four components are not null, the ports exist and are compatible. - */ - public boolean isValid() { - if (this.source == null || this.destination == null || this.inputPort == null || this.outputPort == null) { - return false; - } - // TODO: This is currently not necessarily valid - return true; - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java new file mode 100644 index 00000000..47c3f517 --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java @@ -0,0 +1,437 @@ +/*************************************************************************** + * 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.common; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.RoundingMode; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import kieker.analysis.AnalysisController; +import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; +import kieker.analysis.model.analysisMetaModel.MIDependency; +import kieker.analysis.model.analysisMetaModel.MIProject; +import kieker.analysis.model.analysisMetaModel.impl.MAnalysisMetaModelFactory; +import kieker.common.logging.Log; +import kieker.common.logging.LogFactory; +import kieker.webgui.common.exception.LibraryAlreadyExistingException; +import kieker.webgui.common.exception.ProjectAlreadyExistingException; + +import org.primefaces.model.UploadedFile; + +/** + * This is a singleton class for the access to the file system. It makes sure that the necessary directories for the execution of the application exist. <b>Do + * not</b> remove directories created from this manager during runtime! Directories are created during first access to the class.<br> + * This class uses also a fine grained synchronization to handle the access to the projects. + * + * @author Nils Christian Ehmke + */ +public final class FSManager { + + /** + * This is the singleton instance of this class. + */ + private static final FSManager INSTANCE = new FSManager(); + /** + * This is the extension of the KAX-files. + */ + private static final String KAX_EXTENSION = "kax"; + /** + * This is the extension of the library-files. + */ + private static final String LIB_EXTENSION = "jar"; + /** + * This is the name of the directory for the libraries. + */ + private static final String LIB_DIRECTORY = "lib"; + /** + * This is the name of the root-directory. + */ + private static final String ROOT_DIRECTORY = "data"; + /** + * This is the name of the directory for the views. + */ + private static final String VIEW_DIRECTORY = "view"; + /** + * This is the buffer (in bytes) used to copy files. + */ + private static final int BUF_SIZE_BYTES = 1024; + /** + * This is the factory we will use to create the elements for the projects. + */ + private final MIAnalysisMetaModelFactory factory = new MAnalysisMetaModelFactory(); + /** + * This map contains one lock-object for every project (by name). This works at every project name may exist only once. + */ + private final ConcurrentHashMap<String, Object> projectLocksMap = new ConcurrentHashMap<String, Object>(); + /** + * This is the log object used to log messages, warnings etc. + */ + private static final Log LOG = LogFactory.getLog(FSManager.class); + + /** + * Creates a new instance of this class. + */ + private FSManager() { + // Check for our root-directory and create it if necessary + final File rootDir = new File(FSManager.ROOT_DIRECTORY); + if (!rootDir.exists()) { + final boolean result = rootDir.mkdir(); + if (!result) { + FSManager.LOG.error("Could not create root directory."); + } + } + } + + /** + * Delivers the singleton instance of this class. + * + * @return The only instance of {@link FSManager}. + */ + public static FSManager getInstance() { + return FSManager.INSTANCE; + } + + /** + * This method adds a new project to the application. If the method fails due to an {@link IOException}, it will make sure that the project-directories will be + * removed as if the method would never have been called. + * + * @param project + * The project to be added. + * @throws IOException + * If a write-error occurred during the creation. + * @throws ProjectAlreadyExistingException + * If a project with the same name exists already. + */ + public void addProject(final String project) throws IOException, ProjectAlreadyExistingException { + // Get the lock for the new project + final Object lock = this.getLock(project); + + // Assemble the paths to the directory and to the files for the given project + final File projectDir = new File(FSManager.ROOT_DIRECTORY + File.separator + project); + final File projectFile = new File(FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + project + "." + FSManager.KAX_EXTENSION); + final File libDir = new File(FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + FSManager.LIB_DIRECTORY); + final File viewDir = new File(FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + FSManager.VIEW_DIRECTORY); + + // We need an "empty" project in order to save it. + + final MIProject emptyProject = this.factory.createProject(); + + // Create the directories and the empty file atomically + synchronized (lock) { + // Make sure that the project doesn't exist already + if (projectDir.exists()) { + throw new ProjectAlreadyExistingException("The project with the name '" + project + "' exists already."); + } + + // Create the directories + projectDir.mkdir(); + libDir.mkdir(); + viewDir.mkdir(); + + // Now the empty project file + try { + AnalysisController.saveToFile(projectFile, emptyProject); + } catch (final IOException ex) { + // Something went wrong. Remove the directories and files! + viewDir.delete(); + libDir.delete(); + // Keep in mind that the potential remains of the file have to deleted before the directory. + projectFile.delete(); + projectDir.delete(); + + // Rethrow the exception in order to inform the caller of this method + throw ex; + } + } + } + + /** + * This method opens a project atomically, using the current version on the FS. + * + * @param project + * The project to be loaded. + * @return An instance of {@link MIProject} containing all informations from the project. + * @throws IOException + * If something went wrong during opening the file. + */ + public MIProject openProject(final String project) throws IOException { + // Get the lock for the given project + final Object lock = this.getLock(project); + + // Assemble the path to the KAX-file + final File kaxFile = new File(FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + project + "." + FSManager.KAX_EXTENSION); + + // Load it atomically + synchronized (lock) { + return AnalysisController.loadFromFile(kaxFile); + } + } + + /** + * Returns a list containing all available projects on the FS as a string. + * + * @return A list of string containing all available project. + */ + public Collection<? extends String> getAllProjects() { + final List<String> result = new ArrayList<String>(); + + // Get all directories within our root-dir + final File files[] = new File(FSManager.ROOT_DIRECTORY).listFiles(); + for (final File file : files) { + if (file.isDirectory()) { + result.add(file.getName()); + } + } + + return result; + } + + /** + * This method returns the current time stamp of the given project. The time stamp is the last modification time of the KAX-file. + * + * @param project + * The project whose time stamp should be delivered. + * @return The time stamp of the last modification. + */ + public long getCurrTimeStamp(final String project) { + // Assemble the path to the kax-file of the given project + final String fileName = FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + project + "." + FSManager.KAX_EXTENSION; + + // Try to find this file + final File file = new File(fileName); + + // Get the time stamp atomically + final Object lock = this.getLock(project); + + final long ts; + synchronized (lock) { + ts = file.lastModified(); + } + + // Return the time stamp + return ts; + } + + /** + * This method can be used to get the lock for a given project. If the lock doesn't exist already, a new one will be created. + * + * @param project + * The project whose lock should be delivered. + * @return A lock object for the project. + */ + private Object getLock(final String project) { + final Object newLock = new Object(); + final Object existLock = this.projectLocksMap.putIfAbsent(project, newLock); + + return (existLock != null) ? existLock : newLock; + } + + /** + * This method can be used to upload a new library. + * + * @param srcFile + * The file to be used as a new library. + * @param project + * The name of the project for the new lib. + * @return An instance of {@link MIDependency} if everything went well. + * @throws LibraryAlreadyExistingException + * If a library with the same name for the project exists already. + * @throws IOException + * If something went wrong during writing the file. + */ + public MIDependency uploadLibrary(final UploadedFile srcFile, final String project) throws LibraryAlreadyExistingException, IOException { + // Get the lock for this project + final Object lock = this.getLock(project); + + // Prepare the files + final File libDir = new File(FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + FSManager.LIB_DIRECTORY); + final File dstFile = new File(libDir, srcFile.getFileName()); + + // Now copy the file - if it doesn't already exist + synchronized (lock) { + if (dstFile.exists()) { + throw new LibraryAlreadyExistingException("The library with the name '" + srcFile.getFileName() + "' exists already."); + } + + BufferedInputStream in = null; + BufferedOutputStream out = null; + + try { + // Get the streams. + in = new BufferedInputStream(srcFile.getInputstream()); + out = new BufferedOutputStream(new FileOutputStream(dstFile)); + final byte[] buf = new byte[FSManager.BUF_SIZE_BYTES]; + int count; + + // Transfer the file. + while ((count = in.read(buf)) != -1) { + out.write(buf, 0, count); + } + } finally { + // Try to make sure that the streams will be closed. + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } + } + + final MIDependency dependency = this.factory.createDependency(); + dependency.setFilePath(dstFile.getName()); + return dependency; + } + + /** + * This method delivers all available libraries for the given project as a pair of strings. The first element is the name of the library, the second one the size + * of the lib in MiBytes and as a human readable string. + * + * @param projectName + * The name of the project. + * @return The libraries of the given project. + */ + public List<Pair<String, String>> getLibraries(final String projectName) { + final List<Pair<String, String>> result = new ArrayList<Pair<String, String>>(); + // Get the lock for the project + final Object lock = this.getLock(projectName); + + synchronized (lock) { + // Run through the libs and put them into our list. + final File libDir = new File(FSManager.ROOT_DIRECTORY + File.separator + projectName + File.separator + FSManager.LIB_DIRECTORY); + final File files[] = libDir.listFiles(); + if (files != null) { + for (final File file : files) { + if (file.getName().endsWith("." + FSManager.LIB_EXTENSION)) { + final float len = file.length() / 1024.0f / 1024.0f; + final NumberFormat numberFormat = new DecimalFormat("0.00"); + numberFormat.setRoundingMode(RoundingMode.DOWN); + final String lenStr = numberFormat.format(len); + result.add(new Pair<String, String>(file.getName(), lenStr)); + } + } + } + } + + return result; + } + + /** + * This method can be used to deliver the class loader for the given project. The class loader is able to load from all libraries within the given project. + * + * @param projectName + * The name of the project. + * @return An instance of {@link URLClassLoader} with all available libraries. + */ + public ClassLoader getClassLoader(final String projectName) { + // Get the lock for the project + final Object lock = this.getLock(projectName); + final List<URL> libs = new ArrayList<URL>(); + + // Collect all libraries of the project + synchronized (lock) { + // Run through the libs and put them into our list. + final File libDir = new File(FSManager.ROOT_DIRECTORY + File.separator + projectName + File.separator + FSManager.LIB_DIRECTORY); + final File files[] = libDir.listFiles(); + if (files != null) { + for (final File file : files) { + if (file.getName().endsWith("." + FSManager.LIB_EXTENSION)) { + try { + libs.add(file.toURL()); + } catch (final MalformedURLException ex) { + ex.printStackTrace(); + } + } + } + } + + // Now assemble the URL class loader + return AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>() { + @Override + public URLClassLoader run() { + return new URLClassLoader(libs.toArray(new URL[libs.size()]), AnalysisController.class.getClassLoader()); + } + }); + } + } + + /** + * This method can be used to deliver the fully qualified URL of a given dependency for a given project. + * + * @param lib + * The library whose URL should be delivered. + * @param project + * The corresponding project of the library. + * @return The URL to the given library if everything went well. + * @throws MalformedURLException + * If the URL is for some reason invalid. + */ + public URL getURL(final MIDependency lib, final String project) throws MalformedURLException { + final File file = new File(FSManager.ROOT_DIRECTORY + File.separator + project + File.separator + FSManager.LIB_DIRECTORY + File.separator + + lib.getFilePath()); + return file.toURL(); + } + + /** + * This method delivers all available libraries of the given project as a list of {@link MIDependency}. + * + * @param projectName + * The name of the project whose libraries should be delivered. + * @return A list with all available libraries. + */ + public List<MIDependency> getModelLibraries(final String projectName) { + // Get the lock for the project + final Object lock = this.getLock(projectName); + final List<MIDependency> libs = new ArrayList<MIDependency>(); + + // Collect all libraries of the project + synchronized (lock) { + // Run through the libs and put them into our list. + final File libDir = new File(FSManager.ROOT_DIRECTORY + File.separator + projectName + File.separator + FSManager.LIB_DIRECTORY); + final File files[] = libDir.listFiles(); + if (files != null) { + for (final File file : files) { + if (file.getName().endsWith("." + FSManager.LIB_EXTENSION)) { + final MIDependency dep = this.factory.createDependency(); + dep.setFilePath(file.getName()); + libs.add(dep); + } + } + } + return libs; + } + } + +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/FileManager.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/FileManager.java deleted file mode 100644 index eec6d153..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/FileManager.java +++ /dev/null @@ -1,376 +0,0 @@ -/*************************************************************************** - * 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.common; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import javax.faces.application.FacesMessage; -import javax.faces.context.FacesContext; - -import kieker.analysis.AnalysisController; -import kieker.analysis.exception.AnalysisConfigurationException; -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.analysis.model.analysisMetaModel.impl.MAnalysisMetaModelFactory; -import kieker.common.logging.Log; -import kieker.common.logging.LogFactory; - -import org.primefaces.model.UploadedFile; - -/** - * This is a singleton class for the access to the file system. It makes sure that the necessary directories for the execution of the application exist. <b>Do - * not</b> remove directories created from this manager during runtime! Directories are created during first access to the class.<br> - * Currently nearly all methods are synchronized. A fine grained synchronization should be implemented in the future. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -public final class FileManager { - - /** - * The logger within this class. - */ - private static final Log LOG = LogFactory.getLog(FileManager.class); - /** - * The root dir which contains all other directories. - */ - private static final String ROOT_DIR = "data"; - /** - * The directory which contains the projects. - */ - private static final String PROJECT_DIR = FileManager.ROOT_DIR + File.separator + "projects"; - /** - * The directory which contains the libraries. - */ - private static final String LIB_DIR = FileManager.ROOT_DIR + File.separator + "libraries"; - /** - * The extension of the kieker analysis files. - */ - private static final String EXTENSION = ".kax"; - /** - * The extension of jar-files. - */ - private static final String JAR_EXTENSION = ".jar"; - /** - * The buffer size in bytes uses to upload dependencies. - */ - private static final int BUF_SIZE = 1024; - /** - * The singleton instance of this class. - */ - private static final FileManager INSTANCE = new FileManager(); - /** - * The factory used to create new objects of the meta model. - */ - private final MAnalysisMetaModelFactory factory; - - /** - * Creates a new instance of this class. - */ - private FileManager() { - this.checkAndCreateDirectories(); - this.factory = new MAnalysisMetaModelFactory(); - } - - /** - * Checks whether all directories are available and creates them if necessary. - */ - private void checkAndCreateDirectories() { - synchronized (this) { - // Make sure that the directories exist and create them if necessary. - final File dirProj = new File(FileManager.PROJECT_DIR); - final File dirLib = new File(FileManager.LIB_DIR); - boolean couldCreated = true; - - if (!dirProj.exists()) { - couldCreated &= dirProj.mkdirs(); - } - if (!dirLib.exists()) { - couldCreated &= dirLib.mkdirs(); - } - - if (!couldCreated) { - FileManager.LOG.error("Could not create the necessary directories for the application"); - } - } - } - - /** - * This method saves a given project using the name of the project as the project-directory. The project-directory must already exist. - * - * @param project - * The project to be stored. - * @return true iff the project-directory does already exist and the storage was successful. - */ - public final boolean saveProject(final MIProject project) { - synchronized (this) { - final String projectName = project.getName(); - - final File dirProject = new File(FileManager.PROJECT_DIR + File.separator + projectName); - - // Make sure that the directory for the project exists. - if (dirProject.exists()) { - /* - * Try to save the project. - */ - final File fileProject = new File(dirProject, projectName + FileManager.EXTENSION); - try { - final AnalysisController controller = new AnalysisController(project, PluginClassLoader.getInstance()); - try { - controller.saveToFile(fileProject); - FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "", "Project saved: " + project.getName())); - return true; - } catch (final IOException ex) { - FileManager.LOG.error("Could not save project '" + projectName + "'.", ex); - } catch (final AnalysisConfigurationException ex) { - FileManager.LOG.error("Could not save project '" + projectName + "'.", ex); - } - } catch (final AnalysisConfigurationException ex) { - FileManager.LOG.error("Could not save project '" + projectName + "'.", ex); - } catch (final NullPointerException ex) { - FileManager.LOG.error("Could not save project '" + projectName + "'.", ex); - } - } - return false; - } - } - - /** - * This method saves a given project using the name of the project as the project-directory. The project-directory must not already exist. - * - * @param project - * The project to be stored. - * @return true iff the project-directory does not already exist and the storage was successful. - */ - public final boolean saveNewProject(final MIProject project) { - synchronized (this) { - final String projectName = project.getName(); - final File dirProject = new File(FileManager.PROJECT_DIR + File.separator + projectName); - - // Make sure that the project does not already exist and create the project directory. - if (dirProject.exists() || !dirProject.mkdir()) { - return false; - } else { - // The directory should exist now. Store the project. - return this.saveProject(project); - } - } - } - - /** - * This method can be used to load all currently saved projects. - * - * @return A list containing the loaded projects. If something went wrong, an empty list will be returned, never null. - */ - public final List<MIProject> loadAllProjects() { - final List<MIProject> resultList = new ArrayList<MIProject>(); - synchronized (this) { - // Try to get all directories within the project directory. - final File[] directories = new File(FileManager.PROJECT_DIR).listFiles(); - if (directories != null) { - for (final File directory : directories) { - if (directory.isDirectory()) { - // If there is a project file within the directory, we know the name of it. - final File projectFile = new File(directory, directory.getName() + FileManager.EXTENSION); - if (projectFile.exists()) { - // Try to load the project. - MIProject project; - try { - project = AnalysisController.loadFromFile(projectFile); - resultList.add(project); - } catch (final IOException ex) { - FileManager.LOG.error("Could not load project.", ex); - } - } - } - } - } - } - return resultList; - } - - /** - * This method uploads a given file as a new dependency. The file is stored within the lib-directory of this application. If a file with the same name does - * already exist, it will be replaces. - * - * @param file - * The file to be uploaded. - * @return The new dependency iff the uploading was successful, null otherwise. - */ - public final MIDependency uploadDependency(final UploadedFile file) { - synchronized (this) { - final File depFile = new File(FileManager.LIB_DIR, file.getFileName()); - - BufferedInputStream in = null; - BufferedOutputStream out = null; - try { - // Get the streams. - in = new BufferedInputStream(file.getInputstream()); - out = new BufferedOutputStream(new FileOutputStream(depFile)); - final byte[] buf = new byte[FileManager.BUF_SIZE]; - int count; - - // Transfer the file. - while ((count = in.read(buf)) != -1) { - out.write(buf, 0, count); - } - - } catch (final IOException ex) { - FileManager.LOG.error("Could not transfer file '" + file.getFileName() + "'"); - return null; - } finally { - // Try to make sure that the streams will be closed. - try { - if (in != null) { - in.close(); - } - } catch (final IOException ex) { - FileManager.LOG.warn("Error while uploading dependency '" + file.getFileName() + "'."); - } - try { - if (out != null) { - out.close(); - } - } catch (final IOException ex) { - FileManager.LOG.warn("Error while uploading dependency '" + file.getFileName() + "'."); - } - } - final MIDependency dependency = this.factory.createDependency(); - dependency.setFilePath(depFile.getName()); - return dependency; - } - } - - /** - * Delivers the only instance of this class. - * - * @return The singleton instance of this class. - */ - public static final synchronized FileManager getInstance() { - return FileManager.INSTANCE; - } - - /** - * This method tries to load all available dependencies from the file system. - * - * @return A list containing all available dependencies. If there are no files, an empty list will be returned. - */ - public final List<MIDependency> loadAllDependencies() { - final List<MIDependency> resultList = new ArrayList<MIDependency>(); - synchronized (this) { - // Try to get all files within the library directory. - final File[] files = new File(FileManager.LIB_DIR).listFiles(); - if (files != null) { - for (final File file : files) { - if (file.isFile() && file.getName().endsWith(FileManager.JAR_EXTENSION)) { - final MIDependency dependency = this.factory.createDependency(); - dependency.setFilePath(file.getName()); - resultList.add(dependency); - } - } - } - } - return resultList; - } - - /** - * Tries to delete a given dependency. - * - * @param dependency - * The dependency to be removed. - * @return true iff the dependency exists and the removal was successful. - */ - public final boolean deleteDependency(final MIDependency dependency) { - synchronized (this) { - final File file = new File(FileManager.LIB_DIR, dependency.getFilePath()); - if (file.isFile()) { - return file.delete(); - } - return false; - } - } - - /** - * This method tries to delete a project, by removing the directory of the project and its contents. If something went wrong, the integrity of the folder - * structure is not guaranteed. - * - * @param project - * The project to be removed. - * @return true iff the project has been removed successfully. - */ - public final boolean deleteProject(final MIProject project) { - final String projectName = project.getName(); - - final File dirProject = new File(FileManager.PROJECT_DIR + File.separator + projectName); - synchronized (this) { - if (dirProject.isDirectory()) { - final File[] files = dirProject.listFiles(); - for (final File file : files) { - if (!file.delete()) { - return false; - } - } - return dirProject.delete(); - } - return false; - } - } - - /** - * This method reloads the given project from the file system. - * - * @param project - * The project to be reloaded. - * @return The reloaded project. - */ - public MIProject reloadProject(final MIProject project) { - final String projectName = project.getName(); - - final File projectFile = new File(FileManager.PROJECT_DIR + File.separator + projectName + File.separator + projectName + FileManager.EXTENSION); - synchronized (this) { - if (projectFile.isFile()) { - try { - return AnalysisController.loadFromFile(projectFile); - } catch (final IOException ex) { - FileManager.LOG.error("Could not load project.", ex); - } - } - } - return null; - } - - /** - * This method can be used to deliver the correct and full path to a given library. This is necessary as only the name of the dependencies is stored within the - * model dependency. It is not guaranteed that the given path points to an existing file though. - * - * @param dependency - * The dependency which will be used to assemble the path. - * @return An absolute path to the given dependency. - */ - public String getFullPath(final MIDependency dependency) { - return new File(FileManager.LIB_DIR, dependency.getFilePath()).getAbsolutePath(); - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/LRUCache.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/LRUCache.java deleted file mode 100644 index 0100d475..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/LRUCache.java +++ /dev/null @@ -1,110 +0,0 @@ -/*************************************************************************** - * 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.common; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map.Entry; - -/** - * This is a thread-safe cache, which can be used to cache objects under a specific key. This class is a LRU cache. - * - * @author Nils Christian Ehmke - * - * @param <Key> - * The type for the keys. - * @param <Value> - * The type for the values. - */ -public class LRUCache<Key, Value> { - - /** - * This is the map which is used to store the entries. - */ - private final HashMap<Key, Value> hashMap; - private final int maxSize; - - /** - * Creates a new instance of this class using the given size as maximal cache size. - * - * @param size - * The maximal cache size. - */ - public LRUCache(final int size) { - this.maxSize = size; - this.hashMap = new FixedLinkedHashMap(); - } - - /** - * This method adds a given value within the cache, using the given key. If a value with the same key does already exist, it will be replaced. If the entry would - * excess the maximal cache size, the oldest entry will be removed. - * - * @param key - * The key used to store the value. - * @param value - * The value to be stored. - */ - public void add(final Key key, final Value value) { - synchronized (this.hashMap) { - this.hashMap.put(key, value); - } - } - - /** - * This method delivers the value to the key or null, if the value doesn't exist. - * - * @param key - * The key to the value. - * @return The corresponding value. - */ - public Value get(final Key key) { - synchronized (this.hashMap) { - return this.hashMap.get(key); - } - } - - /** - * A modified version of {@link LinkedHashMap} which has a fixed size. Each time the {@code put} or {@code putAll} method exceeds the size of the - * {@link LRUCache}, the oldest entry is being removed. - * - * @author Nils Christian Ehmke - */ - private class FixedLinkedHashMap extends LinkedHashMap<Key, Value> { - - /** - * The serial version uid. - */ - private static final long serialVersionUID = 1L; - - /** - * Creates a new instance of this class, using the LRUCache's maximal size as the size of the map. - */ - public FixedLinkedHashMap() { - super(LRUCache.this.maxSize); - } - - @Override - protected boolean removeEldestEntry(final Entry<Key, Value> eldest) { - return this.size() > LRUCache.this.maxSize; - } - - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Pair.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Pair.java new file mode 100644 index 00000000..23aebdd2 --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Pair.java @@ -0,0 +1,103 @@ +/*************************************************************************** + * 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.common; + +/** + * This is a simple helper class which can store two values. + * + * @author Nils Christian Ehmke + * @version 1.0 + * + * @param <FST> + * The type of the first element. + * @param <SND> + * The type of the second element. + */ +public class Pair<FST, SND> { + + /** + * This is the first element. + */ + private FST fst; + /** + * This is the second element. + */ + private SND snd; + + /** + * Creates a new instance of this class with null values stored for the elements. + */ + public Pair() { + // No code necessary + } + + /** + * Creates a new instance of this class using the given values. + * + * @param fst + * The first element to be stored in this object. + * @param snd + * The second element to be stored in this object. + */ + public Pair(final FST fst, final SND snd) { + this.fst = fst; + this.snd = snd; + } + + /** + * Delivers the first element. + * + * @return The first element. + */ + public FST getFst() { + return this.fst; + } + + /** + * Sets the first element to a new value. + * + * @param fst + * The new first element. + */ + public void setFst(final FST fst) { + this.fst = fst; + } + + /** + * Delivers the second element. + * + * @return The second element. + */ + public SND getSnd() { + return this.snd; + } + + /** + * Sets the second element to a new value. + * + * @param snd + * The new second element. + */ + public void setSnd(final SND snd) { + this.snd = snd; + } + +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginClassLoader.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginClassLoader.java deleted file mode 100644 index 1a3dd57a..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginClassLoader.java +++ /dev/null @@ -1,143 +0,0 @@ -/*************************************************************************** - * 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.common; - -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.List; - -import kieker.analysis.AnalysisController; -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.common.logging.Log; -import kieker.common.logging.LogFactory; - -/** - * This singleton class is responsible for the dynamic loading of classes. Unlike a normal <code>URLClassLoader</code> it is possible to dynamically add and remove - * urls from the class loader. This instance should always be used if plugin objects have to be created. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -public final class PluginClassLoader extends ClassLoader { - - /** - * The logger within this class. - */ - private static final Log LOG = LogFactory.getLog(PluginClassLoader.class); - /** - * The singleton instance of this class. - */ - private static PluginClassLoader instance; - - private final List<URL> urlList = new ArrayList<URL>(); - - private URLClassLoader classLoader = null; - - /** - * The default constructor of this class. During the creation all available libraries will be added to the class loader. - */ - private PluginClassLoader() { - this.classLoader = new URLClassLoader(new URL[] {}, AnalysisController.class.getClassLoader()); - // Make sure that all libs are loaded. - final List<MIDependency> libs = FileManager.getInstance().loadAllDependencies(); - for (final MIDependency lib : libs) { - try { - this.addURL(new URL("file", "localhost", FileManager.getInstance().getFullPath(lib))); - } catch (final MalformedURLException ex) { - PluginClassLoader.LOG.warn("Could not load library.", ex); - } - } - } - - /** - * This method can be used to add an url to the class loader. - * - * @param url - * The URL of the dependency to be added. - */ - public void addURL(final URL url) { - this.urlList.add(url); - - this.classLoader = (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction<Object>() { - @Override - public Object run() { - return new URLClassLoader(PluginClassLoader.this.urlList.toArray(new URL[PluginClassLoader.this.urlList.size()]), AnalysisController.class - .getClassLoader()); - } - }); - } - - /** - * This method can be used to remove an url from the class loader. - * - * @param url - * The URL of the dependency to be added. - */ - public void removeURL(final URL url) { - this.urlList.remove(url); - - this.classLoader = (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction<Object>() { - @Override - public Object run() { - return new URLClassLoader(PluginClassLoader.this.urlList.toArray(new URL[PluginClassLoader.this.urlList.size()]), AnalysisController.class - .getClassLoader()); - } - }); - } - - /** - * Delivers the only instance of this class. - * - * @return The singleton instance of this class. - */ - public static final PluginClassLoader getInstance() { - // Create the singleton instance if necessary and use a doPrivileged-block. - synchronized (PluginClassLoader.class) { - if (PluginClassLoader.instance == null) { - PluginClassLoader.instance = (PluginClassLoader) AccessController.doPrivileged(new PrivilegedAction<Object>() { - @Override - public Object run() { - return new PluginClassLoader(); - } - }); - } - } - return PluginClassLoader.instance; - } - - /** - * This method tries to load the class with the given name using the currently loaded dependencies. - * - * @param name - * The name of the class to be loaded. - * @return The class. - * @throws ClassNotFoundException - * If a class with the given name could not be found. - */ - @Override - public Class<?> loadClass(final String name) throws ClassNotFoundException { - return this.classLoader.loadClass(name); - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java index c0f67511..6e04c94f 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java @@ -31,24 +31,16 @@ import java.util.jar.JarFile; import kieker.analysis.plugin.AbstractPlugin; import kieker.analysis.plugin.annotation.Plugin; import kieker.analysis.repository.AbstractRepository; +import kieker.analysis.repository.annotation.Repository; /** - * This tool class can be used to find all plugins and repositories within a given jar file - assuming that the <code>PluginClassLoader</code> knows these jars. + * This tool class can be used to find all plugins and repositories within a given jar file - assuming that the given class loader knows these jars. * * @author Nils Christian Ehmke * @version 1.0 - * TODO Cache and observer update! */ public final class PluginFinder { - private static final LRUCache<URL, List<Class<AbstractPlugin>>> PLUGIN_CACHE; - private static final LRUCache<URL, List<Class<AbstractRepository>>> REPOSITORY_CACHE; - - static { - PLUGIN_CACHE = new LRUCache<URL, List<Class<AbstractPlugin>>>(15); - REPOSITORY_CACHE = new LRUCache<URL, List<Class<AbstractRepository>>>(15); - } - /** * Creates a new instance of this class. */ @@ -61,42 +53,24 @@ public final class PluginFinder { * * @param url * The url for the jar. + * @param classLoader + * The class loader used to load the classes. * @return A list containing all available repository-classes or null, if an exception occurred. */ - public static List<Class<AbstractRepository>> getAllRepositoriesWithinJar(final URL url) { - // TODO: Merge this with the other method - final List<Class<AbstractRepository>> repositoryClasses = PluginFinder.REPOSITORY_CACHE.get(url); - if (repositoryClasses != null) { - return repositoryClasses; - } - try { - // Open the jar file and run through all entries within this file. - final JarFile jarFile = new JarFile(new File(url.getPath())); - final List<Class<AbstractRepository>> result = new ArrayList<Class<AbstractRepository>>(); - final Enumeration<JarEntry> jarEntries = jarFile.entries(); - while (jarEntries.hasMoreElements()) { - final JarEntry jarEntry = jarEntries.nextElement(); - try { - String name = jarEntry.toString(); - name = name.replace('/', '.'); - name = name.replace(".class", ""); - // Try to find a class with the same name. - final Class<?> c = PluginClassLoader.getInstance().loadClass(name); + public static List<Class<AbstractRepository>> getAllRepositoriesWithinJar(final URL url, final ClassLoader classLoader) { + final List<Class<?>> clazzes = PluginFinder.getAllClassesWithinJar(url, classLoader); + List<Class<AbstractRepository>> result = null; - if (AbstractRepository.class.isAssignableFrom(c)) { - result.add((Class<AbstractRepository>) c); - } - } catch (final Throwable ex) { // NOCS (IllegalCatchCheck) - // Ignore error. + if (clazzes != null) { + result = new ArrayList<Class<AbstractRepository>>(); + for (final Class<?> clazz : clazzes) { + if (clazz.isAnnotationPresent(Repository.class) && AbstractRepository.class.isAssignableFrom(clazz)) { + result.add((Class<AbstractRepository>) clazz); } } - jarFile.close(); - PluginFinder.REPOSITORY_CACHE.add(url, result); - return result; - } catch (final IOException ex) { - ex.printStackTrace(); } - return null; + + return result; } /** @@ -105,36 +79,57 @@ public final class PluginFinder { * * @param url * The url for the jar. + * @param classLoader + * The class loader used to load the classes. * @return A list containing all available plugin-classes or null, if an exception occurred. */ - public static List<Class<AbstractPlugin>> getAllPluginsWithinJar(final URL url) { - final List<Class<AbstractPlugin>> pluginClasses = PluginFinder.PLUGIN_CACHE.get(url); - if (pluginClasses != null) { - return pluginClasses; + public static List<Class<AbstractPlugin>> getAllPluginsWithinJar(final URL url, final ClassLoader classLoader) { + final List<Class<?>> clazzes = PluginFinder.getAllClassesWithinJar(url, classLoader); + List<Class<AbstractPlugin>> result = null; + + if (clazzes != null) { + result = new ArrayList<Class<AbstractPlugin>>(); + for (final Class<?> clazz : clazzes) { + if (clazz.isAnnotationPresent(Plugin.class) && AbstractPlugin.class.isAssignableFrom(clazz)) { + result.add((Class<AbstractPlugin>) clazz); + } + } } + + return result; + } + + /** + * This method delivers all classes which are available in the given jar. + * + * @param url + * The url for the jar. + * @param classLoader + * The class loader used to load the classes. + * @return A list containing all available classes or null, if an exception occurred. + */ + private static List<Class<?>> getAllClassesWithinJar(final URL url, final ClassLoader classLoader) { try { // Open the jar file and run through all entries within this file. final JarFile jarFile = new JarFile(new File(url.getPath())); - final List<Class<AbstractPlugin>> result = new ArrayList<Class<AbstractPlugin>>(); + final List<Class<?>> result = new ArrayList<Class<?>>(); final Enumeration<JarEntry> jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { final JarEntry jarEntry = jarEntries.nextElement(); try { + // Assemble the correct name String name = jarEntry.toString(); name = name.replace('/', '.'); name = name.replace(".class", ""); - // Try to find a class with the same name. - final Class<?> c = PluginClassLoader.getInstance().loadClass(name); - // If it is a class and has the annotation - put it into our list. - if (c.isAnnotationPresent(Plugin.class) && AbstractPlugin.class.isAssignableFrom(c)) { - result.add((Class<AbstractPlugin>) c); - } + // Try to find a class with the same name and put it into our list + final Class<?> c = classLoader.loadClass(name); + result.add(c); } catch (final Throwable ex) { // NOCS (IllegalCatchCheck) // Ignore error. } } + // Don't forget to close the jar file again. jarFile.close(); - PluginFinder.PLUGIN_CACHE.add(url, result); return result; } catch (final IOException ex) { ex.printStackTrace(); diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/StringToIDBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/LibraryAlreadyExistingException.java similarity index 60% rename from Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/StringToIDBean.java rename to Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/LibraryAlreadyExistingException.java index 78b84789..0c9ba7a1 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/request/StringToIDBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/LibraryAlreadyExistingException.java @@ -18,36 +18,32 @@ * limitations under the License. ***************************************************************************/ -package kieker.webgui.beans.request; - -import javax.faces.bean.ManagedBean; -import javax.faces.bean.RequestScoped; +package kieker.webgui.common.exception; /** - * This is a simple helper bean which can be used to rewrite a given string as an ID. + * This exception shows that a library with the same name exists already. * * @author Nils Christian Ehmke * @version 1.0 */ -@ManagedBean -@RequestScoped -public class StringToIDBean { +public class LibraryAlreadyExistingException extends Exception { + + private static final long serialVersionUID = 1L; /** * Creates a new instance of this class. */ - public StringToIDBean() { - // No code necessary. + public LibraryAlreadyExistingException() { + // No code necessary } /** - * Modified the given string so that it can be used as an ID. In other words: It removes all space characters. + * Creates a new instance of this class using the given parameters. * - * @param string - * The string to be modified. - * @return The given string without space characters. + * @param msg + * The message used for the exception. */ - public String stringToID(final String string) { - return string.replace(" ", "").replace("$", "").replace("@", ""); + public LibraryAlreadyExistingException(final String msg) { + super(msg); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/ProjectAlreadyExistingException.java similarity index 63% rename from Kieker.WebGUI/src/main/java/kieker/webgui/converter/package-info.java rename to Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/ProjectAlreadyExistingException.java index cde21594..09fe5242 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/package-info.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/ProjectAlreadyExistingException.java @@ -18,8 +18,26 @@ * limitations under the License. ***************************************************************************/ -/** - * This package contains all converters used within the project. - */ -package kieker.webgui.converter; +package kieker.webgui.common.exception; +public class ProjectAlreadyExistingException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Creates a new instance of this class. + */ + public ProjectAlreadyExistingException() { + // No code necessary + } + + /** + * Creates a new instance of this class using the given parameters. + * + * @param msg + * The message used for the exception. + */ + public ProjectAlreadyExistingException(final String msg) { + super(msg); + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/package-info.java deleted file mode 100644 index a28a880a..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * 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. - ***************************************************************************/ - -/** - * This package contains all classes with general and common purpose. - */ -package kieker.webgui.common; - diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/ClassToStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/ClassToStringConverter.java deleted file mode 100644 index 64b5acb0..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/ClassToStringConverter.java +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************** - * 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.converter; - -import java.util.HashMap; -import java.util.Map; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.convert.Converter; -import javax.faces.convert.FacesConverter; - -/** - * This converter can be used to convert a class to a string and vice versa. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@FacesConverter(value = ClassToStringConverter.NAME) -public class ClassToStringConverter implements Converter { - - /** - * The name of this class used by the xhtml-files. - */ - public static final String NAME = "kieker.webgui.converter.ClassToStringConverter"; - - /** - * This field stores the mapping between the classes as string and the actual classes. - */ - private final Map<String, Class<?>> mapping; - - /** - * Creates a new instance of this class. - */ - public ClassToStringConverter() { - this.mapping = new HashMap<String, Class<?>>(); - } - - @Override - public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) { - return this.mapping.get(string); - } - - @Override - public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { - final String result = ((Class<?>) o).getName(); - this.mapping.put(result, (Class<?>) o); - return result; - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToCountPluginsConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToCountPluginsConverter.java deleted file mode 100644 index b7ced166..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToCountPluginsConverter.java +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************** - * 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.converter; - -import java.net.MalformedURLException; -import java.net.URL; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.convert.Converter; -import javax.faces.convert.FacesConverter; - -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.webgui.common.FileManager; -import kieker.webgui.common.LRUCache; -import kieker.webgui.common.PluginFinder; - -/** - * This converter can be used to convert an instance of <i>MIDependency</i> to the number of plugins within the dependency, but of course <b>not</b> vice versa. The - * number is cached to avoid that the converter holds the file permanently. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@FacesConverter(value = MIDependencyToCountPluginsConverter.NAME) -public class MIDependencyToCountPluginsConverter implements Converter { - - /** - * The name of this class used by the xhtml-files. - */ - public static final String NAME = "kieker.webgui.converter.MIDependencyToCountPluginsConverter"; - - /** - * The maximal number of dependencies stored within the cache. - */ - private static final int MAX_CACHE_SIZE = 20; - - /** - * This map is the cache and contains the number of plugins within the - * dependencies. - */ - private final LRUCache<MIDependency, String> cache; - - /** - * Creates a new instance of this class. - */ - public MIDependencyToCountPluginsConverter() { - this.cache = new LRUCache<MIDependency, String>(MIDependencyToCountPluginsConverter.MAX_CACHE_SIZE); - } - - /** - * Delivers always null. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is - * associated. - * @param string - * The string to be converted. - * @return Always null. - */ - @Override - public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) { - return null; - } - - /** - * Converts the given dependency to a human readable string - * containing the number of plugins within the jar. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is - * associated. - * @param o - * The object to be converted. - * @return The number of plugins within the jar. If this is - * not possible, an empty string will be returned. - */ - @Override - public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { - if (!(o instanceof MIDependency)) { - return ""; - } else { - final MIDependency dependency = (MIDependency) o; - // Try to find the string within the cache. - String result = this.cache.get(dependency); - if (result == null) { - // We have to create the string first - try { - result = Integer.toString(PluginFinder.getAllPluginsWithinJar(new URL("file", "localhost", FileManager.getInstance().getFullPath(dependency))) - .size()); - // Remember it for the next time - this.cache.add(dependency, result); - } catch (final MalformedURLException e) { - result = ""; - } - } - - return result; - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToSizeConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToSizeConverter.java deleted file mode 100644 index 2d353264..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToSizeConverter.java +++ /dev/null @@ -1,96 +0,0 @@ -/*************************************************************************** - * 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.converter; - -import java.io.File; -import java.text.DecimalFormat; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.convert.Converter; -import javax.faces.convert.FacesConverter; - -import kieker.analysis.model.analysisMetaModel.MIDependency; -import kieker.webgui.common.FileManager; - -/** - * This converter can be used to convert an instance of <i>MIDependency</i> to - * the size (in MiBByte) of the dependency, but of course <b>not</b> vice versa. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@FacesConverter(value = MIDependencyToSizeConverter.NAME) -public class MIDependencyToSizeConverter implements Converter { - /** - * The name of this class used by the xhtml-files. - */ - public static final String NAME = "kieker.webgui.converter.MIDependencyToSizeConverter"; - /** - * The factor used to convert the size into MiBytes. - */ - private static final double FACTOR = 1.0 / 1024 / 1024; // NOCS (MagicNumberCheck) - - /** - * Creates a new instance of this class. - */ - public MIDependencyToSizeConverter() { - /* No code necessary. */ - } - - /** - * Delivers always null. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is - * associated. - * @param string - * The string to be converted. - * @return Always null. - */ - @Override - public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) { - return null; - } - - /** - * Delivers a string-representation of the size of the given dependency. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is - * associated. - * @param o - * The object to be converted. - * @return The size of the given object if it is a dependency and not null, an empty string otherwise. - */ - @Override - public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { - if (!(o instanceof MIDependency)) { - return ""; - } else { - final long size = new File(FileManager.getInstance().getFullPath((MIDependency) o)).length(); - return new DecimalFormat("#.##").format(size * MIDependencyToSizeConverter.FACTOR).concat(" [MiByte]"); - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToStringConverter.java deleted file mode 100644 index 004e0185..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIDependencyToStringConverter.java +++ /dev/null @@ -1,99 +0,0 @@ -/*************************************************************************** - * 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.converter; - -import java.io.File; -import java.util.concurrent.ConcurrentHashMap; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.convert.Converter; -import javax.faces.convert.FacesConverter; - -import kieker.analysis.model.analysisMetaModel.MIDependency; - -/** - * This converter can be used to convert an instance of <i>MIDependency</i> to a human readable string and also vice versa. This implies that the names of the - * libraries (as those are shown as human readable strings) have to be unique. Otherwise the string cannot be mapped to the corresponding object. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@FacesConverter(value = MIDependencyToStringConverter.NAME) -public class MIDependencyToStringConverter implements Converter { - - /** - * This is the name of the converter. - */ - public static final String NAME = "kieker.webgui.converter.MIDependencyToStringConverter"; - /** - * This map is being used to store the already shown dependencies. - */ - private static final ConcurrentHashMap<String, MIDependency> MAP = new ConcurrentHashMap<String, MIDependency>(); - - /** - * Creates a new instance of this class. - */ - public MIDependencyToStringConverter() { - /* - * No code necessary. - */ - } - - /** - * This method delivers always null and should not be used. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is associated. - * @param string - * The string to be converted. - * @return null; - */ - @Override - public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) { - return MIDependencyToStringConverter.MAP.get(string); - } - - /** - * This method converts the given object (on condition that it is an instance of the class <code>MIDependency</code>) to a human readable string. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is associated. - * @param o - * The object to be converted. - * @return A human readable represantation of the given object or null, of the object is from the wrong class. - */ - @Override - public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { - // Make sure that the given object is well-defined. - if (!(o instanceof MIDependency)) { - return ""; - } else { - final String result = new File(((MIDependency) o).getFilePath()).getName(); - MIDependencyToStringConverter.MAP.put(result, (MIDependency) o); - return result; - } - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginToStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginToStringConverter.java deleted file mode 100644 index 9a3d538d..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginToStringConverter.java +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************** - * 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.converter; - -import java.util.concurrent.ConcurrentHashMap; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.convert.Converter; -import javax.faces.convert.FacesConverter; - -import kieker.analysis.model.analysisMetaModel.MIPlugin; - -/** - * This converter can be used to convert a given plugin model instance to a string and vice versa (It uses the object'S toString-method). - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@FacesConverter(value = MIPluginToStringConverter.NAME) -public class MIPluginToStringConverter implements Converter { - /** - * This is the name of this converter. - */ - public static final String NAME = "kieker.webgui.converter.MIPluginToStringConverter"; - /** - * This field stores the mapping. - */ - private static ConcurrentHashMap<String, MIPlugin> map = new ConcurrentHashMap<String, MIPlugin>(); - - /** - * Creates a new instance of this class. - */ - public MIPluginToStringConverter() { - /* No code necessary. */ - } - - @Override - public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) { - return MIPluginToStringConverter.map.get(string); - } - - @Override - public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { - final String result = o.toString(); - MIPluginToStringConverter.map.put(result, (MIPlugin) o); - return result; - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortToStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortToStringConverter.java deleted file mode 100644 index f35f82e9..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortToStringConverter.java +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************** - * 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.converter; - -import java.util.concurrent.ConcurrentHashMap; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.convert.Converter; -import javax.faces.convert.FacesConverter; - -import kieker.analysis.model.analysisMetaModel.MIPort; - -/** - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@FacesConverter(value = MIPortToStringConverter.NAME) -public class MIPortToStringConverter implements Converter { - /** - * This is the name of this converter. - */ - public static final String NAME = "kieker.webgui.converter.MIPortToStringConverter"; - /** - * This field stores the mapping. - */ - private static ConcurrentHashMap<String, MIPort> map = new ConcurrentHashMap<String, MIPort>(); - - /** - * Creates a new instance of this class. - */ - public MIPortToStringConverter() { - /* No code necessary. */ - } - - @Override - public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) { - return MIPortToStringConverter.map.get(string); - } - - @Override - public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { - final String result = o.toString(); - MIPortToStringConverter.map.put(result, (MIPort) o); - return result; - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIProjectToStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIProjectToStringConverter.java deleted file mode 100644 index 8b98d93c..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIProjectToStringConverter.java +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************** - * 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.converter; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; -import javax.faces.convert.Converter; -import javax.faces.convert.FacesConverter; - -import kieker.analysis.model.analysisMetaModel.MIProject; - -/** - * This converter can be used to convert an instance of <i>MIProject</i> to a human readable string, but <b>not</b> vice versa. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -@FacesConverter(value = MIProjectToStringConverter.NAME) -public class MIProjectToStringConverter implements Converter { - - /** - * This is the name of this converter. - */ - public static final String NAME = "kieker.webgui.converter.MIProjectToStringConverter"; - - /** - * Creates a new instance of this class. - */ - public MIProjectToStringConverter() { - /* No code necessary. */ - } - - /** - * This method delivers always null and should not be used. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is - * associated. - * @param string - * The string to be converted. - * @return null - */ - @Override - public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) { - return null; - } - - /** - * This method delivers the name of the given object, if the object is not - * null and the object is an instance of the class <code>MIProject</code>. - * - * @param fc - * The FacesContext for the request being processed. - * @param uic - * The component with which this model object value is - * associated. - * @param o - * The object to be converted. - * @return A human readable representation of the given object if possible, - * null otherwise. - */ - @Override - public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { - // Make sure that the given object is well-defined. - if (!(o instanceof MIProject)) { - return ""; - } else { - return ((MIProject) o).getName(); - } - } -} diff --git a/Kieker.WebGUI/src/main/webapp/AnalysisCockpit.xhtml b/Kieker.WebGUI/src/main/webapp/AnalysisCockpit.xhtml new file mode 100644 index 00000000..8acf4b47 --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/AnalysisCockpit.xhtml @@ -0,0 +1,64 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + <h:head> + <title>Kieker.WebGUI</title> + <link rel="stylesheet" type="text/css" href="../css/Common.css" /> + <link rel="stylesheet" type="text/css" href="../css/AnalysisCockpit.css" /> + </h:head> + + <h:body> + + <!-- This is the layout for the whole page. --> + <p:layout id="layout" fullPage="true"> + + <p:layoutUnit position="north" collapsible="false" header="Kieker.WebGUI"> + <h:form> + <p:menubar> + <p:submenu label="File"> + <p:menuitem value="Close Cockpit" action="#{currentAnalysisCockpitProjectBean.clearProject()}" ajax="false"/> + <p:separator/> + <p:menuitem value="Settings" onclick="settingsDialog.show()" ajax="true"/> + </p:submenu> + + <p:submenu label="Help"> + <p:menuitem value="User Guide" ajax="true"/> + <p:separator/> + <p:menuitem value="About..." onclick="aboutDialog.show()" ajax="true"/> + </p:submenu> + + <p:menuitem styleClass="logOutButton" disabled="true" value="#{userBean.userName} [Log Out]" ajax="true"/> + </p:menubar> + + </h:form> + </p:layoutUnit> + + + <p:layoutUnit position="center" id="centerLayout"> + </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> + </h:form> + </p:layoutUnit> + </p:layout> + + <p:growl id="messages" life="1500" showDetail="true" autoUpdate="false" sticky="false"/> + + <!-- Include the dialog for the configuration. --> + <ui:include src="dialogs/settingsDialog.xhtml" /> + + <!-- Include the about-dialog. --> + <ui:include src="dialogs/aboutDialog.xhtml" /> + + </h:body> +</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/AnalysisController.xhtml b/Kieker.WebGUI/src/main/webapp/AnalysisController.xhtml new file mode 100644 index 00000000..204287fa --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/AnalysisController.xhtml @@ -0,0 +1,79 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + <h:head> + <title>Kieker.WebGUI</title> + <link rel="stylesheet" type="text/css" href="../css/Common.css" /> + <link rel="stylesheet" type="text/css" href="../css/AnalysisController.css" /> + </h:head> + + <h:body> + + <!-- This is the layout for the whole page. --> + <p:layout id="layout" fullPage="true"> + + <p:layoutUnit position="north" collapsible="false" header="Kieker.WebGUI"> + <h:form> + <p:menubar> + <p:submenu label="File"> + <p:menuitem value="Close Controller" action="#{currentAnalysisControllerProjectBean.clearProject()}" ajax="false"/> + <p:separator/> + <p:menuitem value="Settings" onclick="settingsDialog.show()" ajax="true"/> + </p:submenu> + + <p:submenu label="Help"> + <p:menuitem value="User Guide" ajax="true"/> + <p:separator/> + <p:menuitem value="About..." onclick="aboutDialog.show()" ajax="true"/> + </p:submenu> + + <p:menuitem styleClass="logOutButton" disabled="true" value="#{userBean.userName} [Log Out]" ajax="true"/> + </p:menubar> + + </h:form> + </p:layoutUnit> + + + <p:layoutUnit position="center" id="centerLayout"> + </p:layoutUnit> + + <p:layoutUnit position="south" header="Control" resizable="true" collapsible="true"> + <h:form> + <p:commandButton value="Instantiate Analysis Controller" disabled="#{empty currentAnalysisControllerProjectBean.projectName}"/> + <p:commandButton value="Start Analysis" disabled="true"/> + <p:commandButton value="Stop Analysis" disabled="true"/> + <hr/> + <div align="center"> + <h:graphicImage id="iconLEDRed1" url="../img/Icon_LED_Red.png" height="50px"/> + <p:spacer height="0" width="15px"/> + <h:graphicImage id="iconLEDYellow" url="../img/Icon_LED_Gray.png" height="50px"/> + <p:spacer height="0" width="15px"/> + <h:graphicImage id="iconLEDGreen" url="../img/Icon_LED_Gray.png" height="50px"/> + <p:spacer height="0" width="15px"/> + <h:graphicImage id="iconLEDRed2" url="../img/Icon_LED_Gray.png" height="50px"/> + + <p:tooltip for="iconLEDRed1" value="Indicates that the AnalysisController has not been instantiated yet."/> + <p:tooltip for="iconLEDYellow" value="Indicates that the AnalysisController has been instantiated, but not yet started."/> + <p:tooltip for="iconLEDGreen" value="Indicates that the AnalysisController has been started and is running."/> + <p:tooltip for="iconLEDRed2" value="Indicates that the AnalysisController has been terminated."/> + </div> + </h:form> + </p:layoutUnit> + </p:layout> + + <p:growl id="messages" life="1500" showDetail="true" autoUpdate="false" sticky="false"/> + + <!-- Include the dialog for the configuration. --> + <ui:include src="dialogs/settingsDialog.xhtml" /> + + <!-- Include the about-dialog. --> + <ui:include src="dialogs/aboutDialog.xhtml" /> + + </h:body> +</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/AnalysisViewWorkSpace.xhtml b/Kieker.WebGUI/src/main/webapp/AnalysisViewWorkSpace.xhtml new file mode 100644 index 00000000..771cadac --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/AnalysisViewWorkSpace.xhtml @@ -0,0 +1,18 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + <h:head> + <title>Kieker.WebGUI</title> + <link rel="stylesheet" type="text/css" href="../css/AnalysisViewWorkSpace.css" /> + </h:head> + + <h:body> + + </h:body> +</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/META-INF/context.xml b/Kieker.WebGUI/src/main/webapp/META-INF/context.xml deleted file mode 100644 index 94faf711..00000000 --- a/Kieker.WebGUI/src/main/webapp/META-INF/context.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Context antiJARLocking="true" path="/Kieker.WebGUI"/> diff --git a/Kieker.WebGUI/src/main/webapp/ProjectOverview.xhtml b/Kieker.WebGUI/src/main/webapp/ProjectOverview.xhtml new file mode 100644 index 00000000..8706ab5e --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/ProjectOverview.xhtml @@ -0,0 +1,96 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + <h:head> + <title>Kieker.WebGUI</title> + <link rel="stylesheet" type="text/css" href="../css/Common.css" /> + <link rel="stylesheet" type="text/css" href="../css/ProjectOverview.css" /> + </h:head> + + <h:body> + + <p:layout fullPage="true"> + <p:layoutUnit position="north" header="Kieker.WebGUI"> + <h:form id="menubarForm"> + <p:menubar> + <p:submenu label="File"> + <p:menuitem value="New Project" onclick="newProjectDialog.show()" ajax="true"/> + <p:menuitem value="Import Project" ajax="true"/> + <p:separator/> + <p:menuitem value="Refresh Projects List" update=":projectsListForm" ajax="true"/> + <p:separator/> + <p:menuitem value="Settings" onclick="settingsDialog.show()" ajax="true"/> + </p:submenu> + + <p:submenu label="Help"> + <p:menuitem value="User Guide" ajax="true"/> + <p:separator/> + <p:menuitem value="About..." onclick="aboutDialog.show()" ajax="true"/> + </p:submenu> + + <p:menuitem styleClass="logOutButton" disabled="true" value="#{userBean.userName} [Log Out]" ajax="true"/> + </p:menubar> + </h:form> + </p:layoutUnit> + + <p:layoutUnit position="center"> + <h:form id="projectsListForm"> + <p:dataTable rows="15" paginator="true" var="project" value="#{projectsBean.projects}" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"> + <p:column headerText="Project Name" id="modelHeader" sortBy="#{project}"> + <h:outputText value="#{project}" /> + </p:column> + + <p:column headerText="Owner"> + <h:outputText value="N/A" /> + </p:column> + + <p:column headerText="Last Modification" sortBy="#{projectsBean.getCurrTimeStamp(project)}"> + <h:outputText value="#{projectsBean.getCurrTimeStamp(project)}" /> + </p:column> + + <p:column headerText="Analysis" style="text-align: center"> + <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: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"/> + <p:commandButton id="showAnalysis" ajax="false" action="#{currentAnalysisCockpitProjectBean.setProject(project)}" icon="ui-icon-search"/> + + <p:tooltip for="deleteButton" value="Delete Project"/> + <p:tooltip for="openButton" value="Open Project"/> + <p:tooltip for="renameButton" value="Rename Project"/> + <p:tooltip for="copyButton" value="Copy Project"/> + <p:tooltip for="controlAnalysis" value="Open Analysis Control"/> + <p:tooltip for="editAnalysisViews" value="Edit Analysis Views"/> + <p:tooltip for="showAnalysis" value="View Running Analysis"/> + </p:column> + </p:dataTable> + </h:form> + </p:layoutUnit> + + </p:layout> + + <p:growl id="messages" life="1500" showDetail="true" autoUpdate="false" sticky="false"/> + + <!-- Include the dialogs for the project managment. --> + <ui:include src="dialogs/projectDialogs.xhtml" /> + + <!-- Include the dialog for the configuration. --> + <ui:include src="dialogs/settingsDialog.xhtml" /> + + <!-- Include the about-dialog. --> + <ui:include src="dialogs/aboutDialog.xhtml" /> + </h:body> +</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml b/Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml new file mode 100644 index 00000000..8840130f --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml @@ -0,0 +1,100 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + <h:head> + <title>Kieker.WebGUI</title> + <link rel="stylesheet" type="text/css" href="../css/Common.css" /> + <link rel="stylesheet" type="text/css" href="../css/ProjectWorkSpace.css" /> + <script type="text/javascript" src="../js/js-graph-it.js"/> + <link rel="stylesheet" type="text/css" href="../css/js-graph-it.css"/> + </h:head> + + <h:body> + <p:layout id="layout" fullPage="true"> + + <p:layoutUnit position="north" collapsible="false" header="Kieker.WebGUI"> + <h:form> + <p:menubar> + <p:submenu label="File"> + <p:menuitem value="Save Project" ajax="true" disabled="#{empty currentWorkSpaceProjectBean.project}"/> + <p:menuitem value="Reset Project" ajax="true" disabled="#{empty currentWorkSpaceProjectBean.project}"/> + <p:separator/> + <p:menuitem value="Manage Libraries" onclick="manageLibrariesDialog.show()" ajax="true" disabled="#{empty currentWorkSpaceProjectBean.project}"/> + <p:separator/> + <p:menuitem value="Close Project" action="#{currentWorkSpaceProjectBean.clearProject()}" ajax="false"/> + <p:separator/> + <p:menuitem value="Settings" onclick="settingsDialog.show()" ajax="true"/> + </p:submenu> + + <p:submenu label="Help"> + <p:menuitem value="User Guide" ajax="true"/> + <p:separator/> + <p:menuitem value="About..." onclick="aboutDialog.show()" ajax="true"/> + </p:submenu> + + <p:menuitem styleClass="logOutButton" disabled="true" value="#{userBean.userName} [Log Out]" ajax="true"/> + </p:menubar> + + </h:form> + </p:layoutUnit> + + + <p:layoutUnit position="center" id="centerLayout"> + <h:form id="centerForm" style="height: 100%"> + + </h:form> + </p:layoutUnit> + + <p:layoutUnit position="south" size="150" header="Properties" resizable="true" collapsible="true"> + <h:form id="propertiesForm"> + + </h:form> + </p:layoutUnit> + + <p:layoutUnit position="east" size="300" header="Tool Palette" + resizable="true" collapsible="true"> + <h:form id="toolpalette"> + <p:accordionPanel multiple="true" activeIndex=""> + <p:tab title="Reader"> + <ui:repeat value="#{currentWorkSpaceProjectBean.availableReaders}" var="reader"> + <p:commandLink id="readerLink" value="#{reader.simpleName}" action="#{currentWorkSpaceProjectBean.addPlugin(reader)}" update=":centerForm" /><br/> + <p:tooltip style="font-size: 15px" for="readerLink" value="#{currentWorkSpaceProjectBean.getDescription(reader)}"/> + </ui:repeat> + </p:tab> + <p:tab title="Filter"> + <ui:repeat value="#{currentWorkSpaceProjectBean.availableFilters}" var="filter"> + <p:commandLink id="filterLink" value="#{filter.simpleName}" action="#{currentWorkSpaceProjectBean.addPlugin(filter)}" update=":centerForm"/><br/> + <p:tooltip style="font-size: 15px" for="filterLink" value="#{currentWorkSpaceProjectBean.getDescription(filter)}"/> + </ui:repeat> + </p:tab> + <p:tab title="Repositories"> + <ui:repeat value="#{currentWorkSpaceProjectBean.availableRepositories}" var="repository"> + <p:commandLink value="#{repository.simpleName}" update=":centerForm"/><br/> + </ui:repeat> + </p:tab> + </p:accordionPanel> + </h:form> + </p:layoutUnit> + <!-- ******************************************************************************** --> + </p:layout> + + <p:growl id="messages" life="1500" showDetail="true" autoUpdate="false" sticky="false"/> + + <!-- Include the dialog for the configuration. --> + <ui:include src="dialogs/settingsDialog.xhtml" /> + + <!-- Include the about-dialog. --> + <ui:include src="dialogs/aboutDialog.xhtml" /> + + <!-- Include the dialog to handle the connections. --> + <ui:include src="dialogs/connectionDialog.xhtml" /> + + <ui:include src="dialogs/manageLibrariesDialog.xhtml" /> + </h:body> +</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/WEB-INF/beans.xml b/Kieker.WebGUI/src/main/webapp/WEB-INF/beans.xml deleted file mode 100644 index 4ca8195b..00000000 --- a/Kieker.WebGUI/src/main/webapp/WEB-INF/beans.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<beans xmlns="http://java.sun.com/xml/ns/javaee" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> -</beans> diff --git a/Kieker.WebGUI/src/main/webapp/WEB-INF/pretty-config.xml b/Kieker.WebGUI/src/main/webapp/WEB-INF/pretty-config.xml index 5d32888c..4862796d 100644 --- a/Kieker.WebGUI/src/main/webapp/WEB-INF/pretty-config.xml +++ b/Kieker.WebGUI/src/main/webapp/WEB-INF/pretty-config.xml @@ -1,27 +1,37 @@ <pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.2 - http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.2.xsd"> + xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.2 + http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.2.xsd"> <url-mapping id="home"> - <pattern value="/Kieker.WebGUI/main" /> - <view-id value="/faces/main.xhtml" /> - </url-mapping> + <pattern value="/Kieker.WebGUI/" /> + <view-id value="/faces/ProjectOverview.xhtml" /> + </url-mapping> + + <url-mapping id="projectOverview"> + <pattern value="/Kieker.WebGUI/projectOverview" /> + <view-id value="/faces/ProjectOverview.xhtml" /> + </url-mapping> + + <url-mapping id="projectWorkSpace"> + <pattern value="/Kieker.WebGUI/projectWorkSpace" /> + <view-id value="/faces/ProjectWorkSpace.xhtml" /> + </url-mapping> - <url-mapping id="projectDependencies"> - <pattern value="/Kieker.WebGUI/projectDependencies" /> - <view-id value="/faces/projectDependencies.xhtml" /> + <url-mapping id="analysisViewWorkSpace"> + <pattern value="/Kieker.WebGUI/analysisViewWorkSpace" /> + <view-id value="/faces/AnalysisViewWorkSpace.xhtml" /> </url-mapping> - <url-mapping id="manageDependencies"> - <pattern value="/Kieker.WebGUI/manageDependencies" /> - <view-id value="/faces/manageDependencies.xhtml" /> + <url-mapping id="analysisController"> + <pattern value="/Kieker.WebGUI/analysisController" /> + <view-id value="/faces/AnalysisController.xhtml" /> </url-mapping> - <url-mapping id="handleAnalysis"> - <pattern value="/Kieker.WebGUI/handleAnalysis" /> - <view-id value="/faces/handleAnalysis.xhtml" /> + <url-mapping id="analysisCockpit"> + <pattern value="/Kieker.WebGUI/analysisCockpit" /> + <view-id value="/faces/AnalysisCockpit.xhtml" /> </url-mapping> </pretty-config> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml b/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml index f456e788..b34b9846 100644 --- a/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml +++ b/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml @@ -1,29 +1,32 @@ <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> - <context-param> - <param-name>javax.faces.STATE_SAVING_METHOD</param-name> - <param-value>server</param-value> - </context-param> - <context-param> - <param-name>javax.faces.PROJECT_STAGE</param-name> - <param-value>Development</param-value> - </context-param> + <context-param> + <param-name>javax.faces.STATE_SAVING_METHOD</param-name> + <param-value>server</param-value> + </context-param> + <context-param> + <param-name>javax.faces.PROJECT_STAGE</param-name> + <param-value>Development</param-value> + </context-param> - <filter> - <filter-name>PrimeFaces FileUpload Filter</filter-name> - <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class> - <init-param> - <param-name>thresholdSize</param-name> - <param-value>51200</param-value> - </init-param> - </filter> - <filter-mapping> - <filter-name>PrimeFaces FileUpload Filter</filter-name> - <url-pattern>/*</url-pattern> - </filter-mapping> + <!-- This filter is necessary for the PrimeFaces file upload in order to work. --> + <filter> + <filter-name>PrimeFaces FileUpload Filter</filter-name> + <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class> + <init-param> + <param-name>thresholdSize</param-name> + <param-value>51200</param-value> + </init-param> + </filter> - <context-param> + <filter-mapping> + <filter-name>PrimeFaces FileUpload Filter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <!-- This here makes sure that the theme chooser of PrimeFaces will work. --> + <context-param> <param-name>primefaces.THEME</param-name> <param-value>#{currentThemeBean.theme}</param-value> </context-param> @@ -46,14 +49,15 @@ </session-config> <welcome-file-list> - <welcome-file>faces/main.xhtml</welcome-file> + <welcome-file>faces/ProjectWorkSpace.xhtml</welcome-file> </welcome-file-list> <listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener> - <filter> + <!-- This filter will be used by Pretty Filter in order to use better looking URLs. --> + <filter> <filter-name>Pretty Filter</filter-name> <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class> </filter> diff --git a/Kieker.WebGUI/src/main/webapp/css/AnalysisCockpit.css b/Kieker.WebGUI/src/main/webapp/css/AnalysisCockpit.css new file mode 100644 index 00000000..e69de29b diff --git a/Kieker.WebGUI/src/main/webapp/css/AnalysisController.css b/Kieker.WebGUI/src/main/webapp/css/AnalysisController.css new file mode 100644 index 00000000..e69de29b diff --git a/Kieker.WebGUI/src/main/webapp/css/AnalysisViewWorkSpace.css b/Kieker.WebGUI/src/main/webapp/css/AnalysisViewWorkSpace.css new file mode 100644 index 00000000..e69de29b diff --git a/Kieker.WebGUI/src/main/webapp/main.css b/Kieker.WebGUI/src/main/webapp/css/Common.css similarity index 80% rename from Kieker.WebGUI/src/main/webapp/main.css rename to Kieker.WebGUI/src/main/webapp/css/Common.css index 836787cd..a703913e 100644 --- a/Kieker.WebGUI/src/main/webapp/main.css +++ b/Kieker.WebGUI/src/main/webapp/css/Common.css @@ -5,17 +5,13 @@ */ .ui-layout-north { z-index: 20 !important; - overflow: visible !important;; + overflow: visible !important; } .ui-layout-north .ui-layout-unit-content { overflow: visible !important; } -.ui-selectonemenu-items { - font-size: 15px; -} - .ui-layout-center { font-size: 15px; } @@ -36,19 +32,20 @@ font-size: 15px; } -.ui-contextmenu { - font-size: 15px; -} - .ui-dialog { font-size: 15px; width: auto; } -.projectInputText .pluginInputText { - width: 90%; -} +.ui-selectonemenu-items { + font-size: 15px; +} -.ui-tree { - width: auto; +.ui-tooltip { + font-size: 15px; +} + +.logOutButton { + position: absolute; + right: 5px; } \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/css/ProjectOverview.css b/Kieker.WebGUI/src/main/webapp/css/ProjectOverview.css new file mode 100644 index 00000000..9f0c53b1 --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/css/ProjectOverview.css @@ -0,0 +1,5 @@ +@charset "UTF-8"; + +.ui-datatable-odd { + background: none repeat scroll 0 0 #F2F5F9; +} \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/css/ProjectWorkSpace.css b/Kieker.WebGUI/src/main/webapp/css/ProjectWorkSpace.css new file mode 100644 index 00000000..e69de29b diff --git a/Kieker.WebGUI/src/main/webapp/js-graph-it.css b/Kieker.WebGUI/src/main/webapp/css/js-graph-it.css similarity index 100% rename from Kieker.WebGUI/src/main/webapp/js-graph-it.css rename to Kieker.WebGUI/src/main/webapp/css/js-graph-it.css diff --git a/Kieker.WebGUI/src/main/webapp/main/aboutDialog.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/aboutDialog.xhtml similarity index 82% rename from Kieker.WebGUI/src/main/webapp/main/aboutDialog.xhtml rename to Kieker.WebGUI/src/main/webapp/dialogs/aboutDialog.xhtml index 5bae983c..a79f1545 100644 --- a/Kieker.WebGUI/src/main/webapp/main/aboutDialog.xhtml +++ b/Kieker.WebGUI/src/main/webapp/dialogs/aboutDialog.xhtml @@ -5,8 +5,6 @@ xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> - <!-- ******************************************************************************** --> - <!-- This is the about-dialog. --> <p:dialog header="About..." resizable="false" modal="true" widgetVar="aboutDialog" id="aboutDialog"> <h:form> @@ -27,5 +25,4 @@ </div> </h:form> </p:dialog> - <!-- ******************************************************************************** --> </ui:composition> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml new file mode 100644 index 00000000..dc17e985 --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml @@ -0,0 +1,15 @@ +<ui:composition + xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + <p:dialog id="connectionDialog" header="Manage Connections" resizable="false" modal="true" widgetVar="connectionDialog"> + <h:form id="connectionDialogForm" rendered="#{not empty selectedMainProjectBean.mainProject}"> + + </h:form> + </p:dialog> + <!-- ******************************************************************************** --> +</ui:composition> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/dialogs/manageLibrariesDialog.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/manageLibrariesDialog.xhtml new file mode 100644 index 00000000..9e4df244 --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/dialogs/manageLibrariesDialog.xhtml @@ -0,0 +1,46 @@ +<ui:composition + xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui"> + + <p:dialog id="manageLibrariesDialog" header="Libraries" resizable="false" + modal="true" widgetVar="manageLibrariesDialog"> + + <h:form id="dependenciesForm"> + <p:dataTable id="currentDependencies" value="#{currentWorkSpaceProjectBean.libraries}" var="dependency" paginator="true" rows="10" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" > + + <p:column headerText="Filename"> + <h:outputText value="#{dependency.fst}"/> + </p:column> + + <p:column headerText="Size" style="text-align: center"> + <h:outputText value="#{dependency.snd} [MiByte]"/> + </p:column> + + <p:column headerText="Options" style="text-align: center; width:40px"> + <p:commandButton id="deleteButton" icon="ui-icon-trash"/> + <p:tooltip for="deleteButton" value="Delete Library"/> + </p:column> + </p:dataTable> + </h:form> + + <p:spacer width="0" height="5"/> + <div> + <!-- This is the form for the uploading. --> + <h:outputText value="Currently only *.jar-Dependencies can be uploaded. The maximal file size is limited to 100 [MiByte]." /> + <br /> + <br /> + <h:form enctype="multipart/form-data"> + <p:fileUpload auto="true" allowTypes="/(\.|\/)(jar)$/" sizeLimit="104857600" mode="advanced" fileUploadListener="#{currentWorkSpaceProjectBean.handleFileUpload}" update=":dependenciesForm :messages"/> + </h:form> + </div> + <hr/> + <div style="text-align: right"> + <h:form> + <p:commandButton value="Ok" ajax="true" onclick="manageLibrariesDialog.hide()" /> + </h:form> + </div> + </p:dialog> +</ui:composition> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/dialogs/projectDialogs.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/projectDialogs.xhtml new file mode 100644 index 00000000..77d967d2 --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/dialogs/projectDialogs.xhtml @@ -0,0 +1,30 @@ +<ui:composition + xmlns="http://www.w3.org/1999/xhtml" + xmlns:h="http://java.sun.com/jsf/html" + xmlns:ui="http://java.sun.com/jsf/facelets" + xmlns:f="http://java.sun.com/jsf/core" + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> + + <!-- ******************************************************************************** --> + <!-- This is the dialog to create a new project. --> + <p:dialog id="newProjectDialog" header="New Project" resizable="false" modal="true" widgetVar="newProjectDialog"> + <!-- Make sure that closing of the dialog also clears the input field. --> + <p:ajax event="close" update="newProjectDialogForm:newProjectInputText" /> + + <h:form id="newProjectDialogForm"> + <div style="text-align: center"> + <h:outputText value="Name: " /> + <p:inputText id="newProjectInputText" value="#{stringBean.string}" /> + </div> + + <hr/> + <div style="text-align: right"> + <p:commandButton value="Ok" action="#{projectsBean.addProject(stringBean.string)}" update=":projectsListForm :messages" oncomplete="newProjectDialog.hide()" /> + <p:spacer width="10px" height="10" /> + <p:commandButton value="Cancel" onclick="newProjectDialog.hide()" /> + </div> + </h:form> + </p:dialog> + <!-- ******************************************************************************** --> +</ui:composition> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/main/settingsDialog.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/settingsDialog.xhtml similarity index 80% rename from Kieker.WebGUI/src/main/webapp/main/settingsDialog.xhtml rename to Kieker.WebGUI/src/main/webapp/dialogs/settingsDialog.xhtml index 8b3035af..a47b05ba 100644 --- a/Kieker.WebGUI/src/main/webapp/main/settingsDialog.xhtml +++ b/Kieker.WebGUI/src/main/webapp/dialogs/settingsDialog.xhtml @@ -5,8 +5,6 @@ xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> - <!-- ******************************************************************************** --> - <!-- This is the dialog for settings and properties. --> <p:dialog id="settingsDialog" header="Settings" resizable="false" modal="true" widgetVar="settingsDialog"> <h:form> @@ -24,5 +22,4 @@ </div> </h:form> </p:dialog> - <!-- ******************************************************************************** --> </ui:composition> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/handleAnalysis.css b/Kieker.WebGUI/src/main/webapp/handleAnalysis.css deleted file mode 100644 index 0bb60d77..00000000 --- a/Kieker.WebGUI/src/main/webapp/handleAnalysis.css +++ /dev/null @@ -1,37 +0,0 @@ -@charset "UTF-8"; - -.ui-button { - font-size: 15px; -} - -.fileinput-button { - font-size: 5px; -} - -.ui-layout-center { - font-size: 15px; -} - -.ui-layout-north { - font-size: 15px; -} - -.ui-layout-south { - font-size: 15px; -} - -.ui-layout-east { - font-size: 15px; -} - -.ui-layout-west { - font-size: 15px; -} - -.ui-datatable { - font-size: 15px; -} - -.ui-panel { - font-size: 15px; -} \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/handleAnalysis.xhtml b/Kieker.WebGUI/src/main/webapp/handleAnalysis.xhtml deleted file mode 100644 index e180744c..00000000 --- a/Kieker.WebGUI/src/main/webapp/handleAnalysis.xhtml +++ /dev/null @@ -1,101 +0,0 @@ -<?xml version='1.0' encoding='UTF-8' ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:h="http://java.sun.com/jsf/html" - xmlns:f="http://java.sun.com/jsf/core" - xmlns:p="http://primefaces.org/ui" - xmlns:ui="http://java.sun.com/jsf/facelets" - xmlns:c="http://java.sun.com/jsp/jstl/core"> - - <f:view contentType="text/html"> - <h:head> - <title>Kieker.WebGUI - Analysis</title> - <link rel="stylesheet" type="text/css" href="../handleAnalysis.css" /> - <script type="text/javascript" src="../js-graph-it.js"/> - <link rel="stylesheet" type="text/css" href="../js-graph-it.css"/> - <style> - .block { - position: absolute; - } - .connector { - background-color: #FF9900; - } - </style> - </h:head> - - <h:body onload="initPageObjects();"> - - <p:layout fullPage="true"> - <p:layoutUnit header="Navigation" position="north" collapsible="true" resizable="true"> - <!-- The control panel to get back. --> - <h:form> - <c:if test="#{empty selectedProjectBean.selectedProject}"> - No project selected. - </c:if> - Click - <h:link outcome="/main">here</h:link> - to get back to the main menu. - </h:form> - </p:layoutUnit> - - <c:choose> - <c:when test="#{empty selectedProjectBean.selectedProject}"> - <p:layoutUnit position="center" > - </p:layoutUnit> - </c:when> - <c:otherwise> - - <p:layoutUnit position="center"> - <h:form id="centerForm"> - <p:dashboard id="dashboard" binding="#{dashboardBean.dashboard}"> - - </p:dashboard> - </h:form> - </p:layoutUnit> - - <p:layoutUnit position="west" size="200" resizable="true" collapsible="true" header="Plugins"> - <h:form id="pluginsForm"> - <p:accordionPanel value="#{analysisControllerBean.pluginMap.keySet().toArray()}" var="plugin" multiple="true" activeIndex=""> - <p:tab title="#{plugin.name}"> - <ui:repeat value="#{projectsBean.getWidgets(analysisControllerBean.pluginMap.get(plugin).getClass())}" var="widget"> - <p:commandLink value="#{widget.name}" ajax="true" update=":centerForm" action="#{dashboardBean.addWidget(widget)}"/><br/> - </ui:repeat> - </p:tab> - </p:accordionPanel> - </h:form> - </p:layoutUnit> - - <p:layoutUnit position="south" header="Analysis Control" resizable="true" collapsible="true"> - <h:form id="analysisForm"> - <p:commandButton value="Instantiate Analysis" action="#{analysisControllerBean.instantiate(selectedProjectBean.selectedProject)}" update=":analysisForm:analysisStateText :pluginsForm"/> - <p:commandButton id="startAnalysisButton" value="Start Analysis" async="true" action="#{analysisControllerBean.controller.run()}" disabled="#{empty analysisControllerBean.controller}"/> - <p:commandButton id="stopAnalysisButton" value="Stop Analysis" async="true" action="#{analysisControllerBean.controller.terminate()}" disabled="#{empty analysisControllerBean.controller}"/> - <p:spacer height="0px" width="150px"/> - <c:choose> - <c:when test="#{empty analysisControllerBean.controller}"> - <h:outputText id="analysisStateText" value="Analysis State: N/A"/><br/> - </c:when> - <c:otherwise> - <h:outputText id="analysisStateText" value="Analysis State: #{analysisControllerBean.controller.state}"/> - </c:otherwise> - </c:choose> - <br/> - <p:spacer width="0px" height="5px"/> - <p:scrollPanel id="logPanel" style="height: 150px"> - <ui:repeat var="entry" value="#{analysisControllerBean.logEntries}"> - <h:outputText value="#{entry}" /><br/> - </ui:repeat> - </p:scrollPanel> - <p:poll interval="2" update=":analysisForm:logPanel :analysisForm:analysisStateText :analysisForm:startAnalysisButton :analysisForm:stopAnalysisButton"/> - </h:form> - </p:layoutUnit> - - </c:otherwise> - </c:choose> - </p:layout> - - - </h:body> - </f:view> - -</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Gray.png b/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Gray.png new file mode 100644 index 0000000000000000000000000000000000000000..71c7b7afb598667ce2d3b94fe461a3a2c2c361b6 GIT binary patch literal 5565 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 Jyj;^R;(tkwpmqQN literal 0 HcmV?d00001 diff --git a/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Green.png b/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Green.png new file mode 100644 index 0000000000000000000000000000000000000000..1a55bc171a3924d89ba0995889f6c18c26ad85b4 GIT binary patch literal 8922 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 literal 0 HcmV?d00001 diff --git a/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Red.png b/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Red.png new file mode 100644 index 0000000000000000000000000000000000000000..0bf9ba32d99ac0b9f65ffa4a0ffa5d4442e0419b GIT binary patch literal 7146 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 literal 0 HcmV?d00001 diff --git a/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Yellow.png b/Kieker.WebGUI/src/main/webapp/img/Icon_LED_Yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e9505e043f72fdfff21182f2a51ebecd69df75 GIT binary patch literal 9564 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 literal 0 HcmV?d00001 diff --git a/Kieker.WebGUI/src/main/webapp/main/arrow.gif b/Kieker.WebGUI/src/main/webapp/img/arrow.gif similarity index 100% rename from Kieker.WebGUI/src/main/webapp/main/arrow.gif rename to Kieker.WebGUI/src/main/webapp/img/arrow.gif diff --git a/Kieker.WebGUI/src/main/webapp/main/arrow_d.gif b/Kieker.WebGUI/src/main/webapp/img/arrow_d.gif similarity index 100% rename from Kieker.WebGUI/src/main/webapp/main/arrow_d.gif rename to Kieker.WebGUI/src/main/webapp/img/arrow_d.gif diff --git a/Kieker.WebGUI/src/main/webapp/main/arrow_l.gif b/Kieker.WebGUI/src/main/webapp/img/arrow_l.gif similarity index 100% rename from Kieker.WebGUI/src/main/webapp/main/arrow_l.gif rename to Kieker.WebGUI/src/main/webapp/img/arrow_l.gif diff --git a/Kieker.WebGUI/src/main/webapp/main/arrow_r.gif b/Kieker.WebGUI/src/main/webapp/img/arrow_r.gif similarity index 100% rename from Kieker.WebGUI/src/main/webapp/main/arrow_r.gif rename to Kieker.WebGUI/src/main/webapp/img/arrow_r.gif diff --git a/Kieker.WebGUI/src/main/webapp/main/arrow_u.gif b/Kieker.WebGUI/src/main/webapp/img/arrow_u.gif similarity index 100% rename from Kieker.WebGUI/src/main/webapp/main/arrow_u.gif rename to Kieker.WebGUI/src/main/webapp/img/arrow_u.gif diff --git a/Kieker.WebGUI/src/main/webapp/js-graph-it.js b/Kieker.WebGUI/src/main/webapp/js/js-graph-it.js similarity index 100% rename from Kieker.WebGUI/src/main/webapp/js-graph-it.js rename to Kieker.WebGUI/src/main/webapp/js/js-graph-it.js diff --git a/Kieker.WebGUI/src/main/webapp/main.xhtml b/Kieker.WebGUI/src/main/webapp/main.xhtml deleted file mode 100644 index fc9dd9bb..00000000 --- a/Kieker.WebGUI/src/main/webapp/main.xhtml +++ /dev/null @@ -1,223 +0,0 @@ -<?xml version='1.0' encoding='UTF-8' ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:h="http://java.sun.com/jsf/html" - xmlns:ui="http://java.sun.com/jsf/facelets" - xmlns:f="http://java.sun.com/jsf/core" - xmlns:p="http://primefaces.org/ui" - xmlns:c="http://java.sun.com/jsp/jstl/core"> - - <f:view contentType="text/html"> - <h:head> - <title>Kieker.WebGUI</title> - <link rel="stylesheet" type="text/css" href="../main.css" /> - <script type="text/javascript" src="../js-graph-it.js"/> - <link rel="stylesheet" type="text/css" href="../js-graph-it.css"/> - <style> - .block { - position: absolute; - } - .connector { - background-color: #FF9900; - } - </style> - </h:head> - - <h:body onload="initPageObjects();"> - - <!-- This is the layout for the whole page. --> - <p:layout id="layout" fullPage="true"> - - <!-- ******************************************************************************** --> - <!-- This is the top unit within the layout and is used for the menu bar. --> - <p:layoutUnit position="north" size="60" collapsible="false"> - <h:form> - <p:menubar> - <p:submenu label="File"> - <p:menuitem value="New Project" onclick="newProjectDialog.show()" ajax="true" /> - <p:menuitem value="Import Project" ajax="true" /> - <p:menuitem value="Manage Dependencies" ajax="false" url="/Kieker.WebGUI/manageDependencies" /> - <p:separator /> - <p:menuitem value="Settings" onclick="settingsDialog.show()" ajax="true" /> - </p:submenu> - - <!-- This is the submenu for the current project, for example if someone doesn't want to use the context menu within the browser. --> - <p:submenu label="Current Project"> - <p:menuitem value="Save Project" ajax="true" action="#{projectsBean.saveProject(selectedProjectBean.getSelectedProject())}" update=":projectsForm" /> - <p:menuitem value="Set as Main Project" ajax="true" action="#{selectedMainProjectBean.setMainProject(selectedProjectBean.getSelectedProject())}"/> - <p:separator /> - <p:menuitem value="Delete Project" ajax="true" onclick="deleteProjectDialog.show()" /> - <p:menuitem value="Reset Project" ajax="true" onclick="resetProjectDialog.show()" /> - <p:separator /> - <p:menuitem value="Configure Dependencies" ajax="false" url="/Kieker.WebGUI/projectDependencies" /> - <p:separator /> - <p:menuitem value="Analysis" ajax="false" url="/Kieker.WebGUI/handleAnalysis" /> - </p:submenu> - - <p:submenu label="Help"> - <p:menuitem value="About..." ajax="true" onclick="aboutDialog.show()" /> - </p:submenu> - </p:menubar> - - </h:form> - </p:layoutUnit> - <!-- ******************************************************************************** --> - - <!-- ******************************************************************************** --> - <!-- The following layout is at the left side of the page and shows the available projects. --> - <p:layoutUnit header="Projects" collapsible="true" position="west" size="200" resizable="true" minSize="100"> - <h:form id="projectsForm"> - <p:tree selection="#{selectedProjectBean.selectedNode}" id="projectsTree" selectionMode="single" value="#{projectsBean.projectsRoot}" var="node"> - <p:ajax event="select" listener="#{selectedProjectBean.onNodeSelect}"/> - - <p:treeNode type="project"> - <h:outputText style="font-weight: #{selectedMainProjectBean.mainProject == node ? 'bold' : 'normal' }" value="#{node.name}"/> - </p:treeNode> - - <p:treeNode type="dependencies"> - <h:outputText value="#{node}" /> - </p:treeNode> - - <p:treeNode type="usedPlugins"> - <h:outputText value="#{node}" /> - </p:treeNode> - - <p:treeNode type="usedPlugin"> - <h:outputText value="#{node}" /> - </p:treeNode> - </p:tree> - - <p:contextMenu for="projectsTree" nodeType="project"> - <p:menuitem value="Save Project" ajax="true" action="#{projectsBean.saveProject(selectedProjectBean.getSelectedProject())}" update=":projectsForm" /> - <p:menuitem value="Set as Main Project" ajax="true" action="#{selectedMainProjectBean.setMainProject(selectedProjectBean.getSelectedProject())}" /> - <p:separator /> - <p:menuitem value="Delete Project" ajax="true" onclick="deleteProjectDialog.show()" /> - - <p:menuitem value="Reset Project" ajax="true" onclick="resetProjectDialog.show()" /> - <p:separator /> - <p:menuitem value="Configure Dependencies" ajax="false" url="/Kieker.WebGUI/projectDependencies" /> - <p:separator /> - <p:menuitem value="Analysis" ajax="false" url="/Kieker.WebGUI/handleAnalysis" /> - </p:contextMenu> - - <p:contextMenu for="projectsTree" nodeType="dependencies"> - </p:contextMenu> - - <p:contextMenu for="projectsTree" nodeType="usedPlugins"> - </p:contextMenu> - </h:form> - - </p:layoutUnit> - <!-- ******************************************************************************** --> - - <!-- ******************************************************************************** --> - <!-- The following layout unit is within the center and used for the graph. --> - <p:layoutUnit position="center" id="centerLayout"> - <h:form id="centerForm" style="height: 100%"> - <div class="canvas" id="mainCanvas" style="width : 500px;height: 500px"> - <c:forEach items="#{selectedMainProjectBean.mainProject.plugins}" var="plugin" varStatus="counter"> - <p:remoteCommand name="setPlugin#{counter.index}" action="#{selectedPluginBean.setPlugin(plugin)}"/> - <!-- Netbeans reports an error here, but the code does still work though... --> - <div onclick="setPlugin#{counter.index}();" class="ui-panel ui-widget ui-widget-content ui-corner-all block draggable" id="#{stringToIDBean.stringToID(plugin)}" > - <div class="ui-panel-titlebar ui-widget-header ui-corner-all"> - <h:outputText style="font-weight: bold" value="#{plugin.getName()}"/> - </div> - <p:commandLink ajax="true" value="Connections" update=":connectionDialogForm" onclick="connectionDialog.show();"/> - <br/> - <p:commandLink ajax="true" value="Remove" action="#{selectedMainProjectBean.removePlugin(plugin)}" update=":propertiesForm"/> - </div> - - </c:forEach> - <c:forEach items="#{selectedMainProjectBean.validConnections}" var="connection"> - <div class="connector #{stringToIDBean.stringToID(connection.source)} #{stringToIDBean.stringToID(connection.destination)}"> - <label class="source-label"><h:outputText value="#{connection.outputPort.getName()}"/></label> - <label class="destination-label"><h:outputText value="#{connection.inputPort.getName()}"/></label> - - <img src="../main/arrow.gif" class="connector-end"/> - </div> - </c:forEach> - </div> - </h:form> - </p:layoutUnit> - <!-- ******************************************************************************** --> - - <!-- ******************************************************************************** --> - <!-- The following layout unit is located at the bottom and will be used for properties. --> - <p:layoutUnit position="south" size="150" header="Properties" resizable="true" collapsible="true"> - <h:form id="propertiesForm"> - <c:if test="#{not empty selectedPluginBean.plugin}"> - <p:dataTable value="#{selectedPluginBean.advancedProperties}" var="property" id="propertiesList" emptyMessage="No properties available"> - <p:column headerText="Key" style="width:125px"> - <h:outputText value="#{property.name}" rendered="#{not stringBean.checkString(property)}"/> - <h:outputText value="Name" rendered="#{stringBean.checkString(property)}"/> - </p:column> - - <p:column headerText="Value" style="width:125px"> - <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)}"/> - </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)}"/> - </f:facet> - </p:cellEditor> - </p:column> - - <p:column headerText="Options" style="width:50px"> - <p:rowEditor /> - </p:column> - - <p:ajax event="rowEdit" update=":centerForm" /> - </p:dataTable> - </c:if> - </h:form> - </p:layoutUnit> - <!-- ******************************************************************************** --> - - <!-- ******************************************************************************** --> - <!-- The following layout unit is located at the right side of the page and is used as a tool palette. It shows the available plugins etc. --> - <p:layoutUnit position="east" size="300" header="Tool Palette" - resizable="true" collapsible="true"> - <h:form id="toolpalette"> - <p:accordionPanel multiple="true" activeIndex=""> - <p:tab title="Reader"> - <ui:repeat value="#{selectedMainProjectBean.availableReaders}" var="reader"> - <p:commandLink id="readerLink" value="#{reader.simpleName}" action="#{selectedMainProjectBean.addPlugin(reader)}" update=":projectsForm :centerForm" /><br/> - <p:tooltip style="font-size: 15px" for="readerLink" value="#{projectsBean.getDescription(reader)}"/> - </ui:repeat> - </p:tab> - <p:tab title="Filter"> - <ui:repeat value="#{selectedMainProjectBean.availableFilters}" var="filter"> - <p:commandLink id="filterLink" value="#{filter.simpleName}" action="#{selectedMainProjectBean.addPlugin(filter)}" update=":projectsForm :centerForm"/><br/> - <p:tooltip style="font-size: 15px" for="filterLink" value="#{projectsBean.getDescription(filter)}"/> - </ui:repeat> - </p:tab> - <p:tab title="Repositories"> - <ui:repeat value="#{selectedMainProjectBean.availableRepositories}" var="repository"> - <p:commandLink value="#{repository.simpleName}" update=":projectsForm :centerForm"/><br/> - </ui:repeat> - </p:tab> - </p:accordionPanel> - </h:form> - </p:layoutUnit> - <!-- ******************************************************************************** --> - </p:layout> - - <p:growl id="messages" showDetail="true" autoUpdate="true" sticky="false"/> - - <!-- Include the dialogs for creating/deleting projects etc. --> - <ui:include src="main/projectDialogs.xhtml" /> - - <!-- Include the dialog for the configuration. --> - <ui:include src="main/settingsDialog.xhtml" /> - - <!-- Include the about-dialog. --> - <ui:include src="main/aboutDialog.xhtml" /> - - <!-- Include the dialog to handle the connections. --> - <ui:include src="main/connectionDialog.xhtml" /> - </h:body> - </f:view> -</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/main/connectionDialog.xhtml b/Kieker.WebGUI/src/main/webapp/main/connectionDialog.xhtml deleted file mode 100644 index cf19e145..00000000 --- a/Kieker.WebGUI/src/main/webapp/main/connectionDialog.xhtml +++ /dev/null @@ -1,96 +0,0 @@ -<ui:composition - xmlns="http://www.w3.org/1999/xhtml" - xmlns:h="http://java.sun.com/jsf/html" - xmlns:ui="http://java.sun.com/jsf/facelets" - xmlns:f="http://java.sun.com/jsf/core" - xmlns:p="http://primefaces.org/ui" - xmlns:c="http://java.sun.com/jsp/jstl/core"> - - <!-- ******************************************************************************** --> - <p:dialog id="connectionDialog" header="Manage Connections" resizable="false" modal="true" widgetVar="connectionDialog"> - <h:form id="connectionDialogForm" rendered="#{not empty selectedMainProjectBean.mainProject}"> - <p:commandButton value="Add Connection" ajax="true" action="#{selectedMainProjectBean.addConnection()}" update=":connectionDialogForm"/> - <br/><br/> - <p:dataTable value="#{selectedMainProjectBean.connections}" var="connection" paginator="true" rows="10" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"> - - <p:column headerText="Source" style="width:125px"> - <p:cellEditor> - <f:facet name="output"> - <h:outputText value="#{empty connection.source ? 'N/A' : connection.source.name}"/> - </f:facet> - <f:facet name="input"> - <p:selectOneMenu converter="kieker.webgui.converter.MIPluginToStringConverter" value="#{connection.source}" effectDuration="100"> - <f:selectItem value="#{null}" itemLabel="N/A" itemValue="#{null}"/> - <f:selectItems value="#{selectedMainProjectBean.mainProject.plugins}" var="plugin" itemLabel="#{plugin.name}" itemValue="#{plugin}"/> - <p:ajax event="change" update="validColumn outputPortsList"/> - </p:selectOneMenu> - </f:facet> - </p:cellEditor> - </p:column> - - <p:column headerText="Output Port" style="width:125px"> - <p:cellEditor> - <f:facet name="output"> - <h:outputText value="#{empty connection.outputPort ? 'N/A' : connection.outputPort.name}"/> - </f:facet> - <f:facet name="input"> - <h:form id="outputPortsList"> - <p:selectOneMenu rendered="#{not empty connection.source}" converter="kieker.webgui.converter.MIPortToStringConverter" value="#{connection.outputPort}" effectDuration="100"> - <f:selectItem value="#{null}" itemLabel="N/A" itemValue="#{null}"/> - <f:selectItems value="#{connection.source.outputPorts}" var="port" itemLabel="#{port.name}" itemValue="#{port}"/> - <p:ajax event="change" update="validColumn"/> - </p:selectOneMenu> - </h:form> - </f:facet> - </p:cellEditor> - </p:column> - - <p:column headerText="Destination" style="width:125px"> - <p:cellEditor> - <f:facet name="output"> - <h:outputText value="#{empty connection.destination ? 'N/A' : connection.destination.name}"/> - </f:facet> - <f:facet name="input"> - <p:selectOneMenu converter="kieker.webgui.converter.MIPluginToStringConverter" value="#{connection.destination}" effectDuration="100"> - <f:selectItem value="#{null}" itemLabel="N/A" itemValue="#{null}"/> - <f:selectItems value="#{selectedMainProjectBean.filters}" var="plugin" itemLabel="#{plugin.name}" itemValue="#{plugin}"/> - <p:ajax event="change" update="validColumn inputPortsList"/> - </p:selectOneMenu> - </f:facet> - </p:cellEditor> - </p:column> - - <p:column headerText="Input Port" style="width:125px"> - <p:cellEditor> - <f:facet name="output"> - <h:outputText value="#{empty connection.inputPort ? 'N/A' : connection.inputPort.name}"/> - </f:facet> - <f:facet name="input"> - <h:form id="inputPortsList"> - <p:selectOneMenu rendered="#{not empty connection.destination}" converter="kieker.webgui.converter.MIPortToStringConverter" value="#{connection.inputPort}" effectDuration="100"> - <f:selectItem value="#{null}" itemLabel="N/A" itemValue="#{null}"/> - <f:selectItems value="#{connection.destination.inputPorts}" var="port" itemLabel="#{port.name}" itemValue="#{port}"/> - <p:ajax event="change" update="validColumn"/> - </p:selectOneMenu> - </h:form> - </f:facet> - </p:cellEditor> - </p:column> - - <p:column id="validColumn" headerText="Valid" style="width:50px"> - <h:outputText value="#{connection.valid ? 'True' : 'False'}"/> - </p:column> - - <p:column headerText="Options" style="width:50px"> - <p:rowEditor /> - </p:column> - </p:dataTable> - <br/> - <hr/> - <div style="text-align: right"> - <p:commandButton value="Ok" action="#{selectedMainProjectBean.submitConnections()}" oncomplete="connectionDialog.hide();" /> - </div> - </h:form> - </p:dialog> - <!-- ******************************************************************************** --> -</ui:composition> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/main/projectDialogs.xhtml b/Kieker.WebGUI/src/main/webapp/main/projectDialogs.xhtml deleted file mode 100644 index 1a6dbb7a..00000000 --- a/Kieker.WebGUI/src/main/webapp/main/projectDialogs.xhtml +++ /dev/null @@ -1,66 +0,0 @@ -<ui:composition - xmlns="http://www.w3.org/1999/xhtml" - xmlns:h="http://java.sun.com/jsf/html" - xmlns:ui="http://java.sun.com/jsf/facelets" - xmlns:f="http://java.sun.com/jsf/core" - xmlns:p="http://primefaces.org/ui" - xmlns:c="http://java.sun.com/jsp/jstl/core"> - - <!-- ******************************************************************************** --> - <!-- This is the dialog to create a new project. --> - <p:dialog id="newProjectDialog" header="New Project" resizable="false" modal="true" widgetVar="newProjectDialog"> - <!-- Make sure that closing of the dialog also clears the input field. --> - <p:ajax event="close" update="newProjectDialogForm:newProjectInputText" /> - - <h:form id="newProjectDialogForm"> - <div style="text-align: center"> - <h:outputText value="Name: " /> - <p:inputText id="newProjectInputText" value="#{stringBean.string}" /> - </div> - - <hr/> - <div style="text-align: right"> - <p:commandButton value="Ok" action="#{projectsBean.addProject(stringBean.string)}" oncomplete="newProjectDialog.hide()" /> - <p:spacer width="10px" height="10" /> - <p:commandButton value="Cancel" onclick="newProjectDialog.hide()" /> - </div> - </h:form> - </p:dialog> - <!-- ******************************************************************************** --> - - <!-- ******************************************************************************** --> - <!-- This is the dialog to delete the selected project. --> - <p:dialog id="deleteProjectDialog" header="Delete Project" resizable="false" modal="true" widgetVar="deleteProjectDialog"> - <h:form> - <div style="text-align: center"> - <h:outputText value="Do you really want to remove the selected project?" /> - </div> - - <hr/> - <div style="text-align: right"> - <p:commandButton value="Yes" action="#{projectsBean.deleteProject(selectedProjectBean.getSelectedProject())}" update=":projectsForm" oncomplete="deleteProjectDialog.hide()" /> - <p:spacer width="10px" height="10" /> - <p:commandButton value="Cancel" onclick="deleteProjectDialog.hide()" /> - </div> - </h:form> - </p:dialog> - <!-- ******************************************************************************** --> - - <!-- ******************************************************************************** --> - <!-- This is the dialog to reset the selected project. --> - <p:dialog id="resetProjectDialog" header="Reset Project" resizable="false" modal="true" widgetVar="resetProjectDialog"> - <h:form> - <div style="text-align: center"> - <h:outputText value="Do you really want to reset the selected project?" /> - </div> - - <hr/> - <div style="text-align: right"> - <p:commandButton value="Yes" action="#{projectsBean.resetProject(selectedProjectBean.getSelectedProject())}" update=":projectsForm" oncomplete="resetProjectDialog.hide()" /> - <p:spacer width="10px" height="10" /> - <p:commandButton value="Cancel" onclick="resetProjectDialog.hide()" /> - </div> - </h:form> - </p:dialog> - <!-- ******************************************************************************** --> -</ui:composition> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/manageDependencies.css b/Kieker.WebGUI/src/main/webapp/manageDependencies.css deleted file mode 100644 index 4f9b12fd..00000000 --- a/Kieker.WebGUI/src/main/webapp/manageDependencies.css +++ /dev/null @@ -1,30 +0,0 @@ -@charset "UTF-8"; - -.ui-button { - font-size: 15px; -} - -.fileinput-button { - font-size: 5px; -} - -.ui-layout-center { - font-size: 15px; -} - -.ui-layout-north { - font-size: 15px; -} - -.ui-layout-south { - font-size: 15px; -} - - -.ui-datatable { - font-size: 15px; -} - -.ui-panel { - font-size: 15px; -} \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/manageDependencies.xhtml b/Kieker.WebGUI/src/main/webapp/manageDependencies.xhtml deleted file mode 100644 index 6ed5e575..00000000 --- a/Kieker.WebGUI/src/main/webapp/manageDependencies.xhtml +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version='1.0' encoding='UTF-8' ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:h="http://java.sun.com/jsf/html" - xmlns:f="http://java.sun.com/jsf/core" - xmlns:p="http://primefaces.org/ui"> - - <f:view contentType="text/html"> - <h:head> - <title>Kieker.WebGUI - Dependencies</title> - <link rel="stylesheet" type="text/css" href="../manageDependencies.css" /> - </h:head> - - <h:body> - - <p:layout fullPage="true"> - <p:layoutUnit header="Navigation" position="north" collapsible="true" resizable="true"> - <!-- The control panel to get back. --> - <h:form> - Click - <h:link outcome="/main">here</h:link> - to get back to the main menu. - </h:form> - </p:layoutUnit> - - <p:layoutUnit header="Currently available Dependencies" position="center" > - <!-- This form shows the currently available dependencies. --> - <h:form id="currentDependenciesForm"> - <p:dataTable id="currentDependencies" value="#{dependenciesBean.dependencies}" var="dependency" paginator="true" rows="10" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" > - - <p:column> - <f:facet name="header"> - Filename - </f:facet> - <h:outputText value="#{dependency}" > - <f:converter converterId="kieker.webgui.converter.MIDependencyToStringConverter" /> - </h:outputText> - </p:column> - - <p:column> - <f:facet name="header"> - Size - </f:facet> - <div align="center"> - <h:outputText value="#{dependency}" > - <f:converter converterId="kieker.webgui.converter.MIDependencyToSizeConverter" /> - </h:outputText> - </div> - </p:column> - - <p:column> - <f:facet name="header"> - # Plugins - </f:facet> - <div align="center"> - <h:outputText value="#{dependency}" > - <f:converter converterId="kieker.webgui.converter.MIDependencyToCountPluginsConverter" /> - </h:outputText> - </div> - </p:column> - - <p:column style="width:40px"> - <f:facet name="header"> - </f:facet> - <div align="center"> - <p:commandButton ajax="true" update=":currentDependenciesForm" icon="ui-icon-trash" title="Delete" - action="#{dependenciesBean.deleteDependency(dependency)}"/> - </div> - </p:column> - </p:dataTable> - </h:form> - </p:layoutUnit> - - <p:layoutUnit header="Upload Dependencies" position="south" collapsible="true" resizable="true"> - <!-- This is the form for the uploading. --> - <h:outputText value="Currently only *.jar-Dependencies can be uploaded. The maximal file size is limited to 100 [MiByte]." /> - <br /> - <br /> - <h:form enctype="multipart/form-data"> - <p:fileUpload value="#{dependencyUploadBean.file}" - allowTypes="/(\.|\/)(jar)$/" - sizeLimit="104857600" - mode="simple" /> - - <p:spacer width ="50px" height="0px"/> - <p:commandLink ajax="false" actionListener="#{dependencyUploadBean.upload}"> - <h:outputText value="Upload File" /> - </p:commandLink> - </h:form> - - </p:layoutUnit> - - </p:layout> - </h:body> - </f:view> - -</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/projectDependencies.css b/Kieker.WebGUI/src/main/webapp/projectDependencies.css deleted file mode 100644 index 06cd434c..00000000 --- a/Kieker.WebGUI/src/main/webapp/projectDependencies.css +++ /dev/null @@ -1,26 +0,0 @@ -@charset "UTF-8"; - -.ui-button { - font-size: 15px; -} - -.ui-layout-center { - font-size: 15px; -} - -.ui-layout-north { - font-size: 15px; -} - -.ui-panel { - font-size: 15px; -} - -.my-picklist .ui-picklist .ui-picklist-list { - height: 120px; - width: 520px; -} - -.column { - vertical-align: top -} \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/projectDependencies.xhtml b/Kieker.WebGUI/src/main/webapp/projectDependencies.xhtml deleted file mode 100644 index d74b128d..00000000 --- a/Kieker.WebGUI/src/main/webapp/projectDependencies.xhtml +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version='1.0' encoding='UTF-8' ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:h="http://java.sun.com/jsf/html" - xmlns:f="http://java.sun.com/jsf/core" - xmlns:p="http://primefaces.org/ui" - xmlns:c="http://java.sun.com/jsp/jstl/core"> - - <f:view contentType="text/html"> - <h:head> - <title>Kieker.WebGUI - Project Dependencies</title> - <link rel="stylesheet" title="Standard-Stylesheet" type="text/css" - href="../projectDependencies.css" /> - </h:head> - <body> - - <p:layout fullPage="true"> - <p:layoutUnit header="Navigation" position="north" collapsible="true" resizable="true"> - <!-- The control panel to get back. --> - <h:form> - <c:if test="#{empty selectedProjectBean.selectedProject}"> - No project selected. - </c:if> - Click - <h:link outcome="/main">here</h:link> - to get back to the main menu. - </h:form> - </p:layoutUnit> - - <c:choose> - <c:when test="#{empty selectedProjectBean.selectedProject}"> - <p:layoutUnit position="center" > - </p:layoutUnit> - </c:when> - <c:otherwise> - - <p:layoutUnit header="Currently used Dependencies for '#{selectedProjectBean.selectedProject.name}'" position="center" > - <h:form> - <h:panelGrid columns="2" columnClasses="column"> - <h:panelGrid columns="1"> - <p:commandButton ajax="true" value="Accept Selection" action="#{selectedDependenciesBean.submit()}" style="width: 100%" update=":messages"/> - <p:commandButton ajax="true" value="Reset Selection" style="width: 100%" /> - </h:panelGrid> - <p:selectManyCheckbox value="#{selectedDependenciesBean.dependencies}" - layout="pageDirection" - converter="kieker.webgui.converter.MIDependencyToStringConverter"> - <f:selectItems value="#{dependenciesBean.dependencies}" - var="dependency" itemLabel="#{dependency.filePath}" - itemValue="#{dependency}" /> - </p:selectManyCheckbox> - </h:panelGrid> - </h:form> - </p:layoutUnit> - - </c:otherwise> - </c:choose> - - </p:layout> - - <p:growl id="messages" showDetail="true" autoUpdate="true" sticky="false"/> - - </body> - </f:view> - -</html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/test/java/kieker/webgui/common/LRUCacheTest.java b/Kieker.WebGUI/src/test/java/kieker/webgui/common/LRUCacheTest.java deleted file mode 100644 index e6bd4023..00000000 --- a/Kieker.WebGUI/src/test/java/kieker/webgui/common/LRUCacheTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package kieker.webgui.common; - -import junit.framework.Assert; -import junit.framework.TestCase; - -import org.junit.Test; - -/** - * TestCase for {@link LRUCache}. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ -public class LRUCacheTest extends TestCase { - - /** - * Creates a new instance of this class. - */ - public LRUCacheTest() {} - - @Test - public void testEntryStorage() { - final int n = 5; - final LRUCache<Integer, Integer> cache = new LRUCache<Integer, Integer>(n); - - // Make sure that there is nothing stored under the given values yet. - for (int i = 0; i < n; i++) { - Assert.assertNull(cache.get(i)); - } - - // Store everything - for (int i = 0; i < n; i++) { - cache.add(i, n - i); - } - - // Make sure that the values are still available - for (int i = 0; i < n; i++) { - Assert.assertEquals((Integer) (n - i), cache.get(i)); - } - - // Overwrite an entry - cache.add(0, 0); - // Make sure that it worked - Assert.assertEquals((Integer) 0, cache.get(0)); - } - - @Test - public void testMaximalStorage() { - final int n = 5; - final LRUCache<Integer, Integer> cache = new LRUCache<Integer, Integer>(n); - - // Make sure that there is nothing stored under the given values yet. - for (int i = 0; i < n; i++) { - Assert.assertNull(cache.get(i)); - } - - // Store everything and exceed the size - for (int i = 0; i < n + 1; i++) { - cache.add(i, n - i); - } - - // Make sure that the values are still available - for (int i = 1; i < n + 1; i++) { - Assert.assertEquals((Integer) (n - i), cache.get(i)); - } - - // Make sure that the oldest entry isn't available - Assert.assertNull(cache.get(0)); - } -} diff --git a/Kieker.WebGUI/src/test/java/kieker/webgui/common/PluginFinderTest.java b/Kieker.WebGUI/src/test/java/kieker/webgui/common/PluginFinderTest.java deleted file mode 100644 index 0020e52f..00000000 --- a/Kieker.WebGUI/src/test/java/kieker/webgui/common/PluginFinderTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * 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.common; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; - -import junit.framework.Assert; -import junit.framework.TestCase; -import kieker.analysis.plugin.AbstractPlugin; - -import org.junit.Test; - -/** - * @author Nils Christian Ehmke - * @version 1.0 - */ -public class PluginFinderTest extends TestCase { - - /** - * Creates a new instance of this class. - */ - public PluginFinderTest() {} - - /** - * This test makes sure that the plugin finder is able to find plugins within the kieker jar. - */ - @Test - public void testKiekerJarContainsPlugins() { - /* It can be assumed that the kieker jar contains at least one plugin. */ - try { - PluginClassLoader.getInstance().addURL(new URL("file", "localhost", "lib/kieker-1.6-SNAPSHOT_emf.jar")); - final List<Class<AbstractPlugin>> availableKiekerPlugins = PluginFinder.getAllPluginsWithinJar(new URL("file", "localhost", - "lib/kieker-1.6-SNAPSHOT_emf.jar")); - Assert.assertTrue("Kieker-Jar seems to contain no plugins.", availableKiekerPlugins.size() > 0); - } catch (final MalformedURLException ex) { - Assert.fail("Exception occured."); - } - } -} -- GitLab