diff --git a/Kieker.WebGUI/config/quality-config/cs-conf.xml b/Kieker.WebGUI/config/quality-config/cs-conf.xml index f9d8fb899de1f7a2cca5f38cd81e42a4618963cc..3abf3c329ecb5f5b7e61746fcecedd17bda14a1b 100644 --- a/Kieker.WebGUI/config/quality-config/cs-conf.xml +++ b/Kieker.WebGUI/config/quality-config/cs-conf.xml @@ -1,255 +1,1247 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> - -<!-- - This configuration file was written by the eclipse-cs plugin configuration editor ---> -<!-- - Checkstyle-Configuration: CS-Config - Description: none ---> +<!DOCTYPE module PUBLIC + "-//Puppy Crawl//DTD Check Configuration 1.3//EN" + "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> + <module name="Checker"> - <property name="severity" value="warning"/> - <module name="TreeWalker"> - <property name="tabWidth" value="4"/> - <module name="FileContentsHolder"/> - <module name="AnnotationUseStyle"/> - <module name="MissingDeprecated"> - <property name="severity" value="info"/> - </module> - <module name="PackageAnnotation"/> - <module name="SuppressWarnings"> - <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF, ENUM_CONSTANT_DEF, PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, CTOR_DEF"/> - </module> - <module name="AvoidNestedBlocks"> - <property name="allowInSwitchCase" value="true"/> - </module> - <module name="EmptyBlock"> - <property name="tokens" value="LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF, LITERAL_FOR, LITERAL_TRY, LITERAL_WHILE, INSTANCE_INIT, STATIC_INIT"/> - </module> - <module name="LeftCurly"> - <property name="maxLineLength" value="165"/> - <property name="tokens" value="CLASS_DEF, CTOR_DEF, INTERFACE_DEF, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF"/> - </module> - <module name="NeedBraces"> - <property name="tokens" value="LITERAL_DO, LITERAL_ELSE, LITERAL_IF, LITERAL_FOR, LITERAL_WHILE"/> - </module> - <module name="RightCurly"> - <property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE"/> - </module> - <module name="FinalClass"/> - <module name="HideUtilityClassConstructor"/> - <module name="InnerTypeLast"/> - <module name="InterfaceIsType"/> - <module name="MutableException"/> - <module name="VisibilityModifier"> - <property name="protectedAllowed" value="true"/> - <property name="publicMemberPattern" value="^serialVersionUID$"/> - </module> - <module name="ArrayTrailingComma"/> - <module name="AvoidInlineConditionals"> - <property name="severity" value="ignore"/> - <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/> - </module> - <module name="CovariantEquals"/> - <module name="DeclarationOrder"/> - <module name="DefaultComesLast"/> - <module name="EmptyStatement"/> - <module name="EqualsAvoidNull"/> - <module name="EqualsHashCode"/> - <module name="FallThrough"> - <property name="reliefPattern" value="fallthru|falls??through"/> - </module> - <module name="FinalLocalVariable"/> - <module name="HiddenField"> - <property name="tokens" value="PARAMETER_DEF, VARIABLE_DEF"/> - <property name="ignoreConstructorParameter" value="true"/> - <property name="ignoreSetter" value="true"/> - </module> - <module name="IllegalCatch"/> - <module name="IllegalInstantiation"> - <property name="classes" value="java.lang.Boolean"/> - </module> - <module name="IllegalThrows"/> - <module name="IllegalType"> - <property name="tokens" value="PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF"/> - <property name="illegalClassNames" value="java.util.GregorianCalendar, java.util.Hashtable, java.util.HashSet, java.util.HashMap, java.util.ArrayList, java.util.LinkedList, java.util.LinkedHashMap, java.util.LinkedHashSet, java.util.TreeSet, java.util.TreeMap, java.util.Vector"/> - <property name="format" value="XXX"/> - </module> - <module name="InnerAssignment"> - <property name="tokens" value="ASSIGN, BAND_ASSIGN, BOR_ASSIGN, BSR_ASSIGN, BXOR_ASSIGN, DIV_ASSIGN, MINUS_ASSIGN, MOD_ASSIGN, PLUS_ASSIGN, SL_ASSIGN, SR_ASSIGN, STAR_ASSIGN"/> - </module> - <module name="JUnitTestCase"/> - <module name="MissingCtor"/> - <module name="MissingSwitchDefault"/> - <module name="ModifiedControlVariable"/> - <module name="MultipleVariableDeclarations"/> - <module name="NestedForDepth"> - <property name="max" value="2"/> - </module> - <module name="NestedIfDepth"> - <property name="max" value="3"/> - </module> - <module name="NestedTryDepth"/> - <module name="NoClone"/> - <module name="NoFinalizer"/> - <module name="OneStatementPerLine"/> - <module name="PackageDeclaration"/> - <module name="ParameterAssignment"/> - <module name="RedundantThrows"> - <property name="allowUnchecked" value="true"/> - </module> - <module name="RequireThis"/> - <module name="ReturnCount"/> - <module name="SimplifyBooleanExpression"/> - <module name="SimplifyBooleanReturn"/> - <module name="StringLiteralEquality"/> - <module name="SuperClone"/> - <module name="SuperFinalize"/> - <module name="UnnecessaryParentheses"/> - <module name="AvoidStarImport"/> - <module name="AvoidStaticImport"/> - <module name="IllegalImport"> - <property name="illegalPkgs" value="org.apache.commons.logging"/> - </module> - <module name="ImportOrder"> - <property name="groups" value="java,javax,junit,org,com,kieker,org.primefaces,org.eclipse"/> - <property name="separated" value="true"/> - </module> - <module name="RedundantImport"/> - <module name="UnusedImports"/> - <module name="JavadocMethod"> - <property name="severity" value="info"/> - <property name="tokens" value="METHOD_DEF, CTOR_DEF"/> - </module> - <module name="JavadocStyle"> - <property name="severity" value="info"/> - <property name="tokens" value="INTERFACE_DEF, CLASS_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/> - </module> - <module name="JavadocType"> - <property name="severity" value="info"/> - <property name="tokens" value="INTERFACE_DEF, CLASS_DEF"/> - </module> - <module name="JavadocType"> - <property name="severity" value="warning"/> - <property name="scope" value="package"/> - <property name="authorFormat" value="\S"/> - </module> - <module name="JavadocVariable"> - <property name="severity" value="info"/> - <property name="scope" value="package"/> - </module> - <module name="BooleanExpressionComplexity"> - <property name="severity" value="info"/> - <property name="tokens" value="LAND, BAND, LOR, BOR, BXOR"/> - </module> - <module name="CyclomaticComplexity"> - <property name="severity" value="info"/> - </module> - <module name="JavaNCSS"> - <property name="severity" value="info"/> - </module> - <module name="NPathComplexity"> - <property name="severity" value="info"/> - </module> - <module name="ArrayTypeStyle"/> - <module name="FinalParameters"> - <property name="tokens" value="METHOD_DEF, CTOR_DEF"/> - </module> - <module name="Indentation"> - <property name="severity" value="info"/> - <property name="caseIndent" value="0"/> - </module> - <module name="OuterTypeFilename"/> - <module name="TodoComment"> - <property name="format" value="TODO"/> - </module> - <module name="UncommentedMain"> - <property name="severity" value="info"/> - <property name="excludedClasses" value="Main$"/> - </module> - <module name="UpperEll"/> - <module name="ModifierOrder"/> - <module name="AbstractClassName"> - <property name="format" value="^Abstract.*$"/> - </module> - <module name="ClassTypeParameterName"/> - <module name="ConstantName"/> - <module name="LocalFinalVariableName"/> - <module name="LocalVariableName"> - <property name="tokens" value="PARAMETER_DEF"/> - </module> - <module name="MemberName"/> - <module name="MethodName"/> - <module name="MethodTypeParameterName"/> - <module name="PackageName"/> - <module name="ParameterName"/> - <module name="StaticVariableName"/> - <module name="TypeName"> - <property name="tokens" value="CLASS_DEF"/> - </module> - <module name="TypeName"> - <property name="format" value="^I[A-Z][a-zA-Z0-9]*$"/> - <property name="tokens" value="INTERFACE_DEF"/> - </module> - <module name="AnonInnerLength"> - <property name="severity" value="info"/> - </module> - <module name="LineLength"> - <property name="severity" value="info"/> - <property name="max" value="165"/> + + <!-- KIEKER default is warning instead of error --> + <property name="severity" value="error"/> + + <!-- KIEKER Filter --> + <module name="SuppressWithNearbyCommentFilter"> + <property name="commentFormat" value="NOCS"/> + <property name="checkFormat" value=".*"/> + <property name="influenceFormat" value="0"/> </module> - <module name="MethodCount"> - <property name="severity" value="info"/> + + <!-- + If you set the basedir property below, then all reported file + names will be relative to the specified directory. See + http://checkstyle.sourceforge.net/5.x/config.html#Checker + + <property name="basedir" value="${basedir}"/> + <property name="localeCountry" value=""/> JVM locale country + <property name="localeLanguage" value=""/> JVM locale language + <property name="charset" value=""/> JVM file.encoding property + !--> + + + <!-- + !________________________________________________________________________________________ + ! + ! D U P L I C A T E S + !________________________________________________________________________________________ + !--> + <!-- Performs a line-by-line comparison of all code lines and reports duplicate code. !--> + <!-- See http://checkstyle.sf.net/config_duplicates.html !--> + <!-- KIEKER Does not work with headers!! + <module name="StrictDuplicateCode"> + <property name="min" value="12"/> + <property name="fileExtensions" value=""/> </module> - <module name="MethodLength"> - <property name="severity" value="info"/> - <property name="tokens" value="METHOD_DEF, CTOR_DEF"/> + --> + + <!-- + !________________________________________________________________________________________ + ! + ! H E A D E R S + !________________________________________________________________________________________ + !--> + <!-- NOTE: You may enable zero or one of these header checks, but not both. !--> + + <!-- Checks that a source file begins with a specified header. !--> + <!-- See http://checkstyle.sf.net/config_header.html !--> + <!-- KIEKER !--> + <module name="Header"> + <!--<property name="headerFile" value=""/>--> + <!--<property name="charset" value=""/>--> + <property name="header" value="/***************************************************************************\n * Copyright 2013 Kieker Project (http://kieker-monitoring.net)\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ***************************************************************************/\n"/> + <property name="ignoreLines" value="2"/> + <property name="fileExtensions" value="java"/> </module> - <module name="OuterTypeNumber"> - <property name="max" value="2"/> + + <!-- Checks the header of a source file against a header file that contains a regular expression !--> + <!-- for each line of the source header. !--> + <!-- See http://checkstyle.sf.net/config_header.html !--> + <!-- Default: OFF + <module name="RegexpHeader"> + <property name="headerFile" value=""/> + <property name="charset" value=""/> + <property name="header" value=""/> + <property name="multiLines" value=""/> + <property name="fileExtensions" value=""/> </module> - <module name="EmptyForInitializerPad"/> - <module name="EmptyForIteratorPad"/> - <module name="GenericWhitespace"/> - <module name="MethodParamPad"> - <property name="tokens" value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF, SUPER_CTOR_CALL "/> + !--> + + <!-- + !________________________________________________________________________________________ + ! + ! J A V A D O C S + !________________________________________________________________________________________ + !--> + <!-- Checks that each Java package has a Javadoc file used for commenting. !--> + <!-- See http://checkstyle.sourceforge.net/config_javadoc.html#JavadocPackage !--> + <!-- KIEKER: OFF + <module name="JavadocPackage"> + <property name="severity" value="info"/> + <property name="allowLegacy" value="false"/> </module> - <module name="NoWhitespaceAfter"> - <property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS"/> + !--> + + <!-- + !________________________________________________________________________________________ + ! + ! R E G E X P + !________________________________________________________________________________________ + !--> + <!-- A check for detecting that matches across multiple lines. Works with any file type. !--> + <!-- See http://checkstyle.sourceforge.net/config_regexp.html#RegexpMultiline !--> + <!-- Default: OFF + <module name="RegexpMultiline"> + <property name="format" value=""/> + <property name="message" value=""/> + <property name="ignoreCase" value="false"/> + <property name="minimum" value="0"/> + <property name="maximum" value="0"/> + <property name="fileExtensions" value=""/> </module> - <module name="NoWhitespaceBefore"> - <property name="tokens" value="SEMI, POST_DEC, POST_INC"/> + !--> + + <!-- A check for detecting single lines that match a supplied regular expression. Works with any file type. !--> + <!-- See http://checkstyle.sourceforge.net/config_regexp.html#RegexpSingleline !--> + <!-- Default: OFF + <module name="RegexpSingleline"> + <property name="format" value="\s+$"/> + <property name="message" value=""/> + <property name="ignoreCase" value="false"/> + <property name="minimum" value="0"/> + <property name="maximum" value="0"/> + <property name="fileExtensions" value=""/> </module> - <module name="OperatorWrap"> - <property name="tokens" value="BAND, BOR, BSR, BXOR, COLON, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR"/> + !--> + + <!-- + !________________________________________________________________________________________ + ! + ! M I S C E L L A N E O U S + !________________________________________________________________________________________ + !--> + <!-- Checks whether files end with a new line. !--> + <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile !--> + <module name="NewlineAtEndOfFile"> + <property name="lineSeparator" value="system"/> + <property name="fileExtensions" value="*.*"/> </module> - <module name="ParenPad"> - <property name="tokens" value="CTOR_CALL, LPAREN, METHOD_CALL, RPAREN, SUPER_CTOR_CALL"/> + + <!-- Checks that property files contain the same keys. !--> + <!-- See http://checkstyle.sf.net/config_misc.html#Translation !--> + <module name="Translation"> + <property name="fileExtensions" value="properties"/> </module> - <module name="TypecastParenPad"> - <property name="tokens" value="TYPECAST, RPAREN"/> + + + <!-- + !________________________________________________________________________________________ + ! + ! S I Z E V I O L A T I O N S + !________________________________________________________________________________________ + !--> + <!-- Checks for long source files. !--> + <!-- See http://checkstyle.sf.net/config_sizes.html !--> + <module name="FileLength"> + <property name="max" value="2000"/> + <property name="fileExtensions" value="java"/> </module> - <module name="WhitespaceAfter"> - <property name="tokens" value="COMMA, SEMI, TYPECAST"/> + + + <!-- + !________________________________________________________________________________________ + ! + ! W H I T E S P A C E + !________________________________________________________________________________________ + !--> + <!-- Checks that there are no tab characters ('\t') in the source code. !--> + <!-- See http://checkstyle.sourceforge.net/config_whitespace.html#FileTabCharacter !--> + <!-- KIEKER we use TABs + <module name="FileTabCharacter"> + <property name="eachLine" value="false"/> + <property name="fileExtensions" value=""/> </module> - <module name="WhitespaceAround"> - <property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND, LE, LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN, STAR, STAR_ASSIGN"/> - <property name="allowEmptyConstructors" value="true"/> - <property name="allowEmptyMethods" value="true"/> + --> + + <module name="TreeWalker"> + <!-- KIEKER --> + <property name="tabWidth" value="4"/> + <!-- KIEKER --> + <!-- + <module name="kieker.test.common.cs.AnalysisComponentConstructorCheck"> + <property name="ignoreAbstractClasses" value="true"/> + </module> + --> + <!-- KIEKER --> + <!-- + <module name="kieker.test.common.cs.MonitoringRecordFactoryConventionCheck"> + <property name="ignoreAbstractClasses" value="true"/> + </module> + --> + <!-- KIEKER --> + <!-- + <module name="kieker.test.common.cs.JUnitTestsExtendingAbstractKiekerTestCheck"> + <property name="ignoreAbstractClasses" value="true"/> + </module> + --> + <!-- KIEKER --> + <!-- + <module name="kieker.test.common.cs.MissingSinceTagCheck"> + </module> + --> + <!-- KIEKER --> + <!-- + <module name="kieker.test.common.cs.NotAllowedSinceTagCheck"> + </module> + --> + + <module name="FileContentsHolder"/> + + <!-- + !________________________________________________________________________________________ + ! + ! A N N O T A T I O N S + !________________________________________________________________________________________ + !--> + <!-- This check controls the usage style of annotations. !--> + <!-- See http://checkstyle.sourceforge.net/config_annotation.html#AnnotationUseStyle !--> + <module name ="AnnotationUseStyle"> + <property name="elementStyle" value="compact_no_array"/> + <property name="closingParens" value="never"/> + <property name="trailingArrayComma" value="never"/> + </module> + + <!-- Verifies that both the java.lang.Deprecated import is present and the @deprecated Javadoc tag is present when either is present. !--> + <!-- See http://checkstyle.sourceforge.net/config_annotation.html#MissingDeprecated !--> + <!-- KIEKER --> + <module name="MissingDeprecated"> + <property name="severity" value="info"/> + </module> + + <!-- Verifies that the java.lang.Override annotation is present when the {@inheritDoc} javadoc tag is present. !--> + <!-- See http://checkstyle.sourceforge.net/config_annotation.html#MissingOverride !--> + <!-- problems with Java 1.5 + <module name="MissingOverride"> + <property name="javaFiveCompatibility" value="false"/> + </module> + --> + + <!-- This check makes sure that all package annotations are in the package-info.java file. !--> + <!-- See http://checkstyle.sourceforge.net/config_annotation.html#PackageAnnotation !--> + <module name="PackageAnnotation"/> + + <!-- This check allows you to specify what warnings that SuppressWarnings is not allowed to suppress. !--> + <!-- You can also specify a list of TokenTypes that the configured warning(s) cannot be suppressed on. !--> + <!-- See http://checkstyle.sourceforge.net/config_annotation.html#SuppressWarnings !--> + <module name="SuppressWarnings"> + <property name="format" value="^$|^\s+$"/> + <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, + ANNOTATION_FIELD_DEF, ENUM_CONSTANT_DEF, PARAMETER_DEF, + VARIABLE_DEF, METHOD_DEF, CTOR_DEF"/> + </module> + + + <!-- + !________________________________________________________________________________________ + ! + ! B L O C K S + !________________________________________________________________________________________ + !--> + <!-- Finds nested blocks, i.e. blocks that are used freely in the code. !--> + <!-- See http://checkstyle.sf.net/config_blocks.html !--> + <!-- KIEKER allowInSwitchCase !--> + <module name="AvoidNestedBlocks"> + <property name="allowInSwitchCase" value="true"/> + </module> + + <!-- Checks for empty blocks. !--> + <!-- See http://checkstyle.sf.net/config_blocks.html !--> + <!-- KIEKER removed LITERAL_CATCH !--> + <module name="EmptyBlock"> + <property name="option" value="stmt"/> + <property name="tokens" value="LITERAL_DO, + LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF, LITERAL_FOR, + LITERAL_TRY, LITERAL_WHILE, INSTANCE_INIT, STATIC_INIT"/> + </module> + + <!-- Checks for the placement of left curly braces ('{') for code blocks. !--> + <!-- See http://checkstyle.sf.net/config_blocks.html !--> + <module name="LeftCurly"> + <property name="option" value="eol"/> + <property name="maxLineLength" value="165"/> + <property name="tokens" value="CLASS_DEF, CTOR_DEF, + INTERFACE_DEF, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, + LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_SWITCH, + LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, + METHOD_DEF"/> + </module> + + <!-- Checks for braces around code blocks. !--> + <!-- See http://checkstyle.sf.net/config_blocks.html !--> + <module name="NeedBraces"> + <property name="tokens" value="LITERAL_DO, LITERAL_ELSE, LITERAL_IF, LITERAL_FOR, LITERAL_WHILE"/> + </module> + + <!-- Checks the placement of right curly braces ('}') for else, try, and catch tokens. !--> + <!-- See http://checkstyle.sf.net/config_blocks.html !--> + <module name="RightCurly"> + <property name="option" value="same"/> + <property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE"/> + <property name="shouldStartLine" value="true"/> + </module> + + + <!-- + !________________________________________________________________________________________ + ! + ! C L A S S D E S I G N + !________________________________________________________________________________________ + !--> + <!-- Checks that classes are designed for extension. !--> + <!-- See http://checkstyle.sf.net/config_design.html !--> + <!-- Default: OFF + <module name="DesignForExtension"/> + !--> + + <!-- Checks that a class which has only private constructors is declared as final. !--> + <!-- See http://checkstyle.sf.net/config_design.html !--> + <module name="FinalClass"/> + + <!-- Make sure that utility classes (classes that contain only static methods) do not have a public constructor. !--> + <!-- See http://checkstyle.sf.net/config_design.html !--> + <module name="HideUtilityClassConstructor"/> + + <!-- Check nested (internal) classes/interfaces are declared at the bottom of the class after all method and field declarations. !--> + <!-- See http://checkstyle.sourceforge.net/config_design.html#InnerTypeLast !--> + <module name="InnerTypeLast"/> + + <!-- Implements Bloch, Effective Java, Item 17 - Use Interfaces only to define types. !--> + <!-- See http://checkstyle.sf.net/config_design.html !--> + <module name="InterfaceIsType"> + <property name="allowMarkerInterfaces" value="true"/> + </module> + + <!-- Ensures that exceptions (defined as any class name conforming to some regular expression) are immutable. !--> + <!-- That is, have only final fields. !--> + <!-- See http://checkstyle.sf.net/config_design.html !--> + <module name="MutableException"> + <property name="format" value="^.*Exception$|^.*Error$"/> + </module> + + <!-- Restricts throws statements to a specified count. !--> + <!-- See http://checkstyle.sf.net/config_design.html !--> + <!-- KIEKER off + <module name="ThrowsCount"> + <property name="max" value="1"/> + </module> + !--> + + <!-- Checks visibility of class members. !--> + <!-- See http://checkstyle.sf.net/config_design.html !--> + <module name="VisibilityModifier"> + <property name="packageAllowed" value="false"/> + <property name="protectedAllowed" value="true"/> + <property name="publicMemberPattern" value="^serialVersionUID$"/> + </module> + + + <!-- + !________________________________________________________________________________________ + ! + ! C O D I N G + !________________________________________________________________________________________ + !--> + <!-- Checks that array initialization contains a trailing comma. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="ArrayTrailingComma"/> + + <!-- Detects inline conditionals. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="AvoidInlineConditionals"/> + + <!-- Checks that classes that define a covariant equals() method also override method equals(java.lang.Object). !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="CovariantEquals"/> + + <!-- Checks declaration order according to Code Conventions for the Java Programming Language. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="DeclarationOrder"> + <property name="ignoreConstructors" value="false"/> + <property name="ignoreMethods" value="false"/> + <property name="ignoreModifiers" value="false"/> + </module> + + <!-- Check that the default is after all the cases in a switch statement. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="DefaultComesLast"/> + + <!-- The "double-checked locking" idiom (DCL) tries to avoid the runtime cost of synchronization. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!--<module name="DoubleCheckedLocking"/>--> + + <!-- Detects empty statements (standalone ;). !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="EmptyStatement"/> + + <!-- Checks that any combination of String literals with optional assignment is on the left side of an equals() comparison. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#EqualsAvoidNull !--> + <module name="EqualsAvoidNull"/> + + <!-- Checks that classes that override equals() also override hashCode(). !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="EqualsHashCode"/> + + <!-- Checks if any class or object member explicitly initialized to default for its type value. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!-- KIEKER off + <module name="ExplicitInitialization"/> + !--> + + <!-- Checks for fall through in switch statements Finds locations where a case contains Java code ... !--> + <!-- but lacks a break, return, throw or continue statement. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="FallThrough"> + <property name="checkLastCaseGroup" value="false"/> + <property name="reliefPattern" value="fallthru|falls??through"/> + </module> + + <!-- Checks that local variables that never have their values changed are declared final. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="FinalLocalVariable"> + <property name="tokens" value="VARIABLE_DEF"/> + </module> + + <!-- Checks that a local variable or a parameter does not shadow a field that is defined in the same class. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!-- KIEKER ignoreConstructorParameter, ignoreSetter --> + <module name="HiddenField"> + <property name="tokens" value="PARAMETER_DEF, VARIABLE_DEF"/> + <!-- + <property name="ignoreFormat" value=""/> + !--> + <property name="ignoreConstructorParameter" value="true"/> + <property name="ignoreSetter" value="true"/> + <property name="ignoreAbstractMethods" value="false"/> + </module> + + <!-- Catching java.lang.Exception, java.lang.Error or java.lang.RuntimeException is almost never acceptable. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="IllegalCatch"> + <property name="illegalClassNames" value="java.lang.Exception, java.lang.Throwable, java.lang.RuntimeException"/> + </module> + + <!-- Checks for illegal instantiations where a factory method is preferred. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!-- KIEKER on for ??? !--> + <module name="IllegalInstantiation"> + <property name="classes" value="java.lang.Boolean"/> + </module> + + <!-- This check can be used to ensure that types are not declared to be thrown. !--> + <!-- Declaring to throw java.lang.Error or java.lang.RuntimeException is almost never acceptable. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#IllegalThrows !--> + <module name="IllegalThrows"> + <property name="illegalClassNames" value="java.lang.Throwable, java.lang.Error, java.lang.RuntimeException"/> + </module> + + <!-- Checks for illegal tokens. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!-- KIEKER off + <module name="IllegalToken"> + <property name="tokens" value="LITERAL_SWITCH, POST_INC, POST_DEC"/> + </module> + !--> + + <!-- Checks for illegal token text. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!-- Default: OFF + <module name="IllegalTokenText"> + <property name="tokens" value=""/> + <property name="format" value=""/> + <property name="ignoreCase" value="false"/> + <property name="message" value=""/> + </module> + !--> + + <!-- Checks that particular classes are never used as types in variable declarations, return values or parameters. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!-- KIEKER removed format value="^(.*[\\.])?Abstract.*$" !--> + <module name="IllegalType"> + <property name="tokens" value="PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF"/> + <property name="illegalClassNames" value="java.util.GregorianCalendar, java.util.Hashtable, + java.util.HashSet, java.util.HashMap, java.util.ArrayList, + java.util.LinkedList, java.util.LinkedHashMap, + java.util.LinkedHashSet, java.util.TreeSet, + java.util.TreeMap, java.util.Vector"/> + <property name="legalAbstractClassNames" value=""/> + <property name="ignoredMethodNames" value="getInitialContext, getEnvironment"/> + <property name="format" value="XXX"/> + </module> + + <!-- Checks for assignments in subexpressions, such as in String s = Integer.toString(i = 2);. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="InnerAssignment"> + <property name="tokens" value="ASSIGN, BAND_ASSIGN, BOR_ASSIGN, BSR_ASSIGN, BXOR_ASSIGN, + DIV_ASSIGN, MINUS_ASSIGN, MOD_ASSIGN, PLUS_ASSIGN, SL_ASSIGN, + SR_ASSIGN, STAR_ASSIGN"/> + </module> + + <!-- Ensures that the setUp(), tearDown()methods are named correctly, have no arguments, !--> + <!-- return void and are either public or protected. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="JUnitTestCase"/> + + <!-- Checks that there are no "magic numbers", where a magic number is a numeric literal !--> + <!-- that is not defined as a constant. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <!-- deactivated for Kieker + <module name="MagicNumber"> + <property name="tokens" value="NUM_DOUBLE, NUM_FLOAT, NUM_INT, NUM_LONG"/> + <property name="ignoreNumbers" value="-1, 0, 1, 2"/> + <property name="ignoreHashCodeMethod" value="false"/> + </module> + !--> + + <!-- Checks that classes (except abtract one) define a ctor and don't rely on the default one. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="MissingCtor"/> + + <!-- Checks that switch statement has "default" clause. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="MissingSwitchDefault"/> + + <!-- Check for ensuring that for loop control variables are not modified inside the for block. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#ModifiedControlVariable !--> + <module name="ModifiedControlVariable"/> + + <!-- Checks for multiple occurrences of the same string literal within a single file. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#MultipleStringLiterals !--> + <!-- KIEKER off for now + <module name="MultipleStringLiterals"> + <property name="allowedDuplicates" value="1"/> + <property name="ignoreStringsRegexp" value='^""$'/> + <property name="ignoreOccurrenceContext" value="ANNOTATION"/> + </module> + !--> + + <!-- Checks that each variable declaration is in its own statement and on its own line. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="MultipleVariableDeclarations"/> + + <!-- Restricts nested for blocks to a specified depth. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#NestedForDepth !--> + <module name="NestedForDepth"> + <property name="max" value="2"/> + </module> + + <!-- Restricts nested if-else blocks to a specified depth. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="NestedIfDepth"> + <property name="max" value="3"/> + </module> + + <!-- Restricts nested try-catch blocks to a specified depth. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="NestedTryDepth"> + <property name="max" value="1"/> + </module> + + <!-- Checks that the clone method is not overridden from the Object class. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#NoClone !--> + <module name="NoClone"/> + + <!-- Verifies there are no finalize() methods defined in a class. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#NoFinalizer !--> + <module name="NoFinalizer"/> + + <!-- Checks there is only one statement per line. !--> + <!-- See http://checkstyle.sourceforge.net/config_coding.html#OneStatementPerLine !--> + <module name="OneStatementPerLine"/> + + <!-- Ensure a class has a package declaration. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="PackageDeclaration"> + <property name="ignoreDirectoryName" value="false"/> + </module> + + <!-- Disallow assignment of parameters. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="ParameterAssignment"/> + + <!-- Checks for redundant exceptions declared in throws clause such as duplicates, !--> + <!-- unchecked exceptions or subclasses of another declared exception. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="RedundantThrows"> + <property name="allowUnchecked" value="true"/> + <property name="allowSubclasses" value="false"/> + <property name="logLoadErrors" value="true"/> + <property name="suppressLoadErrors" value="false"/> + </module> + + <!-- Checks that code doesn't rely on the "this." default. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="RequireThis"> + <property name="checkFields" value="true"/> + <property name="checkMethods" value="true"/> + </module> + + <!-- Restrict the number of return statements. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="ReturnCount"> + <property name="max" value="2"/> + <property name="format" value=""/> + </module> + + <!-- Checks for overly complicated boolean expressions. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + + <module name="SimplifyBooleanExpression"/> + + <!-- Checks for overly complicated boolean return statements. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="SimplifyBooleanReturn"/> + + <!-- Checks that string literals are not used with == or !=. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="StringLiteralEquality"/> + + <!-- Checks that an overriding clone() method invokes super.clone(). !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="SuperClone"/> + + <!-- Checks that an overriding finalize() method invokes super.finalize(). !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="SuperFinalize"/> + + <!-- Checks for the use of unnecessary parentheses. !--> + <!-- See http://checkstyle.sf.net/config_coding.html !--> + <module name="UnnecessaryParentheses"/> + + + <!-- + !________________________________________________________________________________________ + ! + ! I M P O R T S + !________________________________________________________________________________________ + !--> + <!-- Checks that there are no import statements that use the * notation. !--> + <!-- See http://checkstyle.sf.net/config_import.html !--> + <module name="AvoidStarImport"> + <property name="excludes" value=""/> + <property name="allowClassImports" value="false"/> + <property name="allowStaticMemberImports" value="false"/> + </module> + + <!-- Checks that there are no static import statements. !--> + <!-- See http://checkstyle.sourceforge.net/config_imports.html#AvoidStaticImport !--> + <module name="AvoidStaticImport"> + <property name="excludes" value=""/> + </module> + + <!-- Checks for imports from a set of illegal packages. !--> + <!-- See http://checkstyle.sf.net/config_import.html !--> + <module name="IllegalImport"> + <property name="illegalPkgs" value="junit.framework"/> + <property name="illegalPkgs" value="sun"/> + <property name="illegalPkgs" value="org.apache.commons.logging"/> + <property name="illegalPkgs" value="java.util.logging"/> + </module> + + <!-- Controls what can be imported in each package. Useful for ensuring that application layering rules !--> + <!-- are not violated, especially on large projects. !--> + <!-- See http://checkstyle.sourceforge.net/config_imports.html#ImportControl !--> + <!-- Default: OFF + <module name="ImportControl"> + <property name="file" value=""/> + <property name="url" value=""/> + </module> + !--> + + <!-- Checks the ordering/grouping of imports. !--> + <!-- See http://checkstyle.sf.net/config_import.html !--> + <module name="ImportOrder"> + <property name="option" value="under"/> + <property name="groups" value="java,javax,junit,org,com,kieker,kieker,org.primefaces,org.eclipse"/> + <property name="ordered" value="true"/> + <property name="separated" value="true"/> + <property name="caseSensitive" value="true"/> + </module> + + <!-- Checks for redundant import statements. !--> + <!-- See http://checkstyle.sf.net/config_import.html !--> + <module name="RedundantImport"/> + + <!-- Checks for unused import statements. !--> + <!-- See http://checkstyle.sf.net/config_import.html !--> + <module name="UnusedImports"/> + + + <!-- + !________________________________________________________________________________________ + ! + ! J A V A D O C S + !________________________________________________________________________________________ + !--> + <!-- Checks to ensure that the javadoc tags exist (if required) !--> + <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocMethod !--> + <!-- KIEKER: adapted !--> + <module name="JavadocMethod"> + <property name="severity" value="info"/> + <property name="scope" value="protected"/> + <!-- + <property name="excludeScope" value=""/> + !--> + <property name="allowUndeclaredRTE" value="false"/> + <property name="allowThrowsTagsForSubclasses" value="false"/> + <property name="allowMissingParamTags" value="false"/> + <property name="allowMissingThrowsTags" value="false"/> + <property name="allowMissingReturnTag" value="false"/> + <property name="allowMissingJavadoc" value="false"/> + <property name="allowMissingPropertyJavadoc" value="true"/> + <property name="logLoadErrors" value="true"/> + <property name="suppressLoadErrors" value="false"/> + <property name="tokens" value="METHOD_DEF, CTOR_DEF"/> + </module> + + <!-- Validates Javadoc comments to help ensure they are well formed. !--> + <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocStyle !--> + <module name="JavadocStyle"> + <property name="severity" value="info"/> + <property name="scope" value="private"/> + <!-- + <property name="excludeScope" value=""/> + !--> + <property name="checkFirstSentence" value="true"/> +<!--TODO: <property name="endOfSentenceFormat" value="([.?!][ \t\n\r\f<])|([.?!]$)"/> !--> + <property name="checkEmptyJavadoc" value="false"/> + <property name="checkHtml" value="false"/> + <property name="tokens" value="INTERFACE_DEF, CLASS_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/> + </module> + + <!-- Checks Javadoc comments for class and interface definitions. !--> + <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocType !--> + <module name="JavadocType"> + <property name="severity" value="info"/> + <property name="scope" value="private"/> + <!--<property name="excludeScope" value=""/>!--> + <property name="authorFormat" value=""/> + <!--<property name="versionFormat" value=""/>!--> + <property name="allowMissingParamTags" value="false"/> + <property name="allowUnknownTags" value="false"/> + <property name="tokens" value="INTERFACE_DEF, CLASS_DEF"/> + </module> + + <module name="JavadocType"> + <property name="severity" value="error"/> + <property name="scope" value="package"/> + <property name="authorFormat" value="\S"/> + </module> + + <!-- Checks that variables have Javadoc comments. !--> + <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocVariable !--> + <module name="JavadocVariable"> + <property name="severity" value="info"/> + <property name="scope" value="protected"/> + <!-- + <property name="excludeScope" value=""/> + !--> + </module> + + <!-- Outputs a JavaDoc tag as information. !--> + <!-- See http://checkstyle.sourceforge.net/config_javadoc.html#WriteTag !--> + <!-- KIEKER + <module name="WriteTag"> + <property name="severity" value="info"/> + <property name="tag" value=""/> + <property name="tagFormat" value=""/> + <property name="tagSeverity" value="info"/> + </module> + --> + + + <!-- + !________________________________________________________________________________________ + ! + ! M E T R I C S + !________________________________________________________________________________________ + !--> + <!-- Restrict the number of number of &&, || and ^ in an expression. !--> + <!-- See http://checkstyle.sf.net/config_metrics.html !--> + <!-- KIEKER Off --> + <!-- <module name="BooleanExpressionComplexity"> + <property name="severity" value="info"/> + <property name="max" value="3"/> + <property name="tokens" value="LAND, BAND, LOR, BOR, BXOR"/> + </module> --> + + <!-- This metric measures the number of instantiations of other classes within the given class. !--> + <!-- See http://checkstyle.sf.net/config_metrics.html !--> + <!-- KIEKER Off --> + <!-- <module name="ClassDataAbstractionCoupling"> + <property name="severity" value="info"/> + <property name="max" value="7"/> + </module> --> + + <!-- The number of other classes a given class relies on. !--> + <!-- See http://checkstyle.sf.net/config_metrics.html !--> + <!-- KIEKER Off --> + <!--<module name="ClassFanOutComplexity"> + <property name="severity" value="info"/> + <property name="max" value="20"/> + </module> --> + + <!-- Checks cyclomatic complexity against a specified limit. !--> + <!-- See http://checkstyle.sf.net/config_metrics.html !--> + <module name="CyclomaticComplexity"> + <property name="severity" value="ignore"/> + <property name="max" value="10"/> + </module> + + <!-- Determines complexity of methods, classes and files by counting the Non Commenting Source Statements (NCSS). !--> + <!-- See http://checkstyle.sourceforge.net/config_metrics.html#JavaNCSS !--> + <!-- KIEKER Off --> + <!--<module name="JavaNCSS"> + <property name="severity" value="info"/> + <property name="methodMaximum" value="50"/> + <property name="classMaximum" value="1500"/> + <property name="fileMaximum" value="2000"/> + </module> --> + + <!-- The NPATH metric computes the number of possible execution paths through a function. !--> + <!-- See http://checkstyle.sf.net/config_metrics.html !--> + <!-- KIEKER Off --> + <!--<module name="NPathComplexity"> + <property name="severity" value="info"/> + <property name="max" value="200"/> + </module> --> + + + <!-- + !________________________________________________________________________________________ + ! + ! M I S C E L L A N E O U S + !________________________________________________________________________________________ + !--> + <!-- Checks the style of array type definitions. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <module name="ArrayTypeStyle"> + <property name="javaStyle" value="true"/> + </module> + + <!-- Checks for restricted tokens beneath other tokens. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <!-- Default: OFF + <module name="DescendantToken"> + <property name="tokens" value=""/> + <property name="limitedTokens" value=""/> + <property name="minimumDepth" value="0"/> + <property name="maximumDepth" value="java.lang.Integer.MAX_VALUE"/> + <property name="minimumNumber" value="0"/> + <property name="maximumNumber" value="java.lang.Integer.MAX_VALUE"/> + <property name="sumTokenCounts" value="false"/> + <property name="minimumMessage" value="descendant.token.min"/> + <property name="maximumMessage" value="descendant.token.max"/> + </module> + !--> + + <!-- Check that method/constructor parameters are final. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <module name="FinalParameters"> + <property name="tokens" value="METHOD_DEF, CTOR_DEF"/> + </module> + + <!-- A generic check for code problems - the user can search for any pattern. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <!-- Default: OFF + <module name="GenericIllegalRegexp"> + <property name="format" value="\S\s+$"/> + <property name="message" value="Line has trailing spaces."/> + <property name="ignoreCase" value="false"/> + <property name="ignoreComments" value="false"/> + </module> + !--> + + <!-- Checks correct indentation of Java Code. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <!-- KIEKER deactivated for now + <module name="Indentation"> + <property name="severity" value="info"/> + <property name="basicOffset" value="4"/> + <property name="braceAdjustment" value="0"/> + <property name="caseIndent" value="0"/> + </module> + !--> + + <!-- Checks that the outer type name and the file name match. !--> + <!-- See http://checkstyle.sourceforge.net/config_misc.html#OuterTypeFilename !--> + <module name="OuterTypeFilename"/> + + <!-- A check for TODO: comments. Actually it is a generic regular expression matcher on Java comments. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <!-- Kieker !--> + <module name="TodoComment"> + <property name="format" value="TODO"/> + <property name="severity" value="warning"/> + </module> + <module name="TodoComment"> + <property name="format" value="FIXME"/> + <property name="severity" value="error"/> + </module> + + <!-- The check to ensure that requires that comments be the only thing on a line. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <!-- KIEKER we use them + <module name="TrailingComment"> + <property name="format" value="^[\\s\\}\\);]*$"/> + <property name="legalComment" value=""/> + </module> + --> + + <!-- Checks for uncommented main() methods (debugging leftovers). !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <!-- KIEKER do not check for these + <module name="UncommentedMain"> + <property name="severity" value="info"/> + <property name="excludedClasses" value="Main$"/> + </module> + --> + + <!-- Checks that long constants are defined with an upper ell. That is 'L' and not 'l'. !--> + <!-- See http://checkstyle.sf.net/config_misc.html !--> + <module name="UpperEll"/> + + + <!-- + !________________________________________________________________________________________ + ! + ! M O D I F I E R S + !________________________________________________________________________________________ + !--> + <!-- Checks that the order of modifiers conforms to the suggestions in the Java Language specification, !--> + <!-- sections 8.1.1, 8.3.1 and 8.4.3. !--> + <!-- See http://checkstyle.sf.net/config_modifiers.html !--> + <module name="ModifierOrder"/> + + <!-- Checks that there are no redundant modifiers. !--> + <!-- See http://checkstyle.sf.net/config_modifiers.html !--> + <!-- KIEKER off + <module name="RedundantModifier"> + <property name="tokens" value="METHOD_DEF, VARIABLE_DEF, ANNOTATION_FIELD_DEF"/> + </module> + !--> + + <!-- + !________________________________________________________________________________________ + ! + ! N A M I N G C O N V E N T I O N S + !________________________________________________________________________________________ + !--> + <!-- Checks for abstract class name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <!-- KIEKER removed |^.*Factory$ --> + <module name="AbstractClassName"> + <property name="format" value="^Abstract.*$"/> + <property name="ignoreModifier" value="false"/> + <property name="ignoreName" value="false"/> + </module> + + <!-- Checks for class type parameter name naming conventions. !--> + <!-- See http://checkstyle.sourceforge.net/config_naming.html#ClassTypeParameterName !--> + <module name="ClassTypeParameterName"> + <property name="format" value="^[A-Z]$"/> + </module> + + <!-- Checks for constant name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="ConstantName"> + <property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"/> + <property name="applyToPublic" value="true"/> + <property name="applyToProtected" value="true"/> + <property name="applyToPackage" value="true"/> + <property name="applyToPrivate" value="true"/> + </module> + + <!-- Checks for local final variable name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="LocalFinalVariableName"> + <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> + <property name="tokens" value="VARIABLE_DEF, PARAMETER_DEF"/> + </module> + + <!-- Checks for local variable name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="LocalVariableName"> + <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> + <property name="tokens" value="PARAMETER_DEF"/> + </module> + + <!-- Checks for member variable name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="MemberName"> + <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> + <property name="applyToPublic" value="true"/> + <property name="applyToProtected" value="true"/> + <property name="applyToPackage" value="true"/> + <property name="applyToPrivate" value="true"/> + </module> + + <!-- Checks for method name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="MethodName"> + <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> + </module> + + <!-- Checks for method type parameter name naming conventions. !--> + <!-- See http://checkstyle.sourceforge.net/config_naming.html#MethodTypeParameterName !--> + <module name="MethodTypeParameterName"> + <property name="format" value="^[A-Z]$"/> + </module> + + <!-- Checks for package name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="PackageName"> + <property name="format" value="^[a-z]+(\.[a-zA-Z_][a-zA-Z0-9_]*)*$"/> + </module> + + <!-- Checks for parameter name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="ParameterName"> + <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> + </module> + + <!-- Checks for static variable name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <module name="StaticVariableName"> + <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> + <property name="applyToPublic" value="true"/> + <property name="applyToProtected" value="true"/> + <property name="applyToPackage" value="true"/> + <property name="applyToPrivate" value="true"/> + </module> + + <!-- Checks for type name naming conventions. !--> + <!-- See http://checkstyle.sf.net/config_naming.html !--> + <!-- KIEKER: modded --> + <module name="TypeName"> + <property name="format" value="^[A-Z][a-zA-Z0-9]*$"/> + <property name="tokens" value="CLASS_DEF"/> + <property name="applyToPublic" value="true"/> + <property name="applyToProtected" value="true"/> + <property name="applyToPackage" value="true"/> + <property name="applyToPrivate" value="true"/> + </module> + + <module name="TypeName"> + <property name="format" value="^I[A-Z][a-zA-Z0-9]*$"/> + <property name="tokens" value="INTERFACE_DEF"/> + <property name="applyToPublic" value="true"/> + <property name="applyToProtected" value="true"/> + <property name="applyToPackage" value="true"/> + <property name="applyToPrivate" value="true"/> + </module> + + + <!-- + !________________________________________________________________________________________ + ! + ! R E G E X P + !________________________________________________________________________________________ + !--> + <!-- A check that makes sure that a specified pattern exists, exists less than a set number of times, !--> + <!-- or does not exist in the file. !--> + <!-- See http://checkstyle.sourceforge.net/config_misc.html#Regexp !--> + <!-- Default: OFF + <module name="Regexp"> + <property name="format" value=""/> + <property name="message" value=""/> + <property name="illegalPattern" value="false"/> + <property name="duplicateLimit" value="-1"/> + <property name="errorLimit" value="100"/> + <property name="ignoreComments" value="false"/> + </module> + !--> + + <!-- This class is variation on RegexpSingleline for detecting single lines that match a !--> + <!-- supplied regular expression in Java files. It supports suppressing matches in Java comments. !--> + <!-- See http://checkstyle.sourceforge.net/config_regexp.html#RegexpSinglelineJava !--> + <!-- Default: OFF + <module name="RegexpSinglelineJava"> + <property name="format" value=""/> + <property name="message" value=""/> + <property name="ignoreCase" value="false"/> + <property name="minimum" value="0"/> + <property name="maximum" value="0"/> + <property name="ignoreComments" value="false"/> + </module> + !--> + + <!-- + !________________________________________________________________________________________ + ! + ! S I Z E V I O L A T I O N S + !________________________________________________________________________________________ + !--> + <!-- Checks for long anonymous inner classes. !--> + <!-- See http://checkstyle.sf.net/config_sizes.html !--> + <!-- KIEKER Set to 50 instead of 20 --> + <module name="AnonInnerLength"> + <property name="severity" value="info"/> + <property name="max" value="50"/> + </module> + + <!-- Restricts the number of executable statements to a specified limit. !--> + <!-- See http://checkstyle.sf.net/config_sizes.html !--> + <!-- KIEKER off + <module name="ExecutableStatementCount"> + <property name="severity" value="info"/> + <property name="max" value="30"/> + <property name="tokens" value="CTOR_DEF, METHOD_DEF, INSTANCE_INIT, STATIC_INIT"/> + </module> + !--> + + <!-- See http://checkstyle.sf.net/config_sizes.html !--> + <!-- Checks for long lines. !--> + <module name="LineLength"> + <property name="severity" value="info"/> + <property name="ignorePattern" value="^$"/> + <property name="max" value="165"/> + </module> + + <!-- Checks the number of methods declared in each type. This includes the number of each scope !--> + <!-- (private, package, protected and public) as well as an overall total. !--> + <!-- See http://checkstyle.sourceforge.net/config_sizes.html#MethodCount !--> + <module name="MethodCount"> + <property name="severity" value="info"/> + <property name="maxTotal" value="100"/> + <property name="maxPrivate" value="100"/> + <property name="maxPackage" value="100"/> + <property name="maxProtected" value="100"/> + <property name="maxPublic" value="100"/> + </module> + + <!-- Checks for long methods and constructors. !--> + <!-- See http://checkstyle.sf.net/config_sizes.html !--> + <module name="MethodLength"> + <property name="severity" value="info"/> + <property name="max" value="150"/> + <property name="countEmpty" value="true"/> + <property name="tokens" value="METHOD_DEF, CTOR_DEF"/> + </module> + + <!-- Checks for the number of types declared at the outer (or root) level in a file. !--> + <!-- See http://checkstyle.sourceforge.net/config_sizes.html#OuterTypeNumber !--> + <!-- KIEKER 2 !--> + <module name="OuterTypeNumber"> + <property name="max" value="2"/> + </module> + + <!-- Checks the number of parameters of a method or constructor. !--> + <!-- See http://checkstyle.sf.net/config_sizes.html !--> + <!-- KIEKER off + <module name="ParameterNumber"> + <property name="severity" value="info"/> + <property name="max" value="7"/> + <property name="tokens" value="METHOD_DEF, CTOR_DEF"/> + </module> + !--> + + <!-- + !________________________________________________________________________________________ + ! + ! W H I T E S P A C E + !________________________________________________________________________________________ + !--> + <!-- Checks the padding of an empty for initializer. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="EmptyForInitializerPad"> + <property name="option" value="nospace"/> + </module> + + <!-- Checks the padding of an empty for iterator. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="EmptyForIteratorPad"> + <property name="option" value="nospace"/> + </module> + + <!-- Checks that the whitespace around the Generic tokens < and > is correct to the typical convention. !--> + <!-- See http://checkstyle.sourceforge.net/config_whitespace.html#GenericWhitespace !--> + <module name="GenericWhitespace"/> + + <!-- Checks the padding between the identifier of a method definition, !--> + <!-- constructor definition, method call, or constructor invocation; and the left parenthesis of the parameter list. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="MethodParamPad"> + <property name="allowLineBreaks" value="false"/> + <property name="option" value="nospace"/> + <property name="tokens" value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF, SUPER_CTOR_CALL "/> + </module> + + <!-- Checks that there is no whitespace after a token. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <!-- KIEKER removed ARRAY_INIT !--> + <module name="NoWhitespaceAfter"> + <property name="allowLineBreaks" value="true"/> + <property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS"/> + </module> + + <!-- Checks that there is no whitespace before a token. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="NoWhitespaceBefore"> + <property name="allowLineBreaks" value="false"/> + <property name="tokens" value="SEMI, POST_DEC, POST_INC"/> + </module> + + <!-- Checks the policy on how to wrap lines on operators. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="OperatorWrap"> + <property name="option" value="nl"/> + <property name="tokens" value="BAND, BOR, BSR, BXOR, COLON, DIV, + EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, + LOR, LT, MINUS, MOD, NOT_EQUAL, + PLUS, QUESTION, SL, SR, STAR"/> + </module> + + <!-- Checks the policy on the padding of parentheses. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="ParenPad"> + <property name="option" value="nospace"/> + <property name="tokens" value="CTOR_CALL, LPAREN, METHOD_CALL, RPAREN, SUPER_CTOR_CALL"/> + </module> + + <!-- Checks the policy on the padding of parentheses for typecasts. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="TypecastParenPad"> + <property name="option" value="nospace"/> + <property name="tokens" value="TYPECAST, RPAREN"/> + </module> + + <!-- Checks that a token is followed by whitespace. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="WhitespaceAfter"> + <property name="tokens" value="COMMA, SEMI, TYPECAST"/> + </module> + + <!-- Checks that a token is surrounded by whitespace. !--> + <!-- See http://checkstyle.sf.net/config_whitespace.html !--> + <module name="WhitespaceAround"> + <property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, + BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND, + LE, LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, + LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, + LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, + MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, + QUESTION, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN, STAR, STAR_ASSIGN"/> + <property name="allowEmptyConstructors" value="true"/> + <property name="allowEmptyMethods" value="true"/> + </module> + </module> - </module> - <module name="SuppressWithNearbyCommentFilter"> - <property name="commentFormat" value="NOCS"/> - </module> - <module name="Header"> - <property name="header" value="/***************************************************************************\n * Copyright 2013 Kieker Project (http://kieker-monitoring.net)\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ***************************************************************************/\n"/> - <property name="ignoreLines" value="2"/> - <property name="fileExtensions" value="java"/> - </module> - <module name="NewlineAtEndOfFile"> - <property name="fileExtensions" value="*.*"/> - </module> - <module name="Translation"/> - <module name="FileLength"/> + </module> diff --git a/Kieker.WebGUI/pom.xml b/Kieker.WebGUI/pom.xml index 773151f0d8a99770dc84f4ce59f982e0c2acc6b7..537bfd904d61261d402bb9472f0f3fff7ce99498 100644 --- a/Kieker.WebGUI/pom.xml +++ b/Kieker.WebGUI/pom.xml @@ -29,7 +29,7 @@ <klay.jar>klay_0.2.0.jar</klay.jar> <spring.version>3.1.2.RELEASE</spring.version> <slf4j.version>1.7.2</slf4j.version> - <primefaces.themes.version>1.0.8</primefaces.themes.version> + <primefaces.themes.version>1.0.9</primefaces.themes.version> </properties> <repositories> diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java index b22be75ad176cac5ab8abcaa4735d5e68a2c3a55..7ae88ec70da2747c73b8998799a9eafce1747922 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java @@ -54,197 +54,57 @@ import kieker.webgui.common.exception.ProjectLoadException; */ public final class ClassAndMethodContainer { - /** - * This is the logger, which will be used to log messages and exceptions for this class. - */ private static final Log LOG = LogFactory.getLog(ClassAndMethodContainer.class); - /** - * The exception which is used if something went wrong during loading. - */ private static final String MSG_LOAD_EXCEPTION = "An error occured while loading the classes and methods."; private Class<?> logImplWebguiLoggingClass; - /** - * This is the class equivalence of {@link AnalysisControllerWithMapping}. - */ private Class<?> analysisControllerWithMappingClass; - /** - * This is the class equivalence of {@link AnalysisController}. - */ private Class<?> analysisControllerClass; - /** - * This is the class equivalence of {@link AnalysisControllerThread}. - */ private Class<?> analysisControllerThreadClass; - /** - * This is the class equivalence of {@link AbstractRepository}. - */ private Class<?> abstractRepositoryClass; - /** - * This is the class equivalence of {@link AbstractPlugin}. - */ private Class<?> abstractPluginClass; - /** - * This is the class equivalence of {@link AbstractFilterPlugin}. - */ private Class<?> abstractFilterPluginClass; - /** - * This is the class equivalence of {@link AbstractRepository}. - */ private Class<?> abstractReaderPluginClass; - /** - * This is the class equivalence of {@link Plugin}. - */ private Class<? extends Annotation> pluginAnnotationClass; - /** - * This is the class equivalence of {@link Repository}. - */ private Class<? extends Annotation> repositoryAnnotationClass; - /** - * This is the class equivalence of {@link Property}. - */ private Class<? extends Annotation> propertyAnnotationClass; - /** - * This is the class equivalence of {@link OutputPort}. - */ private Class<? extends Annotation> outputPortAnnotationClass; - /** - * This is the class equivalence of {@link InputPort}. - */ private Class<? extends Annotation> inputPortAnnotationClass; - /** - * This is the class equivalence of {@link RepositoryPort}. - */ private Class<? extends Annotation> repositoryPortAnnotationClass; - /** - * This is the class equivalence of {@link Display}. - */ private Class<? extends Annotation> displayAnnotationClass; - /** - * This is the class equivalence of {@link Image}. - */ private Class<?> imageClass; - /** - * This is the class equivalence of {@link PlainText}. - */ private Class<?> plainTextClass; - /** - * This is the class equivalence of {@link HtmlText}. - */ private Class<?> htmlTextClass; - /** - * This is the description()-method of the class equivalence of {@link Plugin}. - */ + private Method pluginDescriptionMethod; - /** - * This is the description()-method of the class equivalence of {@link Repository}. - */ private Method repositoryDescriptionMethod; - /** - * This is the configuration()-method of the class equivalence of {@link Plugin}. - */ private Method pluginConfigurationMethod; - /** - * This is the description()-method of the class equivalence of {@link Repository}. - */ private Method repositoryConfigurationMethod; - /** - * This is the outputPorts()-method of the class equivalence of {@link Plugin}. - */ private Method pluginOutputPortsMethod; - /** - * This is the repositoryPorts()-method of the class equivalence of {@link Plugin}. - */ private Method pluginRepositoryPortsMethod; - /** - * This is the name()-method of the class equivalence of {@link Display}. - */ private Method displayNameMethod; - /** - * This is the name()-method of the class equivalence of {@link InputPort}. - */ private Method inputPortNameMethod; - /** - * This is the name()-method of the class equivalence of {@link OutputPort}. - */ private Method outputPortNameMethod; - /** - * This is the name()-method of the class equivalence of {@link RepositoryPort}. - */ private Method repositoryPortNameMethod; - /** - * This is the name()-method of the class equivalence of {@link Property}. - */ private Method propertyNameMethod; - /** - * This is the defaultValue()-method of the class equivalence of {@link Property}. - */ private Method propertyDefaultValueMethod; - /** - * This is the getText()-method of the class equivalence of {@link PlainText}. - */ private Method plainTextgetTextMethod; - /** - * This is the getController()-method of the class equivalence of {@link AnalysisControllerWithMapping}. - */ private Method analysisControllerWithMappingGetController; - /** - * This is the getPluginMap()-method of the class equivalence of {@link AnalysisControllerWithMapping}. - */ private Method analysisControllerWithMappingGetMapping; - /** - * This is the createAnalysisController(MIProject, ClassLoader)-method of the class equivalence of {@link AnalysisControllerWithMapping}. - */ private Method analysisControllerCreateAnalysisController; - /** - * This is the start()-method of the class equivalence of {@link AnalysisController}. - */ private Method analysisControllerThreadStart; - /** - * This is the terminate()-method of the class equivalence of {@link AnalysisController}. - */ private Method analysisControllerThreadTerminate; - /** - * This is the join(long)-method of the class equivalence of {@link AnalysisController}. - */ private Method analysisControllerThreadJoin; - /** - * This is the getState()-method of the class equivalence of {@link AnalysisController}. - */ private Method analysisControllerGetState; - /** - * This is the description()-method of the class equivalence of {@link Property}. - */ private Method propertyDescriptionMethod; - /** - * This is the loadFromFile(File)-method of the class equivalence of {@link AnalysisController}. - */ private Method analysisControllerLoadFromFile; - /** - * This is the description()-method of the class equivalence of {@link Display}. - */ private Method displayDescriptionMethod; - /** - * This is the dependencies()-method of the class equivalence of {@link Plugin}. - */ private Method pluginDependenciesMethod; - /** - * This is the dependencies()-method of the class equivalence of {@link Repository}. - */ private Method repositoryDependenciesMethod; - /** - * This is the programmaticOnly()-method of the class equivalence of {@link Plugin}. - */ private Method pluginProgrammaticOnlyMethod; - /** - * This is the programmaticOnly()-method of the class equivalence of {@link Repository}. - */ private Method repositoryProgrammaticOnlyMethod; private Method logImplWebguiLoggingClassGetEntriesMethod; - /** - * This is the constructor for {@link AnalysisControllerThread}, which gets an instance of {@link AnalysisController}. - */ private Constructor<?> analysisControllerThreadConstructor; /** @@ -282,33 +142,11 @@ public final class ClassAndMethodContainer { } } - /** - * Loads the constructors. - * - * @throws NoSuchMethodException - * If something went wrong. - * @throws SecurityException - * If something went wrong. - * - */ private void loadConstructors() throws SecurityException, NoSuchMethodException { // Now the constructors this.analysisControllerThreadConstructor = this.analysisControllerThreadClass.getConstructor(this.analysisControllerClass); } - /** - * Loads the special cases. - * - * @param classLoader - * The classloader. - * @throws ClassNotFoundException - * If something went wrong. - * @throws NoSuchMethodException - * If something went wrong. - * @throws SecurityException - * If something went wrong. - * - */ private void loadSpecialCases(final ClassLoader classLoader) throws ClassNotFoundException, SecurityException, NoSuchMethodException { // This is a special case as we need to load some additional classes to search for the correct method final Class<?> miProjectClass = classLoader.loadClass(MIProject.class.getName()); @@ -327,14 +165,6 @@ public final class ClassAndMethodContainer { this.analysisControllerThreadJoin = joinMethod; } - /** - * Loads the methods. - * - * @throws NoSuchMethodException - * If something went wrong. - * @throws SecurityException - * If something went wrong. - */ private void loadMethods() throws SecurityException, NoSuchMethodException { // The following part has to be done carefully: The methods will be loaded via the name this.pluginDescriptionMethod = this.pluginAnnotationClass.getMethod("description", new Class<?>[0]); @@ -362,17 +192,8 @@ public final class ClassAndMethodContainer { this.pluginProgrammaticOnlyMethod = this.pluginAnnotationClass.getMethod("programmaticOnly", new Class<?>[0]); this.repositoryProgrammaticOnlyMethod = this.repositoryAnnotationClass.getMethod("programmaticOnly", new Class<?>[0]); this.logImplWebguiLoggingClassGetEntriesMethod = this.logImplWebguiLoggingClass.getMethod("getEntries", String.class); - } - /** - * Loads the classes. - * - * @param classLoader - * The classloader. - * @throws ClassNotFoundException - * if something went wrong. - */ @SuppressWarnings("unchecked") private void loadClasses(final ClassLoader classLoader) throws ClassNotFoundException { // For the first: Use the classloader the load all classes we will need. @@ -400,425 +221,190 @@ public final class ClassAndMethodContainer { this.displayAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Display.class.getName()); } - /** - * The getter-method for the field {@link ClassAndMethodContainer#abstractFilterPluginClass}. - * - * @return The current value for the field. - */ public Class<?> getAbstractFilterPluginClass() { return this.abstractFilterPluginClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#abstractReaderPluginClass}. - * - * @return The current value for the field. - */ public Class<?> getAbstractReaderPluginClass() { return this.abstractReaderPluginClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#pluginAnnotationClass}. - * - * @return The current value for the field. - */ public Class<? extends Annotation> getPluginAnnotationClass() { return this.pluginAnnotationClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#repositoryAnnotationClass}. - * - * @return The current value for the field. - */ public Class<? extends Annotation> getRepositoryAnnotationClass() { return this.repositoryAnnotationClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#propertyAnnotationClass}. - * - * @return The current value for the field. - */ public Class<? extends Annotation> getPropertyAnnotationClass() { return this.propertyAnnotationClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#outputPortAnnotationClass}. - * - * @return The current value for the field. - */ public Class<? extends Annotation> getOutputPortAnnotationClass() { return this.outputPortAnnotationClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#inputPortAnnotationClass}. - * - * @return The current value for the field. - */ public Class<? extends Annotation> getInputPortAnnotationClass() { return this.inputPortAnnotationClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#repositoryPortAnnotationClass}. - * - * @return The current value for the field. - */ public Class<? extends Annotation> getRepositoryPortAnnotationClass() { return this.repositoryPortAnnotationClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#displayAnnotationClass}. - * - * @return The current value for the field. - */ public Class<? extends Annotation> getDisplayAnnotationClass() { return this.displayAnnotationClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#pluginDescriptionMethod}. - * - * @return The current value for the field. - */ public Method getPluginDescriptionMethod() { return this.pluginDescriptionMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#repositoryDescriptionMethod}. - * - * @return The current value for the field. - */ public Method getRepositoryDescriptionMethod() { return this.repositoryDescriptionMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#pluginConfigurationMethod}. - * - * @return The current value for the field. - */ public Method getPluginConfigurationMethod() { return this.pluginConfigurationMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#repositoryConfigurationMethod}. - * - * @return The current value for the field. - */ public Method getRepositoryConfigurationMethod() { return this.repositoryConfigurationMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#pluginOutputPortsMethod}. - * - * @return The current value for the field. - */ public Method getPluginOutputPortsMethod() { return this.pluginOutputPortsMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#pluginRepositoryPortsMethod}. - * - * @return The current value for the field. - */ public Method getPluginRepositoryPortsMethod() { return this.pluginRepositoryPortsMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#displayNameMethod}. - * - * @return The current value for the field. - */ public Method getDisplayNameMethod() { return this.displayNameMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#abstractRepositoryClass}. - * - * @return The current value for the field. - */ public Class<?> getAbstractRepositoryClass() { return this.abstractRepositoryClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#abstractPluginClass}. - * - * @return The current value for the field. - */ public Class<?> getAbstractPluginClass() { return this.abstractPluginClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#inputPortNameMethod}. - * - * @return The current value for the field. - */ public Method getInputPortNameMethod() { return this.inputPortNameMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#outputPortNameMethod}. - * - * @return The current value for the field. - */ public Method getOutputPortNameMethod() { return this.outputPortNameMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#repositoryPortNameMethod}. - * - * @return The current value for the field. - */ public Method getRepositoryPortNameMethod() { return this.repositoryPortNameMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#propertyNameMethod}. - * - * @return The current value for the field. - */ public Method getPropertyNameMethod() { return this.propertyNameMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#propertyDefaultValueMethod}. - * - * @return The current value for the field. - */ public Method getPropertyDefaultValueMethod() { return this.propertyDefaultValueMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#imageClass}. - * - * @return The current value for the field. - */ public Class<?> getImageClass() { return this.imageClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#plainTextClass}. - * - * @return The current value for the field. - */ public Class<?> getPlainTextClass() { return this.plainTextClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#htmlTextClass}. - * - * @return The current value for the field. - */ public Class<?> getHtmlTextClass() { return this.htmlTextClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#plainTextgetTextMethod}. - * - * @return The current value for the field. - */ public Method getPlainTextgetTextMethod() { return this.plainTextgetTextMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerWithMappingGetMapping}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerWithMappingGetMapping() { return this.analysisControllerWithMappingGetMapping; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerClass}. - * - * @return The current value for the field. - */ public Class<?> getAnalysisControllerClass() { return this.analysisControllerClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerWithMappingClass}. - * - * @return The current value for the field. - */ public Class<?> getAnalysisControllerWithMappingClass() { return this.analysisControllerWithMappingClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadClass}. - * - * @return The current value for the field. - */ public Class<?> getAnalysisControllerThreadClass() { return this.analysisControllerThreadClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerCreateAnalysisController}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerCreateAnalysisController() { return this.analysisControllerCreateAnalysisController; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerWithMappingGetController}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerWithMappingGetController() { return this.analysisControllerWithMappingGetController; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadStart}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerThreadStart() { return this.analysisControllerThreadStart; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadTerminate}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerThreadTerminate() { return this.analysisControllerThreadTerminate; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadJoin}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerThreadJoin() { return this.analysisControllerThreadJoin; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadJoin}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerGetState() { return this.analysisControllerGetState; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#propertyDescriptionMethod}. - * - * @return The current value for the field. - */ public Method getPropertyDescriptionMethod() { return this.propertyDescriptionMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadConstructor}. - * - * @return The current value for the field. - */ public Constructor<?> getAnalysisControllerThreadConstructor() { return this.analysisControllerThreadConstructor; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerLoadFromFile}. - * - * @return The current value for the field. - */ public Method getAnalysisControllerLoadFromFile() { return this.analysisControllerLoadFromFile; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#pluginDependenciesMethod}. - * - * @return The value of the field. - */ public Method getPluginDependenciesMethod() { return this.pluginDependenciesMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#displayDescriptionMethod}. - * - * @return The current value for the field. - */ public Method getDisplayDescriptionMethod() { return this.displayDescriptionMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#repositoryDependenciesMethod}. - * - * @return The value of the field. - */ public Method getRepositoryDependenciesMethod() { return this.repositoryDependenciesMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#pluginProgrammaticOnlyMethod}. - * - * @return The value of the field. - */ public Method getPluginProgrammaticOnlyMethod() { return this.pluginProgrammaticOnlyMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#repositoryProgrammaticOnlyMethod}. - * - * @return The value of the field. - */ public Method getRepositoryProgrammaticOnlyMethod() { return this.repositoryProgrammaticOnlyMethod; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#logImplWebguiLoggingClass}. - * - * @return The value of the field. - */ public Class<?> getLogImplWebguiLoggingClass() { return this.logImplWebguiLoggingClass; } - /** - * The getter-method for the field {@link ClassAndMethodContainer#logImplWebguiLoggingClassGetEntriesMethod}. - * - * @return The value of the field. - */ public Method getLogImplWebguiLoggingClassGetEntriesMethod() { return this.logImplWebguiLoggingClassGetEntriesMethod; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AbstractKiekerWebGUIException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AbstractKiekerWebGUIException.java index 129d007a6d729df8a302ed0108be39425f49086e..c6d7014492dae6df3cdfb139465c94bf90b9c3fa 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AbstractKiekerWebGUIException.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AbstractKiekerWebGUIException.java @@ -23,9 +23,6 @@ package kieker.webgui.common.exception; */ public abstract class AbstractKiekerWebGUIException extends RuntimeException { - /** - * The UID. - */ private static final long serialVersionUID = 1L; /** diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInitializationException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInitializationException.java index 740006f6b056ff04573692f64fde990b61b2138e..f384e16a12bf1926a67b46f8d21e046faef70e85 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInitializationException.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInitializationException.java @@ -17,7 +17,7 @@ package kieker.webgui.common.exception; /** - * This class represents an exception occurring when the analysis is instantiated. + * This class represents an exception which can occur during the instantiation of an analysis. * * @author Nils Christian Ehmke */ diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/ComponentInitializationException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/ComponentInitializationException.java index 5b3dc268ae9d9f7d93f9b3e79eab383d175fa0a1..526cdb9121032a3dbd51b6944c6b487b1d4398ea 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/ComponentInitializationException.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/ComponentInitializationException.java @@ -16,6 +16,8 @@ package kieker.webgui.common.exception; /** + * This class represents an exception occurring when a component (filter, plugin) could not be initialized. + * * @author Nils Christian Ehmke */ public class ComponentInitializationException extends AbstractKiekerWebGUIException { diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DataAccessException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DataAccessException.java index 4fbf2ed657f46f6100c13ebab7b87a5f46fe0ca3..6af6a7c0b7f7cfd03d16f579d9b25337f354ffeb 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DataAccessException.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DataAccessException.java @@ -17,6 +17,8 @@ package kieker.webgui.common.exception; /** + * This class represents an exception occurring during an access to the database. + * * @author Nils Christian Ehmke */ public final class DataAccessException extends AbstractKiekerWebGUIException { diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DisplayNotFoundException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DisplayNotFoundException.java index fe2a6b923621ab4ae5e29263489872dcb32d093e..c71c9ef89b6e3d343f020aa5a083addf36fc776a 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DisplayNotFoundException.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/DisplayNotFoundException.java @@ -17,7 +17,7 @@ package kieker.webgui.common.exception; /** - * This exception occurs when a display object has been ordered, which is not available. + * This exception occurs when a non existing display object has been ordered. * * @author Nils Christian Ehmke */ diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/UninitializedGraphException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/GraphLayoutException.java similarity index 76% rename from Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/UninitializedGraphException.java rename to Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/GraphLayoutException.java index 9c4b88be7ddb4db2d882852d62f9aecdac2a55fd..1b0272de51fb854ba199dc3c84de6cb5fcec466c 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/UninitializedGraphException.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/GraphLayoutException.java @@ -17,19 +17,18 @@ package kieker.webgui.common.exception; /** - * An Exception that is thrown when trying to connect Edges if a graph has not been - * loaded by the GraphFlowLayouter. + * This class represents an exception which can occur during the autolayout of a graph. * - * @author row, Nils Christian Ehmke + * @author Nils Christian Ehmke */ -public class UninitializedGraphException extends AbstractKiekerWebGUIException { +public class GraphLayoutException extends AbstractKiekerWebGUIException { private static final long serialVersionUID = 1L; /** * Creates a new instance of this class. */ - public UninitializedGraphException() { + public GraphLayoutException() { super(); } @@ -39,7 +38,7 @@ public class UninitializedGraphException extends AbstractKiekerWebGUIException { * @param msg * The message used for the exception. */ - public UninitializedGraphException(final String msg) { + public GraphLayoutException(final String msg) { super(msg); } @@ -51,7 +50,7 @@ public class UninitializedGraphException extends AbstractKiekerWebGUIException { * @param cause * The cause for the exception. */ - public UninitializedGraphException(final String msg, final Throwable cause) { + public GraphLayoutException(final String msg, final Throwable cause) { super(msg, cause); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/InvalidInputSizeException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/InvalidInputSizeException.java deleted file mode 100644 index 9177208a40c4419bb1764b47d4c0087c538bd087..0000000000000000000000000000000000000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/InvalidInputSizeException.java +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * Copyright 2013 Kieker Project (http://kieker-monitoring.net) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***************************************************************************/ - -package kieker.webgui.common.exception; - -/** - * An Exception that is thrown when an Array of invalid size is loaded by the GraphFlowLayouter. - * - * Arrays loaded by the addEdges() method must be divisible by 4. - * Arrays loaded by the addNodes() method must be of length: 1 + nodeCount * 8 - * - * @author row, Nils Christian Ehmke - */ -public class InvalidInputSizeException extends AbstractKiekerWebGUIException { - - private static final long serialVersionUID = 1L; - - /** - * Creates a new instance of this class. - */ - public InvalidInputSizeException() { - super(); - } - - /** - * Creates a new instance of this class using the given parameters. - * - * @param msg - * The message used for the exception. - */ - public InvalidInputSizeException(final String msg) { - super(msg); - } - - /** - * Creates a new instance of this class using the given parameters. - * - * @param msg - * The message used for the exception. - * @param cause - * The cause for the exception. - */ - public InvalidInputSizeException(final String msg, final Throwable cause) { - super(msg, cause); - } -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/ComponentListContainer.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/ComponentListContainer.java index b87c27e18b758c492a5cf056c2cd46f395fcd2cf..c05aa54c3e075bc0003729d70266a1f5c1f6846b 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/ComponentListContainer.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/ComponentListContainer.java @@ -46,29 +46,14 @@ public class ComponentListContainer { this.repositories = repositories; } - /** - * Getter for the property {@link ComponentListContainer#readers}. - * - * @return The current value of the property. - */ public List<PluginContainer> getReaders() { return this.readers; } - /** - * Getter for the property {@link ComponentListContainer#filters}. - * - * @return The current value of the property. - */ public List<PluginContainer> getFilters() { return this.filters; } - /** - * Getter for the property {@link ComponentListContainer#repositories}. - * - * @return The current value of the property. - */ public List<RepositoryContainer> getRepositories() { return this.repositories; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/PluginContainer.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/PluginContainer.java index 9ee3e1baabd6eddcdb18b4beb83ba4577a07822a..4ed90682a15c5a772a5dad4ec7bf30dad86e493e 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/PluginContainer.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/PluginContainer.java @@ -68,47 +68,22 @@ public class PluginContainer implements IComponentContainer { this.displayDescriptions = displayDescriptions; } - /** - * Delivers the description of the repository. - * - * @return The human readable description string. - */ public String getDescription() { return this.description; } - /** - * Delivers the dependency description of the repository. - * - * @return The human readable dependency string. - */ public String getDependency() { return this.dependency; } - /** - * Tells whether the repository has been fully initialized. - * - * @return true iff the repository has been initialized fully. - */ public boolean isFullyInitialized() { return this.fullyInitialized; } - /** - * Tells whether the instance is a reader or not. - * - * @return true iff the plugin is a reader - */ public boolean isReader() { return this.plugin instanceof MIReader; } - /** - * Tells whether the instance is a filter or not. - * - * @return true iff the filter is a reader - */ public boolean isFilter() { return this.plugin instanceof MIFilter; } @@ -124,10 +99,8 @@ public class PluginContainer implements IComponentContainer { return this.displayDescriptions.get(display); } - /* - * (non-Javadoc) - * - * @see kieker.webgui.common.IComponentContainer#getPropertyDescription(java.lang.String) + /** + * {@inheritDoc} */ @Override public String getPropertyDescription(final String property) { diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/Project.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/Project.java deleted file mode 100644 index 9b405cef374ec648be5a57ff7568a6c4144f4e09..0000000000000000000000000000000000000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/Project.java +++ /dev/null @@ -1,98 +0,0 @@ -/*************************************************************************** - * Copyright 2013 Kieker Project (http://kieker-monitoring.net) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***************************************************************************/ -package kieker.webgui.domain; - -import kieker.analysis.model.analysisMetaModel.MIProject; - -/** - * This is a container for an instance of {@link MIProject}. Later it will probably contain more data. - * - * @author Nils Christian Ehmke - */ -public class Project { - - private String owner; - private String lastEditor; - private MIProject projectInstance; - - /** - * Creates a new instance of this class using the given parameters. - * - * @param projectInstance - * The model instance to be stored in this object. - */ - public Project(final MIProject projectInstance) { - this.projectInstance = projectInstance; - } - - /** - * Getter for the property {@link Project#projectInstance}. - * - * @return The current value of the property. - */ - public MIProject getProjectInstance() { - return this.projectInstance; - } - - /** - * Setter for the property {@link Project#projectInstance}. - * - * @param projectInstance - * The new value of the property. - */ - public void setProjectInstance(final MIProject projectInstance) { - this.projectInstance = projectInstance; - } - - /** - * Getter for the property {@link Project#owner}. - * - * @return The current value of the property. - */ - public String getOwner() { - return this.owner; - } - - /** - * Setter for the property {@link Project#owner}. - * - * @param owner - * The new value of the property. - */ - public void setOwner(final String owner) { - this.owner = owner; - } - - /** - * Getter for the property {@link Project#lastEditor}. - * - * @return The current value of the property. - */ - public String getLastEditor() { - return this.lastEditor; - } - - /** - * Setter for the property {@link Project#lastEditor}. - * - * @param lastEditor - * The new value of the property. - */ - public void setLastEditor(final String lastEditor) { - this.lastEditor = lastEditor; - } - -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/RepositoryContainer.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/RepositoryContainer.java index 7eaa08f0293dae8956b9b6ec4c9b8b18f114b47b..524aa00c8a6d1988c98f2ae9206ea2a32a0cc1eb 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/RepositoryContainer.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/RepositoryContainer.java @@ -58,29 +58,14 @@ public class RepositoryContainer implements IComponentContainer { this.propertyDescriptions = propertyDescriptions; } - /** - * Delivers the description of the repository. - * - * @return The human readable description string. - */ public String getDescription() { return this.description; } - /** - * Delivers the dependency description of the repository. - * - * @return The human readable dependency string. - */ public String getDependency() { return this.dependency; } - /** - * Tells whether the repository has been fully initialized. - * - * @return true iff the repository has been initialized fully. - */ public boolean isFullyInitialized() { return this.fullyInitialized; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/User.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/User.java index 563e0e2245adf0f72eea99e04eed4d821cd8f7ef..949af48b87dcf171224add06d097f8454b948afb 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/User.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/User.java @@ -47,78 +47,34 @@ public class User { this.password = password; } - /** - * Getter for the property {@link User#name}. - * - * @return The current value of the property. - */ public String getName() { return this.name; } - /** - * Setter for the property {@link User#name}. - * - * @param name - * The new value of the property. - */ public void setName(final String name) { this.name = name; } - /** - * Getter for the property {@link User#password}. - * - * @return The current value of the property. - */ public String getPassword() { return this.password; } - /** - * Setter for the property {@link User#password}. - * - * @param password - * The new value of the property. - */ public void setPassword(final String password) { this.password = password; } - /** - * Getter for the property {@link User#role}. - * - * @return The current value of the property. - */ public Role getRole() { return this.role; } - /** - * Setter for the property {@link User#role}. - * - * @param role - * The new value of the property. - */ public void setRole(final Role role) { this.role = role; } - /** - * Getter for the property {@link User#enabled}. - * - * @return The current value of the property. - */ public boolean isEnabled() { return this.enabled; } - /** - * Setter for the property {@link User#enabled}. - * - * @param enabled - * The new value of the property. - */ public void setEnabled(final boolean enabled) { this.enabled = enabled; } @@ -145,21 +101,10 @@ public class User { private int id; - /** - * Creates a new instance of this enum. - * - * @param id - * The id of the role. - */ private Role(final int id) { this.id = id; } - /** - * Getter for the property {@link Role#id}. - * - * @return The current value of the property. - */ public int getID() { return this.id; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java index 66c6f16b812b50d8e3bb4a7e2b82d5043d0e228f..ea79960e3b7c4f3f5c2b92c51ae524637b6e462a 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java @@ -139,6 +139,8 @@ public interface IProjectDAO { * Determines whether a newer project file will be overwritten without further warning or not. * @param username * The name of the user who saves the project. + * @param layout + * The current layout of the analysis graph. It is valid if this parameter is null. * * @throws ProjectNotExistingException * If a project with the given name does not exist. @@ -148,8 +150,8 @@ public interface IProjectDAO { * If the project on the file system is newer and the overwriteNewerProject-flag has not been set. */ @PreAuthorize("hasAnyRole('User', 'Administrator')") - public abstract void saveProject(String projectName, MIProject project, long timeStamp, boolean overwriteNewerProject, String username) throws - ProjectNotExistingException, IOException, NewerProjectException; + public abstract void saveProject(String projectName, MIProject project, long timeStamp, boolean overwriteNewerProject, String username, final String layout) + throws ProjectNotExistingException, IOException, NewerProjectException; /** * Delivers the current time stamp of the given project. @@ -269,4 +271,19 @@ public interface IProjectDAO { */ @PreAuthorize("isAuthenticated()") public abstract String getLastUser(final String projectName); + + /** + * @param projectName + * @return + */ + /** + * Delivers the stored layout for the given project. + * + * @param projectName + * The name of the project. + * + * @return The layout string as it is stored within the meta data. If this isn't available, null will be returned. + */ + @PreAuthorize("isAuthenticated()") + public abstract String getLayout(String projectName); } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java index fb24148a759565d318b44fbffd1ca3eba6a1850f..a8b165e3cfd475eb6a85468a0d69a0d8d77591c9 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/DerbyUserDAOImpl.java @@ -253,7 +253,16 @@ public class DerbyUserDAOImpl implements IUserDAO { final boolean isEnabled = queryResult.getBoolean(5); // The case that the user has no role cannot happen, as the database should make sure that this is not possible - final Role role = isAdministrator ? Role.ROLE_ADMIN : (isUser ? Role.ROLE_USER : (isGuest ? Role.ROLE_GUEST : null)); // NOPMD (Null assigning) + final Role role; + if (isAdministrator) { + role = Role.ROLE_ADMIN; + } else if (isUser) { + role = Role.ROLE_USER; + } else if (isGuest) { + role = Role.ROLE_GUEST; + } else { + role = null; + } result.add(new User(username, null, role, isEnabled)); } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java index 641ecf5abf0ddfbeda1c7f8a1fccd346abfd0dea..2e6704b80420e55146f289340e44a9dac64aef18 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java @@ -103,8 +103,10 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { private static final String LIB_EXTENSION = "jar"; private static final String LIB_DIRECTORY = "lib"; private static final String ROOT_DIRECTORY = "data"; + private static final String PROPERTY_KEY_LAST_USER = "last user"; private static final String PROPERTY_KEY_OWNER = "owner"; + private static final String PROPERTY_KEY_LAYOUT = "layout"; @Autowired private PluginFinder pluginFinder; @@ -857,7 +859,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { // Now load the kax file and use the resulting MIProject to overwrite the existing (newly created) kax file final MIProject project = AnalysisController.loadFromFile(tempFile); - this.saveProject(projectName, project, 0, true, username); + this.saveProject(projectName, project, 0, true, username, null); } /* @@ -962,7 +964,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { @Override @PreAuthorize("hasAnyRole('User', 'Administrator')") public void saveProject(final String projectName, final MIProject project, final long timeStamp, final boolean overwriteNewerProject, - final String username) throws ProjectNotExistingException, IOException, NewerProjectException { + final String username, final String layout) throws ProjectNotExistingException, IOException, NewerProjectException { // Check whether the project exists if (!this.projectExists(projectName)) { throw new ProjectNotExistingException("A project with the name '" + projectName + "' does not exist."); @@ -980,6 +982,9 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { // Store the new meta data final Properties properties = FSProjectDAOImpl.loadPropertiesFile(projectName); properties.put(FSProjectDAOImpl.PROPERTY_KEY_LAST_USER, username); + if (layout != null) { + properties.put(FSProjectDAOImpl.PROPERTY_KEY_LAYOUT, layout); + } FSProjectDAOImpl.savePropertiesFile(properties, projectName); } @@ -1284,6 +1289,23 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return FSProjectDAOImpl.assembleKaxFile(projectName); } + /* + * (non-Javadoc) + * + * @see kieker.webgui.persistence.IProjectDAO#getLayout(java.lang.String) + */ + @Override + public String getLayout(final String projectName) { + try { + final Properties properties = FSProjectDAOImpl.loadPropertiesFile(projectName); + return properties.getProperty(FSProjectDAOImpl.PROPERTY_KEY_LAYOUT); + } catch (final IOException ex) { + FSProjectDAOImpl.LOG.warn("Could not open meta file.", ex); + } + + return null; + } + /* * (non-Javadoc) * diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/IGraphLayoutService.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/IGraphLayoutService.java index 6c2e885fc67b48f72dbc07a07f3c07688e5ab1ac..84e6fe95d2bda71f041feda50a0a7f828206f5e8 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/IGraphLayoutService.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/IGraphLayoutService.java @@ -18,8 +18,7 @@ package kieker.webgui.service; import org.springframework.security.access.prepost.PreAuthorize; -import kieker.webgui.common.exception.InvalidInputSizeException; -import kieker.webgui.common.exception.UninitializedGraphException; +import kieker.webgui.common.exception.GraphLayoutException; /** * An interface for a service providing a graph layouter. @@ -37,12 +36,10 @@ public interface IGraphLayoutService { * A String containing connection information of edges. * @return A String of space separated node positions. * - * @throws UninitializedGraphException - * If the graph has not been initialized yet. - * @throws InvalidInputSizeException - * If the input size is somehow invalid. + * @throws GraphLayoutException + * If the autolayout failed. */ @PreAuthorize("isAuthenticated()") - public String layoutGraph(String nodes, String edges) throws UninitializedGraphException, InvalidInputSizeException; + public String layoutGraph(String nodes, String edges) throws GraphLayoutException; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java index 0a42a4b6e693272d74a2e5408465c88a84f6fa1f..ad527a74e4ed74ecb60c65a198711987b0a127b4 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java @@ -144,6 +144,8 @@ public interface IProjectService { * Determines whether a newer project file will be overwritten without further warning or not. * @param username * The name of the user who saves the project. + * @param layout + * The current layout of the analysis graph. It is valid if this parameter is null. * * @throws ProjectNotExistingException * If a project with the given name does not exist. @@ -154,7 +156,7 @@ public interface IProjectService { */ @PreAuthorize("hasAnyRole('User', 'Administrator')") public void saveProject(final String projectName, final MIProject project, final long timeStamp, final boolean overwriteNewerProject, - final String username) throws ProjectNotExistingException, IOException, NewerProjectException; + final String username, final String layout) throws ProjectNotExistingException, IOException, NewerProjectException; /** * Delivers the current time stamp of the given project. @@ -366,4 +368,15 @@ public interface IProjectService { */ @PreAuthorize("hasAnyRole('User', 'Administrator')") public boolean deleteLibrary(String projectName, String libName) throws IOException; + + /** + * Delivers the stored layout for the given project. + * + * @param projectName + * The name of the project. + * + * @return The layout string as it is stored within the meta data. If this isn't available, null will be returned. + */ + @PreAuthorize("isAuthenticated()") + public String getLayout(String projectName); } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java index af70e2767c75a6d673ae466b1ed5562c01e53aac..a26641578f87cf33ca20d1216e71e0959b5098a5 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java @@ -21,8 +21,7 @@ import java.util.List; import org.springframework.stereotype.Service; -import kieker.webgui.common.exception.InvalidInputSizeException; -import kieker.webgui.common.exception.UninitializedGraphException; +import kieker.webgui.common.exception.GraphLayoutException; import kieker.webgui.service.IGraphLayoutService; import org.eclipse.emf.common.util.EList; @@ -44,9 +43,8 @@ import de.cau.cs.kieler.kiml.util.KimlUtil; import de.cau.cs.kieler.klay.layered.LayeredLayoutProvider; /** - * This class provides a single method, that is used for GraphFlow layouting. The JavaScript GraphFlow throws an "autoLayout"-Event upon using the function - * autoLayout(). This event provides two Strings which may be used by this class' layoutGraph(nodes, edges) method. The return value can then be used as an argument - * for the GraphFlow's loadPositionsFromLayout(positions) function. + * This is a utility class providing a method to layout a graph from the graph flow editor. The method accepts two strings (one for the nodes, one for the edges) + * which are the result of specific javascript functions of the graph. For further information look into the API description of the flow editor itself. * * @author row, Nils Christian Ehmke */ @@ -60,193 +58,221 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService { // No code necessary } - /** - * Parses a String array, building a graph with nodes and fixed ports. - * - * @param positions - * The node positions. - * @param layoutInformation - * The necessary information about the graph. - * @throws InvalidInputSizeException - * If the given input is somehow invalid in size. - */ - private static void addNodes(final String[] positions, final LayoutInformation layoutInformation) throws InvalidInputSizeException { - layoutInformation.getGraph().getData(KShapeLayout.class).setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL); + private static void addNodes(final int scale, final String[] nodeInfo, final LayoutInformation layoutInformation) throws NumberFormatException { + // define node and port list + final List<List<KLabeledGraphElement>> nodesAndPorts = layoutInformation.getNodesAndPorts(); + List<KLabeledGraphElement> nodeAndPortList; - // prepare array of lists - List<KLabeledGraphElement> child; - - final int dimHalf = Integer.parseInt(positions[0]); + // retrieve size modifier + final int dimHalf = scale; final int dim = dimHalf * 2; - // check input Array for correct length - if (((positions.length - 1) % 8) != 0) { - throw new InvalidInputSizeException(); - } - - // loop variables + // loop variables // + String[] nodeProps; KNode node; + int parentIndex; + KNode parent; KPort port; KShapeLayout layout; + + boolean isNodeFamily; int width; int height; int portCount; + int portType; int portX; int portY; - int c = 1; - int i = 0; - // iterate input node positions - while (c < positions.length) { - // get size and increment array pointer - width = Integer.parseInt(positions[c++]); - height = Integer.parseInt(positions[c++]); + int i; + int n; + int p; + int lp; + final int l = nodeInfo.length; - // create Node + // -- 1. initialize empty nodes -- + for (n = 0; n < l; n++) { + // init node node = KimlUtil.createInitializedNode(); - node.setParent(layoutInformation.getGraph()); - child = new ArrayList<KLabeledGraphElement>(); - layoutInformation.getChildren().add(i, child); - child.add(node); + // create a list that will contain the node itself + // as well as its ports (should they exist) + nodeAndPortList = new ArrayList<KLabeledGraphElement>(); + nodeAndPortList.add(node); + + // add the list to the global 2 dimensional list + nodesAndPorts.add(n, nodeAndPortList); + } + + // -- 2. Define nodes by the properties, given in the string -- + for (n = 0; n < l; n++) { + nodeProps = nodeInfo[n].split(" "); + + // get Node from global list + node = (KNode) nodesAndPorts.get(n).get(0); + + // i is our property array-pointer + i = 0; + + // retrieve node information + isNodeFamily = "f".equals(nodeProps[i++]); + width = Integer.parseInt(nodeProps[i++]); + height = Integer.parseInt(nodeProps[i++]); + + // determine the parent of the node + parentIndex = Integer.parseInt(nodeProps[i++]); + if (parentIndex > 0) { + parent = (KNode) nodesAndPorts.get(parentIndex).get(0); + node.setParent(parent); + } else { + node.setParent(layoutInformation.getGraph()); + } // set node dimensions layout = node.getData(KShapeLayout.class); layout.setWidth(width); layout.setHeight(height); - layout.setProperty(LayoutOptions.FIXED_SIZE, Boolean.TRUE); - layout.setProperty(LayoutOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS); - portX = -dimHalf; - - // add Ports - for (int portType = 0; portType < 3; portType++) { - // determine port x-position - if (portType == 1) { - portX = width - dimHalf; - } - portCount = Integer.parseInt(positions[c++]); - portY = Integer.parseInt(positions[c++]); + // parse port data if it is a NodeFamily + if (isNodeFamily) { + + // let the node size be fixed for now + // (resizable nodeFamilies may be implemented in the future) + layout.setProperty(LayoutOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS); + portX = -dimHalf; + + // add Ports + for (portType = 0; portType < 3; portType++) { + // determine port x-position + if (portType == 1) { + portX = width - dimHalf; + } - final int lp = portCount; - for (int n = 0; n < lp; n++) { + portCount = Integer.parseInt(nodeProps[i++]); + portY = Integer.parseInt(nodeProps[i++]); - // create port - port = KimlUtil.createInitializedPort(); - port.setNode(node); - child.add(port); + for (p = 0, lp = portCount; p < lp; p++) { - // set layout for Port - layout = port.getData(KShapeLayout.class); + // create port + port = KimlUtil.createInitializedPort(); + port.setNode(node); + nodesAndPorts.get(n).add(port); - // set position and dimension - layout.setWidth(dim); - layout.setHeight(dimHalf); - layout.setYpos(portY); - layout.setXpos(portX); + // set layout for Port + layout = port.getData(KShapeLayout.class); - portY += dim; + // set position and dimension of port + layout.setWidth(dim); + layout.setHeight(dimHalf); + layout.setYpos(portY); + layout.setXpos(portX); + + portY += dim; + } } } - i++; } } - /** - * Parses an array which must contain quadruples of numbers.<br/> - * The first number must be the index of the children-array, where - * the source node is located.<br/> - * The second number must be the index of the children-array, where - * the target node is located.<br/> - * The third number must be the index of the source node ArrayList, where - * the source port is located.<br/> - * The fourth number must be the index of the target node ArrayList, where - * the target port is located. - * - * @param edgeInfo - * The single elements for the edges. - * @param layoutInformation - * The necessary information about the graph. - * @throws UninitializedGraphException - * If the graph has not yet been initialized. - * @throws InvalidInputSizeException - * If the input size is invalid. - */ - private static void addEdges(final String[] edgeInfo, final LayoutInformation layoutInformation) throws UninitializedGraphException, InvalidInputSizeException { - // cannot add edges if no graph was constructed - if (layoutInformation.getChildren() == null) { - throw new UninitializedGraphException(); - } - if ((edgeInfo.length % 4) != 0) { - throw new InvalidInputSizeException(); - } + private static void addEdges(final String[] edgeInfo, final LayoutInformation layoutInformation) throws NumberFormatException { + final List<List<KLabeledGraphElement>> nodesAndPorts = layoutInformation.getNodesAndPorts(); // set up loop variables + String[] edgeProps; KEdge edge; - int sourceID; - int targetID; - KPort sourcePort; + + int id; + boolean hasSourcePort; + + KNode sourceNode; + int sourcePortIndex; + KPort sourcePort = null; + List<KLabeledGraphElement> sourceList; + + int targetPortIndex; KPort targetPort; - int e = 0; - final int l = edgeInfo.length; + List<KLabeledGraphElement> targetList; + int ea = 0; + int p; + int epl; + + // read from String + for (final String element : edgeInfo) { + + // get edge info of a single source + edgeProps = element.split(" "); + p = 0; + + // get source index and port + id = Integer.parseInt(edgeProps[p++]); + sourceList = nodesAndPorts.get(id); + sourceNode = (KNode) sourceList.get(0); + + sourcePortIndex = Integer.parseInt(edgeProps[p++]) + 1; + hasSourcePort = sourcePortIndex != 0; + + if (hasSourcePort) { + sourcePort = (KPort) sourceList.get(sourcePortIndex); + } + + // get target ports + epl = edgeProps.length; + while (p < epl) { + + // get target index and port + id = Integer.parseInt(edgeProps[p++]); + targetList = nodesAndPorts.get(id); + + // define edge + edge = KimlUtil.createInitializedEdge(); + edge.setSource(sourceNode); + edge.setTarget((KNode) targetList.get(0)); + + targetPortIndex = Integer.parseInt(edgeProps[p++]) + 1; + if (targetPortIndex != 0) { + targetPort = (KPort) targetList.get(targetPortIndex); + + // set target port of edge + edge.setTargetPort(targetPort); + targetPort.getEdges().add(edge); + } + if (hasSourcePort) { + // set source port of edge + edge.setSourcePort(sourcePort); + sourcePort.getEdges().add(edge); + } + layoutInformation.getEdges().add(ea++, edge); + } - while (e < l) { - // read from String - sourceID = Integer.parseInt(edgeInfo[e++]); - targetID = Integer.parseInt(edgeInfo[e++]); - sourcePort = (KPort) layoutInformation.getChildren().get(sourceID).get(1 + Integer.parseInt(edgeInfo[e++])); - targetPort = (KPort) layoutInformation.getChildren().get(targetID).get(1 + Integer.parseInt(edgeInfo[e++])); - - // add edge to graph - edge = KimlUtil.createInitializedEdge(); - edge.setSource((KNode) layoutInformation.getChildren().get(sourceID).get(0)); - edge.setTarget((KNode) layoutInformation.getChildren().get(targetID).get(0)); - - // set ports of edge - edge.setSourcePort(sourcePort); - sourcePort.getEdges().add(edge); - edge.setTargetPort(targetPort); - targetPort.getEdges().add(edge); - - layoutInformation.getEdges().add(ea++, edge); } } - /** - * This simple method "corrects" an array containing only an empty string. - * - * @param arr - * The array to be corrected. - * @return An corrected version of the array. - */ private static String[] correctEmptyArray(final String[] arr) { - return ((arr.length == 1) && arr[0].isEmpty()) ? new String[0] : arr; + if ((arr.length == 1) && arr[0].isEmpty()) { + return new String[0]; + } else { + return arr; + } } - /** - * Assembles the necessary layout information using the given parameters. - * - * @param nodesStr - * The string containing the information about the nodes. - * @param edgesStr - * The string containing the information about the edges. - * @return An object containing the layout information for the graph. - * @throws UninitializedGraphException - * If the graph has not been initialized yet. - * @throws InvalidInputSizeException - * IF the input size of the graph is somehow invalid. - */ - private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) throws UninitializedGraphException, - InvalidInputSizeException { - final String[] edgeInfo = GraphLayoutServiceImpl.correctEmptyArray(edgesStr.split(" ")); - final String[] positions = GraphLayoutServiceImpl.correctEmptyArray(nodesStr.split(" ")); + private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) throws GraphLayoutException { + final int firstSemicolon = nodesStr.indexOf(';'); + + // if there is no semicolon, we got an empty graph + if (firstSemicolon < 0) { + throw new GraphLayoutException("Empty graph"); + } + + final int scale = Integer.parseInt(nodesStr.substring(0, firstSemicolon)); - final List<List<KLabeledGraphElement>> children = new ArrayList<List<KLabeledGraphElement>>(positions.length / 2); - final List<KEdge> edges = new ArrayList<KEdge>(edgeInfo.length / 4); + final String[] nodeInfo = GraphLayoutServiceImpl.correctEmptyArray(nodesStr.substring(firstSemicolon + 1).split(";")); + final String[] edgeInfo = GraphLayoutServiceImpl.correctEmptyArray(edgesStr.split(";")); + + final List<List<KLabeledGraphElement>> children = new ArrayList<List<KLabeledGraphElement>>(nodeInfo.length - 1); + final List<KEdge> edges = new ArrayList<KEdge>(edgeInfo.length); final LayoutInformation layoutInformation = new LayoutInformation(KimlUtil.createInitializedNode(), children, edges); - GraphLayoutServiceImpl.addNodes(positions, layoutInformation); + GraphLayoutServiceImpl.addNodes(scale, nodeInfo, layoutInformation); GraphLayoutServiceImpl.addEdges(edgeInfo, layoutInformation); return layoutInformation; @@ -258,73 +284,100 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService { * @see kieker.webgui.service.impl.IGraphLayoutService#layoutGraph(java.lang.String, java.lang.String) */ @Override - public String layoutGraph(final String nodes, final String edges) throws UninitializedGraphException, InvalidInputSizeException { - final LayoutInformation layoutInformation = GraphLayoutServiceImpl.assembleLayoutInformation(nodes, edges); + public String layoutGraph(final String nodes, final String edges) { + final String layoutedGraph; + final String bendPoints; + + try { + final LayoutInformation layoutInformation = GraphLayoutServiceImpl.assembleLayoutInformation(nodes, edges); + + // Create a progress monitor + final IKielerProgressMonitor progressMonitor = new BasicProgressMonitor(); - // Create a progress monitor - final IKielerProgressMonitor progressMonitor = new BasicProgressMonitor(); + // Create the layout provider + final AbstractLayoutProvider layoutProvider = new LayeredLayoutProvider(); - // Create the layout provider - final AbstractLayoutProvider layoutProvider = new LayeredLayoutProvider(); + // Perform layout on the created graph + layoutProvider.doLayout(layoutInformation.getGraph(), progressMonitor); - // Perform layout on the created graph - layoutProvider.doLayout(layoutInformation.getGraph(), progressMonitor); + // convert layouted graph positions to String + layoutedGraph = GraphLayoutServiceImpl.getPositions(layoutInformation); + bendPoints = GraphLayoutServiceImpl.getBendPoints(layoutInformation); + + } catch (final NumberFormatException e) { + throw new GraphLayoutException("Invalid Graph Information String", e); + } - // convert layouted graph positions to String - final String layoutedGraph = GraphLayoutServiceImpl.getPositions(layoutInformation); - final String bendPoints = GraphLayoutServiceImpl.getBendPoints(layoutInformation); return layoutedGraph + "#" + bendPoints; } - /** - * Reads the (layouted) positions of a constructed KGraph and writes them as integers to a string, seperating each number with a space. - * - * @param layoutInformation - * The object containing the necessary information about the graph. - * @return The constructed string. - */ private static String getPositions(final LayoutInformation layoutInformation) { + + final List<List<KLabeledGraphElement>> nodesAndPorts = layoutInformation.getNodesAndPorts(); final StringBuilder sb = new StringBuilder(); KShapeLayout layout; + KNode node; + int x; + int y; // position of node + int width; + int height; - for (final KNode node : layoutInformation.getGraph().getChildren()) { + for (final List<KLabeledGraphElement> list : nodesAndPorts) { + node = (KNode) list.get(0); layout = node.getData(KShapeLayout.class); - final int x = Math.round(layout.getXpos() + (layout.getWidth() / 2)); - final int y = Math.round(layout.getYpos() + (layout.getHeight() / 2)); + x = Math.round(layout.getXpos() + (layout.getWidth() / 2)); + + // hotFix: wrong nodeFamily position: needs to be half the height lower + if (list.size() > 1) { + y = Math.round(layout.getYpos() + (layout.getHeight())); + } else { + y = Math.round(layout.getYpos() + (layout.getHeight() / 2)); + } + + width = Math.round(layout.getWidth()); + height = Math.round(layout.getHeight()); sb.append(x); sb.append(" "); sb.append(y); sb.append(" "); + sb.append(width); + sb.append(" "); + sb.append(height); + sb.append(";"); } return sb.toString(); } - /** - * This method iterates through all edges of the given object and creates a semicolon separated String containing bend points of all edges. - * - * @param layoutInformation - * The object containing the information about the graph and the layout. - * @return The string containing the bend points. - */ private static String getBendPoints(final LayoutInformation layoutInformation) { final StringBuilder sb = new StringBuilder(); // iterate edges for (final KEdge edge : layoutInformation.getEdges()) { + final KEdgeLayout layout = edge.getData(KEdgeLayout.class); final EList<KPoint> bendPoints = layout.getBendPoints(); // iterate bend points final int bl = bendPoints.size(); - for (int b = 0; b < bl; b++) { - final KPoint point = bendPoints.get(b); + KPoint point; + + if (bl > 0) { + point = bendPoints.get(0); sb.append(Math.round(point.getX())); sb.append(" "); sb.append(Math.round(point.getY())); - sb.append(" "); + + for (int b = 1; b < bl; b++) { + sb.append(" "); + point = bendPoints.get(b); + sb.append(Math.round(point.getX())); + sb.append(" "); + sb.append(Math.round(point.getY())); + + } } - sb.append("; "); + sb.append(";"); } return sb.toString(); @@ -338,13 +391,7 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService { private static class LayoutInformation { private final KNode graph; - /** - * An array containing the child node and the ports from left to right. - */ private final List<List<KLabeledGraphElement>> children; - /** - * An array containing edges. This way we can return edge information in the same order. - */ private final List<KEdge> edges; /** @@ -361,31 +408,22 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService { this.graph = graph; this.children = children; this.edges = edges; + + // set graph layout options + final KShapeLayout layout = graph.getData(KShapeLayout.class); + // layout.setProperty(LayoutOptions.LAYOUT_HIERARCHY, true); + layout.setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL); + } - /** - * Getter for the property {@link LayoutInformation#graph}. - * - * @return The current value of the property. - */ public KNode getGraph() { return this.graph; } - /** - * Getter for the property {@link LayoutInformation#children}. - * - * @return The current value of the property. - */ - public List<List<KLabeledGraphElement>> getChildren() { + public List<List<KLabeledGraphElement>> getNodesAndPorts() { return this.children; } - /** - * Getter for the property {@link LayoutInformation#edges}. - * - * @return The current value of the property. - */ public List<KEdge> getEdges() { return this.edges; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java index 2d44ff711a4841261c160b94e317543ac60ba04c..843a07419648f32f35c76d3976636130e69ebce1 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java @@ -143,11 +143,11 @@ public final class ProjectServiceImpl implements IProjectService { */ @Override public void saveProject(final String projectName, final MIProject project, final long timeStamp, final boolean overwriteNewerProject, - final String username) throws ProjectNotExistingException, IOException, NewerProjectException { + final String username, final String layout) throws ProjectNotExistingException, IOException, NewerProjectException { final Object projectLock = this.getLock(projectName, this.fileSystemLocks); synchronized (projectLock) { - this.projectDAO.saveProject(projectName, project, timeStamp, overwriteNewerProject, username); + this.projectDAO.saveProject(projectName, project, timeStamp, overwriteNewerProject, username, layout); } } @@ -410,4 +410,18 @@ public final class ProjectServiceImpl implements IProjectService { this.projectDAO.importProject(projectName, username, file); } } + + /* + * (non-Javadoc) + * + * @see kieker.webgui.service.IProjectService#getLayout(java.lang.String) + */ + @Override + public String getLayout(final String projectName) { + final Object projectLock = this.getLock(projectName, this.fileSystemLocks); + + synchronized (projectLock) { + return this.projectDAO.getLayout(projectName); + } + } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/GlobalPropertiesBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/GlobalPropertiesBean.java index a8cb1c013e1c06d3be347a3671a39807688272ea..d7f6227f52396ce906b46f87169d31459873fc48 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/GlobalPropertiesBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/GlobalPropertiesBean.java @@ -17,21 +17,35 @@ package kieker.webgui.web.beans.application; import java.io.Serializable; +import java.util.Locale; import java.util.ResourceBundle; import javax.faces.application.FacesMessage; import javax.faces.application.FacesMessage.Severity; import javax.faces.context.FacesContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + /** - * The class {@link GlobalPropertiesBean} is a singleton scoped Spring bean, containing properties, constants and partially localized texts for the application. Some - * of the properties are injected via Spring, others are loaded directly from the resource bundle. This makes sure that those constants can be modified without a - * necessary recompiling of the whole application.<br> - * It implements the {@link Serializable} interface to make sure that some session scoped beans can use this class.<br> - * It is singleton scoped as the properties are the same for every user and as only one instance of this class is necessary. + * This class is a singleton scoped {@code Spring} bean containing properties, constants, methods and even some localized texts which are used at various parts in + * the application. While some of the properties are loaded directly from the resource bundles, some other are injected via {@code Spring}. This makes sure that most + * of the constants could be modified without recompiling the whole application.<br> + * </br> + * + * If you want to change the values, take a look either at the files in the {@code resources} directory or at the {@code Spring} configuration files.<br> + * </br> + * + * The class implements the {@link Serializable} interface to make sure that some session scoped beans can use this class. It is furthermore singleton scoped as the + * properties are the same for every user. Therefore only one instance of this class is necessary.<br> + * </br> + * + * As this bean is {@code Spring} managed, it is <b>not</b> recommended to use the constructor or the setter methods. * * @author Nils Christian Ehmke */ +@Component +@Scope("singleton") public final class GlobalPropertiesBean implements Serializable { private static final long serialVersionUID = 4253541090603377504L; @@ -66,279 +80,131 @@ public final class GlobalPropertiesBean implements Serializable { // No code necessary } - /** - * Setter for the property {@link GlobalPropertiesBean#projectOverviewPage}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param projectOverviewPage - * The new value for the property. - */ public void setProjectOverviewPage(final String projectOverviewPage) { this.projectOverviewPage = projectOverviewPage; } - /** - * This method delivers the redirecting-link to the project overview page. - * - * @return The value of the property. - */ public String getProjectOverviewPage() { return this.projectOverviewPage; } - /** - * Setter for the property {@link GlobalPropertiesBean#facesContextThemeKey}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param facesContextThemeKey - * The new value for the property. - */ public void setFacesContextThemeKey(final String facesContextThemeKey) { this.facesContextThemeKey = facesContextThemeKey; } - /** - * This method delivers the key name of the theme within the faces context. This key can be used to load the default theme from the faces context if necessary. - * - * @return The value of the property. - */ public String getFacesContextThemeKey() { return this.facesContextThemeKey; } - /** - * Setter for the property {@link GlobalPropertiesBean#defaultTheme}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param defaultTheme - * The new value for the property. - */ public void setDefaultTheme(final String defaultTheme) { this.defaultTheme = defaultTheme; } - /** - * This method delivers the default theme stored in the properties file. - * - * @return The value of the property. - */ public String getDefaultTheme() { return this.defaultTheme; } - /** - * Setter for the property {@link GlobalPropertiesBean#analysisEditorGridSizeCookieName}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param analysisEditorGridSizeCookieName - * The new value for the property. - */ public void setAnalysisEditorGridSizeCookieName(final String analysisEditorGridSizeCookieName) { this.analysisEditorGridSizeCookieName = analysisEditorGridSizeCookieName; } - /** - * This method delivers the name of the cookie for the grid size within the analysis editor. - * - * @return The value of the property. - */ public String getAnalysisEditorGridSizeCookieName() { return this.analysisEditorGridSizeCookieName; } - /** - * Setter for the property {@link GlobalPropertiesBean#analysisEditorGridColorCookieName}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param analysisEditorGridColorCookieName - * The new value for the property. - */ public void setAnalysisEditorGridColorCookieName(final String analysisEditorGridColorCookieName) { this.analysisEditorGridColorCookieName = analysisEditorGridColorCookieName; } - /** - * This method delivers the name of the cookie for the grid color within the analysis editor. - * - * @return The value of the property. - */ public String getAnalysisEditorGridColorCookieName() { return this.analysisEditorGridColorCookieName; } - /** - * Setter for the property {@link GlobalPropertiesBean#analysisEditorDefaultGridSize}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param analysisEditorDefaultGridSize - * The new value for the property. - */ public void setAnalysisEditorDefaultGridSize(final String analysisEditorDefaultGridSize) { this.analysisEditorDefaultGridSize = analysisEditorDefaultGridSize; } - /** - * This method delivers the default grid size within the analysis editor. - * - * @return The value of the property. - */ public String getAnalysisEditorDefaultGridSize() { return this.analysisEditorDefaultGridSize; } - /** - * Setter for the property {@link GlobalPropertiesBean#analysisEditorDefaultGridColor}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param analysisEditorDefaultGridColor - * The new value for the property. - */ public void setAnalysisEditorDefaultGridColor(final String analysisEditorDefaultGridColor) { this.analysisEditorDefaultGridColor = analysisEditorDefaultGridColor; } - /** - * This method delivers the default grid color within the analysis editor. - * - * @return The value of the property. - */ public String getAnalysisEditorDefaultGridColor() { return this.analysisEditorDefaultGridColor; } - /** - * Setter for the property {@link GlobalPropertiesBean#themeCookieName}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param themeCookieName - * The new value for the property. - */ public void setThemeCookieName(final String themeCookieName) { this.themeCookieName = themeCookieName; } - /** - * This method delivers the name of the theme cookie stored in the properties file. This cookie name should only be used to (re)store the current user's look and - * feel. - * - * @return The value of the property. - */ public String getThemeCookieName() { return this.themeCookieName; } - /** - * This method delivers the localized message, which can be used if the loading of a project resulted in an exception. - * - * @return The value of the property. - */ public String getMsgProjectLoadingException() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_PROJECT_LOADING_EXCEPTION); } - /** - * This method delivers the localized message, which can be used if a project has been saved. - * - * @return The value of the property. - */ public String getMsgProjectSaved() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_PROJECT_SAVED); } - /** - * This method delivers the localized message, which can be used if the creation of a plugin resulted in an exception. - * - * @return The value of the property. - */ public String getMsgPluginCreationException() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_PLUGIN_CREATION_EXCEPTION); } - /** - * This method delivers the localized message, which can be used if the creation of a repository resulted in an exception. - * - * @return The value of the property. - */ public String getMsgRepositoryCreationException() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_REPOSITORY_CREATION_EXCEPTION); } - /** - * This method delivers the localized message, which can be used if a library has been uploaded. - * - * @return The value of the property. - */ public String getMsgLibraryUploaded() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_LIBRARY_UPLOADED); } - /** - * This method delivers the localized message, which can be used if a project has been created. - * - * @return The value of the property. - */ public String getMsgProjectCreated() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_PROJECT_CREATED); } - /** - * This method delivers the localized message, which can be used if the saving of a project failed. - * - * @return The value of the property. - */ public String getMsgProjectSavingException() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_PROJECT_SAVING_EXCEPTION); } - /** - * This method delivers the localized message, which can be used if a project does not exist. - * - * @return The value of the property. - */ public String getMsgProjectNotExistingException() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_PROJECT_NOT_EXISTING_EXCEPTION); } - /** - * This method delivers the localized message, which can be used if a project has been modified externally. - * - * @return The value of the property. - */ public String getMsgProjectModified() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_PROJECT_MODIFIED); } - /** - * This method delivers the localized message, which can be used if a library does not exist. - * - * @return The value of the property. - */ public String getMsgLibraryExistingException() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_LIBRARY_EXISTING_EXCEPTION); } - /** - * This method delivers the localized message, which can be used if the uploading of a library failed. - * - * @return The value of the property. - */ public String getMsgLibraryUploadingException() { return GlobalPropertiesBean.getLocalizedString(GlobalPropertiesBean.PROPERTY_MSG_LIBRARY_UPLOADING_EXCEPTION); } - /** - * Delivers the localized property for the given key. - * - * @param key - * They key of the property. - * @return The value for the current locale (in the current faces context) from the common resource bundle. - */ private static String getLocalizedString(final String key) { // Get the correct resource bundle for the current language (taken from the current context) and search it for the given key - return ResourceBundle.getBundle(GlobalPropertiesBean.RESOURCE_BUNDLE_NAME, FacesContext.getCurrentInstance().getELContext().getLocale()).getString(key); + final Locale currLocale = FacesContext.getCurrentInstance().getELContext().getLocale(); + return ResourceBundle.getBundle(GlobalPropertiesBean.RESOURCE_BUNDLE_NAME, currLocale).getString(key); } /** - * This method shows the current user a message by using the growl-component of PrimeFaces. + * This method shows a message by using the growl-component of PrimeFaces (within the current context). * * @param severity * The severity of the message. + * * @param msg - * The message itself. + * The message to show. */ public 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/web/beans/application/ProjectsBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ProjectsBean.java index ea26d976be07d815c110732b4dedb8994924c940..f41f692afee1688de127fc8bfc6c263efe1aba86 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ProjectsBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ProjectsBean.java @@ -27,6 +27,7 @@ import javax.faces.application.FacesMessage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import kieker.analysis.AnalysisController.STATE; @@ -43,16 +44,18 @@ import kieker.webgui.web.beans.view.CurrentProjectOverviewBean; import org.primefaces.model.UploadedFile; /** - * The {@link ProjectsBean} is a Spring managed bean to manage a list with all application wide available projects. It provides methods to receive this list as well + * This class is a {@code Spring} managed bean to manage a list with all application wide available projects. It provides methods to receive this list as well * as methods to add, create, rename, open and copy projects. Furthermore the state of existing projects (like the timestamp or the state of the analysis) can be * received via this bean. In order to realize a good abstraction, this bean should be used for most accesses to the projects. The necessary synchronization is * achieved in the {@link IProjectService}.<br> - * As this bean contains the whole list of the available projects, it is session scoped. There is no reason for multiple instances of this class. + * As this bean contains the whole list of the available projects, it is singleton scoped. There is no reason for multiple instances of this class. * * @author Nils Christian Ehmke */ @Component @Lazy +@Scope("singleton") +// TODO Remove this bean if possible. It seems to be unnecessary. public final class ProjectsBean { private static final Log LOG = LogFactory.getLog(ProjectsBean.class); @@ -62,6 +65,8 @@ public final class ProjectsBean { private final List<String> projects = Collections.synchronizedList(new ArrayList<String>()); @Autowired private IProjectService projectService; + @Autowired + private GlobalPropertiesBean globalPropertiesBean; /** * Default constructor. <b>Do not use this constructor. This bean is Spring managed.</b> @@ -101,7 +106,7 @@ public final class ProjectsBean { // If there were no exception, everything went well. We can add the project to our list. this.projects.add(project); // Inform the user - GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, "Project created."); + GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, this.globalPropertiesBean.getMsgProjectCreated()); // Update the list of the "calling" bean currentProjectOverviewBean.updateLists(); } catch (final IOException ex) { @@ -134,7 +139,7 @@ public final class ProjectsBean { // If there were no exception, everything went well. We can add the project to our list. this.projects.add(destinationProject); // Inform the user - GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, "Project created."); + GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, this.globalPropertiesBean.getMsgProjectCreated()); // Update the list of the "calling" bean currentProjectOverviewBean.updateLists(); } catch (final IOException ex) { diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ThemeSwitcherBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ThemeSwitcherBean.java index c3e4a28a469112d239fd1a4665ec6909fdb4617d..77956239810e83a799c3c8b387b859c97a661429 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ThemeSwitcherBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ThemeSwitcherBean.java @@ -19,13 +19,23 @@ package kieker.webgui.web.beans.application; import java.util.Collections; import java.util.Map; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + /** - * The {@link ThemeSwitcherBean} is responsible for holding a list with all application wide available themes (look and feels). As this is a static list, it is not - * possible to import new themes during the runtime. The initialization is done in the Spring configuration file.<br> - * This class is a singleton scoped Spring managed bean, as the list with the available themes is a static list. + * This is a {@code Spring} managed bean which is responsible to hold the map with all available themes (look and feels). The content is static, which means that it + * is not possible to add further themes during runtime. If you want to change the themes (or add new ones) take a look into the {@code Spring} configuration + * files.<br> + * </br> + * + * This class is a singleton scoped bean, as the list with the available themes is a static list. + * + * As this bean is {@code Spring} managed, it is <b>not</b> recommended to use the constructor or the setter methods. * * @author Nils Christian Ehmke */ +@Component +@Scope("singleton") public final class ThemeSwitcherBean { private Map<String, String> themes; @@ -37,22 +47,12 @@ public final class ThemeSwitcherBean { // No code necessary } - /** - * Returns the available themes. - * - * @return A map containing the user readable names of the themes as a key and the actual theme-names as the corresponding value. The map can not be modified. - */ public Map<String, String> getThemes() { - return Collections.unmodifiableMap(this.themes); + return this.themes; } - /** - * The setter for the property {@link ThemeSwitcherBean#themes}. <b>Do not use this method. This property is Spring managed.</b> - * - * @param themes - * The value for the property. - */ public void setThemes(final Map<String, String> themes) { - this.themes = themes; + // Make sure that the map with the themes is read-only. + this.themes = Collections.unmodifiableMap(themes); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/package-info.java index 8c6cd69c56fad06aec16a0dad5be4135e60d6792..4d6ac48ba2ba35bd4af97eb9820a5da30d5c13c7 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/package-info.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/package-info.java @@ -15,7 +15,7 @@ ***************************************************************************/ /** - * This package contains Spring managed beans with application (singleton) scope. + * This package contains {@code Spring} managed beans with application (singleton) scope. * * @author Nils Christian Ehmke */ diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/NewUserBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/NewUserBean.java index bcc7a98bcf1f5d08cedca18aea2c7d1721db6045..1f41503182544c41d2783b3a42472148fc662995 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/NewUserBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/NewUserBean.java @@ -22,8 +22,9 @@ import org.springframework.stereotype.Component; import kieker.webgui.domain.User.Role; /** - * This simple bean is request scoped and can be used to store the necessary data for a new user during a request. It is not to be used to deliver a list of users - * for example, as there is a field for a password. + * This simple {@code Spring} managed bean is request scoped and can be used to store the necessary data for a new user during a request. It should not be used, for + * example, to deliver a list containing the available user within the system, as this bean contains a field for the password. For such cases you should use + * {@link kieker.webgui.domain.User} instead. * * @author Nils Christian Ehmke */ @@ -46,78 +47,34 @@ public class NewUserBean { this.active = false; } - /** - * Getter for the property {@link NewUserBean#role}. - * - * @return The current value of the property. - */ public Role getRole() { return this.role; } - /** - * Setter for the property {@link NewUserBean#role}. - * - * @param role - * The new value for the property. - */ public void setRole(final Role role) { this.role = role; } - /** - * Delivers the current value of the property {@link NewUserBean#username}. - * - * @return The current value of the property. - */ public String getUsername() { return this.username; } - /** - * Setter for the property {@link NewUserBean#username}. - * - * @param username - * The new value for the property. - */ public void setUsername(final String username) { this.username = username; } - /** - * Delivers the current value of the property {@link NewUserBean#password}. - * - * @return The current value of the property. - */ public String getPassword() { return this.password; } - /** - * Setter for the property {@link NewUserBean#password}. - * - * @param password - * The new value for the property. - */ public void setPassword(final String password) { this.password = password; } - /** - * Delivers the current value of the property {@link NewUserBean#isActive}. - * - * @return The current value of the property. - */ public boolean isActive() { return this.active; } - /** - * Setter for the property {@link NewUserBean#isActive}. - * - * @param active - * The new value for the property. - */ public void setActive(final boolean active) { this.active = active; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/StringBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/StringBean.java index c8536c16690af624843d58b1c18f539db967652c..07452f0a25870f6d2c73cc3a3b464c51f947bfa0 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/StringBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/StringBean.java @@ -20,9 +20,8 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; /** - * This simple bean can be used to store a string during a request. Furthermore it provides some simple methods to handle strings within the application where a bean - * is necessary. <br> - * For technical reasons this bean is a request scoped bean. + * This simple {@code Spring} managed bean can be used to store a string during a request. Furthermore it provides some simple methods to handle strings within the + * application where a bean is necessary. * * @author Nils Christian Ehmke */ @@ -39,21 +38,10 @@ public final class StringBean { this.string = ""; } - /** - * Delivers the value of this bean. - * - * @return The current string stored within this bean. - */ public String getString() { return this.string; } - /** - * Sets the value of this bean. - * - * @param string - * The new string to be stored within this bean. - */ public void setString(final String string) { this.string = string; } @@ -64,6 +52,7 @@ public final class StringBean { * * @param object * The object to be verified. + * * @return true if and only if the given object is an instance of String. */ public boolean checkString(final Object object) { @@ -78,6 +67,7 @@ public final class StringBean { * The name to be shortened. * @param maxChar * The maximal number of characters. + * * @return The shortened name. */ public String shortenLongName(final String name, final int maxChar) { diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/UploadFileBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/UploadFileBean.java index 5cd35a984b0d80c2c9bbe196e37ccf2346e162c9..eac5cab1f8c9b05a886885fdd9864948a8b26814 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/UploadFileBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/UploadFileBean.java @@ -22,8 +22,7 @@ import org.springframework.stereotype.Component; import org.primefaces.model.UploadedFile; /** - * This simple bean is request scoped and can be used to store the necessary data for a new user during a request. It is not to be used to deliver a list of users - * for example, as there is a field for a password. + * This simple {@code Spring} managed bean is request scoped and can be used to store the necessary data for a file upload. * * @author Nils Christian Ehmke */ @@ -40,21 +39,10 @@ public class UploadFileBean { // No code necessary } - /** - * Getter for the property {@link UploadFileBean#file}. - * - * @return The current value of the property. - */ public UploadedFile getFile() { return this.file; } - /** - * Setter for the property {@link UploadFileBean#file}. - * - * @param file - * The new value of the property. - */ public void setFile(final UploadedFile file) { this.file = file; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/package-info.java index c3da2af58107c70c658f29e22aa6d9f5b4fe0380..79a46170081da4677d7a4ea7ab7fadf401b4ff8b 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/package-info.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/request/package-info.java @@ -15,7 +15,7 @@ ***************************************************************************/ /** - * This package contains Spring managed beans with request scope. + * This package contains {@code Spring} managed beans with request scope. * * @author Nils Christian Ehmke */ diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/UserBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/UserBean.java index 2a7134e465ae137c8e2fa74381cc3507b677b6b6..1b5adbe76459f4e6446dbd36b2fffbd04e741298 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/UserBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/UserBean.java @@ -35,8 +35,11 @@ import org.springframework.stereotype.Component; import kieker.webgui.web.beans.application.GlobalPropertiesBean; /** - * This bean contains information about the user of this session (like the properties and configurations). This class is a Spring managed bean with session scope. - * This means also that it is possible to login the same user multiple times. As it is a session bean, it must implement the {@link Serializable} interface. + * This bean contains information about the user of this session (like the properties and configurations). This class is a {@code Spring} managed bean with session + * scope. This means also that it is possible to login the same user multiple times.<br> + * </br> + * + * As it is a session bean, it must implement the {@link Serializable} interface. * * @author Nils Christian Ehmke */ @@ -87,7 +90,7 @@ public final class UserBean implements Serializable { } /** - * Delivers the role of the current user. + * Delivers the role of the current user. If something goes wrong during the search, it returns a human readable 'N/A'. * * @return The current userrole. */ @@ -106,11 +109,6 @@ public final class UserBean implements Serializable { return userrole; } - /** - * Delivers the {@link UserDetails} of the current user. - * - * @return The current user details. - */ private static UserDetails getUserDetails() { final Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof UserDetails) { @@ -125,82 +123,53 @@ public final class UserBean implements Serializable { * @param globalPropertiesBean * The new value for the property. */ - public void setGlobalPropertiesBean(final GlobalPropertiesBean globalPropertiesBean) { - synchronized (this) { - this.globalPropertiesBean = globalPropertiesBean; - } + public synchronized void setGlobalPropertiesBean(final GlobalPropertiesBean globalPropertiesBean) { + this.globalPropertiesBean = globalPropertiesBean; } - /** - * The getter for the property {@link UserBean#lookAndFeel}. - * - * @return The current value for the property. - */ - public String getLookAndFeel() { - synchronized (this) { - return this.lookAndFeel; - } + public synchronized String getLookAndFeel() { + return this.lookAndFeel; } /** - * The setter for the property {@link UserBean#lookAndFeel}. + * The setter for the property {@link UserBean#lookAndFeel}. The method tries to save the value in the cookies of the user. * * @param lookAndFeel * The new value for the property. */ - public void setLookAndFeel(final String lookAndFeel) { - synchronized (this) { - this.lookAndFeel = lookAndFeel; - UserBean.saveValueInCookie(this.globalPropertiesBean.getThemeCookieName(), lookAndFeel); - } + public synchronized void setLookAndFeel(final String lookAndFeel) { + this.lookAndFeel = lookAndFeel; + UserBean.saveValueInCookie(this.globalPropertiesBean.getThemeCookieName(), lookAndFeel); } - /** - * The getter for the property {@link UserBean#gridColor}. - * - * @return The current value for the property. - */ - public String getGridColor() { - synchronized (this) { - return this.gridColor; - } + public synchronized String getGridColor() { + return this.gridColor; } /** - * The setter for the property {@link UserBean#gridColor}. + * The setter for the property {@link UserBean#gridColor}. The method tries to save the value in the cookies of the user. * * @param gridColor * The new value for the property. */ - public void setGridColor(final String gridColor) { - synchronized (this) { - this.gridColor = gridColor; - UserBean.saveValueInCookie(this.globalPropertiesBean.getAnalysisEditorGridColorCookieName(), gridColor); - } + public synchronized void setGridColor(final String gridColor) { + this.gridColor = gridColor; + UserBean.saveValueInCookie(this.globalPropertiesBean.getAnalysisEditorGridColorCookieName(), gridColor); } - /** - * The getter for the property {@link UserBean#gridSize}. - * - * @return The current value for the property. - */ - public int getGridSize() { - synchronized (this) { - return this.gridSize; - } + public synchronized int getGridSize() { + return this.gridSize; } /** - * The setter for the property {@link UserBean#gridSize}. + * The setter for the property {@link UserBean#gridSize}. The method tries to save the value in the cookies of the user. * * @param gridSize * The new value for the property. */ - public void setGridSize(final int gridSize) { - synchronized (this) { - this.gridSize = gridSize; - UserBean.saveValueInCookie(this.globalPropertiesBean.getAnalysisEditorGridSizeCookieName(), Integer.toString(gridSize)); - } + public synchronized void setGridSize(final int gridSize) { + this.gridSize = gridSize; + UserBean.saveValueInCookie(this.globalPropertiesBean.getAnalysisEditorGridSizeCookieName(), Integer.toString(gridSize)); } /** diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/package-info.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/package-info.java index e2cb640f71f6a3edf6785cce9128e2c80edc1a48..c7a2cde2d3876705cc67ce33d8949025c2b11603 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/package-info.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/session/package-info.java @@ -15,7 +15,7 @@ ***************************************************************************/ /** - * This package contains Spring managed beans with session scope. + * This package contains {@code Spring} managed beans with session scope. * * @author Nils Christian Ehmke */ diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java index 9e1becf2e39cef97a8fd8ddf9e364a21d2b1778c..d099f388b32d91ed78d6e71a2deee8ae515120d2 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; @@ -93,6 +94,7 @@ public final class CurrentAnalysisEditorBean { private ProjectsBean projectsBean; @Autowired private UserBean userBean; + private String currentLayout; /** * Creates a new instance of this class. <b>Do not call this constructor manually. It will only be accessed by Spring.</b> @@ -221,40 +223,19 @@ public final class CurrentAnalysisEditorBean { this.availableComponents = this.projectService.getAvailableComponents(this.projectName); } - /** - * This method delivers the project stored in this bean. - * - * @return The project for this user. - */ public synchronized 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 newName - * The name of the project. - */ public synchronized void setProjectName(final String newName) { // Remember the given parameters this.projectName = newName; } - /** - * This method delivers the project name stored in this bean. - * - * @return The project name for this user. - */ public synchronized String getProjectName() { return this.projectName; } - /** - * This method delivers the available components for the current project. The delivered components are never abstract or programmaticOnly. - * - * @return A list with all components. - */ public synchronized ComponentListContainer getAvailableComponents() { return this.availableComponents; } @@ -266,27 +247,16 @@ public final class CurrentAnalysisEditorBean { this.timeStamp = System.currentTimeMillis(); } - /** - * This method delivers the current time stamp. - * - * @return The time stamp for this user. - */ public synchronized long getTimeStamp() { return this.timeStamp; } - /** - * This method delivers the currently selected plugin (or the currently selected repository). If nothing has been selected, null will be returned. - * - * @return The currently selected plugin or repository. - */ public synchronized MIAnalysisComponent getSelectedPlugin() { return this.selectedComponent; } /** - * 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 the size in - * MiBytes as human readable string. The first element is always the kieker-library. + * This method delivers the available libraries of this project as a pair of strings. The first element is always the kieker-library. * * @return The available libraries. */ @@ -305,6 +275,15 @@ public final class CurrentAnalysisEditorBean { return new ArrayList<String>(); } + /** + * This method should be called before saving the project to deliver the current layout within the request parameter map. + */ + public synchronized void preSaveProject() { + // Get the parameters + final Map<String, String> paramMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap(); + this.currentLayout = paramMap.get("layoutString"); + } + /** * This method tries to save the current project and informs the user about success or fail. * @@ -313,7 +292,7 @@ public final class CurrentAnalysisEditorBean { */ public synchronized void saveProject(final boolean overwriteNewerProject) { try { - this.projectService.saveProject(this.projectName, this.project, this.timeStamp, overwriteNewerProject, this.userBean.getUsername()); + this.projectService.saveProject(this.projectName, this.project, this.timeStamp, overwriteNewerProject, this.userBean.getUsername(), this.currentLayout); GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, this.globalPropertiesBean.getMsgProjectSaved()); // Update the time stamp! this.resetTimeStamp(); @@ -346,7 +325,6 @@ public final class CurrentAnalysisEditorBean { // Add it to the project - and to the graph this.project.getRepositories().add(repository); this.currentAnalysisEditorGraphBean.addRepository(repository); - this.currentAnalysisEditorGraphBean.refreshGraph(); this.setModificationsFlag(); } @@ -368,7 +346,6 @@ public final class CurrentAnalysisEditorBean { } else { this.currentAnalysisEditorGraphBean.addFilter((MIFilter) plugin); } - this.currentAnalysisEditorGraphBean.refreshGraph(); this.setModificationsFlag(); } @@ -515,8 +492,6 @@ public final class CurrentAnalysisEditorBean { for (final MIRepository repository : this.project.getRepositories()) { this.currentAnalysisEditorGraphBean.addRepository(repository); } - // The API demands the graph to be repainted at this point - this.currentAnalysisEditorGraphBean.refreshGraph(); // Now initialize the connections between filters... for (final MIPlugin plugin : this.project.getPlugins()) { @@ -544,12 +519,16 @@ public final class CurrentAnalysisEditorBean { this.currentAnalysisEditorGraphBean.setGridColor(this.userBean.getGridColor()); this.currentAnalysisEditorGraphBean.setGridSize(this.userBean.getGridSize()); - // Perform an initial auto layout - this.currentAnalysisEditorGraphBean.startAutoLayout(); - this.currentAnalysisEditorGraphBean.checkReadOnlyForGuests(); + // Perform either an initial auto layout or use the saved layout - if it exists + final String layout = this.projectService.getLayout(this.projectName); + + if (layout != null) { + this.currentAnalysisEditorGraphBean.loadLayout(layout); + } else { + this.currentAnalysisEditorGraphBean.startAutoLayout(); + } - // Repaint the graph - this.currentAnalysisEditorGraphBean.refreshGraph(); + this.currentAnalysisEditorGraphBean.checkReadOnlyForGuests(); } /** diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java index ff79edc29e2581ad2390faa6322d5b4b54f7d894..1fe0b910f7712cea56e4e28e36e6ee0fbc83acf4 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorGraphBean.java @@ -36,8 +36,7 @@ import kieker.analysis.model.analysisMetaModel.MIRepositoryConnector; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; import kieker.monitoring.core.registry.Registry; -import kieker.webgui.common.exception.InvalidInputSizeException; -import kieker.webgui.common.exception.UninitializedGraphException; +import kieker.webgui.common.exception.GraphLayoutException; import kieker.webgui.service.IGraphLayoutService; import kieker.webgui.web.beans.session.UserBean; @@ -100,9 +99,8 @@ public final class CurrentAnalysisEditorGraphBean { private static final String JS_CMD_SET_READ_ONLY = "graph.setReadOnly(false, true)"; private static final String JS_CMD_SCALE_TO_FIT = "graph.scaleToFit()"; - private static final String JS_CMD_REFRESH_GRAPH = "graph.refresh()"; private static final String JS_CMD_START_AUTO_LAYOUT = "graph.autoLayout()"; - private static final String JS_CMD_LOAD_FROM_LAYOUT = "graph.loadPositionsFromLayout('%s')"; + private static final String JS_CMD_LOAD_FROM_LAYOUT = "graph.loadPositions('%s')"; private static final String JS_CMD_RENAME_NODE = "graph.getNode('%s').name = '%s'"; private static final Object REPOSITORY_INPUT_PORT = "R"; @@ -172,10 +170,7 @@ public final class CurrentAnalysisEditorGraphBean { // Now use it RequestContext.getCurrentInstance().execute(String.format(CurrentAnalysisEditorGraphBean.JS_CMD_LOAD_FROM_LAYOUT, newLayout)); - RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_REFRESH_GRAPH); - } catch (final UninitializedGraphException ex) { - CurrentAnalysisEditorGraphBean.LOG.warn("Autolayout failed.", ex); - } catch (final InvalidInputSizeException ex) { + } catch (final GraphLayoutException ex) { CurrentAnalysisEditorGraphBean.LOG.warn("Autolayout failed.", ex); } } @@ -187,13 +182,6 @@ public final class CurrentAnalysisEditorGraphBean { RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_EDGE_CONSTRAINTS); } - /** - * Refreshes the graph after changes have been made. - */ - public synchronized void refreshGraph() { - RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_REFRESH_GRAPH); - } - /** * This method adds a filter to the current graph. * @@ -571,7 +559,6 @@ public final class CurrentAnalysisEditorGraphBean { final String cmd = String.format(CurrentAnalysisEditorGraphBean.JS_CMD_RENAME_NODE, this.componentMap.get(node), CurrentAnalysisEditorGraphBean.simpleEscape(newName)); RequestContext.getCurrentInstance().execute(cmd); - this.refreshGraph(); } /** @@ -591,35 +578,33 @@ public final class CurrentAnalysisEditorGraphBean { * @return The escaped string. */ private static final String simpleEscape(final String str) { - return str != null ? str.replaceAll("\'", "") : str; + if (str != null) { + return str.replaceAll("\'", ""); + } else { + return str; + } } - /** - * Getter for the property {@link CurrentAnalysisEditorGraphBean#gridEnabled}. - * - * @return The current value of the property. - */ public synchronized boolean isGridEnabled() { return this.gridEnabled; } - /** - * Getter for the property {@link CurrentAnalysisEditorGraphBean#snapEnabled}. - * - * @return The current value of the property. - */ public synchronized boolean isSnapEnabled() { return this.snapEnabled; } + public synchronized void setCurrentAnalysisEditorBean(final CurrentAnalysisEditorBean currentAnalysisEditorBean) { + this.currentAnalysisEditorBean = currentAnalysisEditorBean; + } + /** - * The setter for the field {@link CurrentAnalysisEditorGraphBean#currentAnalysisEditorBean}. + * This method makes sure that the given layout will be loaded by the current graph. * - * @param currentAnalysisEditorBean - * The new value for this field. + * @param layout + * The new layout for the graph. */ - public synchronized void setCurrentAnalysisEditorBean(final CurrentAnalysisEditorBean currentAnalysisEditorBean) { - this.currentAnalysisEditorBean = currentAnalysisEditorBean; + public synchronized void loadLayout(final String layout) { + RequestContext.getCurrentInstance().execute(String.format(CurrentAnalysisEditorGraphBean.JS_CMD_LOAD_FROM_LAYOUT, layout)); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java index ac0bee89a8e301b198ec6b74ffa2bcec8c4d372e..6b93fac86549220d69b7823215b6ca57f68879aa 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitBean.java @@ -47,10 +47,10 @@ import org.primefaces.model.DefaultDashboardColumn; import org.primefaces.model.DefaultDashboardModel; /** - * The {@link CurrentCockpitBean} contains the necessary data behind an instance of the cockpit. It provides methods to read the state of the currently selected - * project.<br> - * The class is a Spring managed bean with view scope to make sure that one user (even in one session) can open multiple projects at a time without causing any - * problems. + * This class is a {@code Spring} managed bean with view scope containing the necessary data behind an instance of the cockpit.<br> + * <br/> + * + * It has view scope to make sure that one user (even in one session) can open multiple projects at a time without causing any problems. * * @author Nils Christian Ehmke */ @@ -58,9 +58,10 @@ import org.primefaces.model.DefaultDashboardModel; @Scope("view") public final class CurrentCockpitBean { - private static final int NUMBER_COLUMNS = 2; private static final Log LOG = LogFactory.getLog(CurrentCockpitBean.class); + private static final int NUMBER_COLUMNS = 2; + private String projectName; private MIProject project; private MIView activeView; @@ -149,21 +150,10 @@ public final class CurrentCockpitBean { this.dashboard.getChildren().clear(); } - /** - * This method delivers the project stored in this bean. - * - * @return The project for this user. - */ public synchronized MIProject getProject() { return this.project; } - /** - * This method sets the project stored within this bean. - * - * @param newName - * The name of the project. - */ public synchronized void setProjectName(final String newName) { // Remember the given parameters this.projectName = newName; @@ -194,11 +184,6 @@ public final class CurrentCockpitBean { } } - /** - * This method delivers the project name stored in this bean. - * - * @return The project name for this user. - */ public synchronized String getProjectName() { return this.projectName; } @@ -243,11 +228,6 @@ public final class CurrentCockpitBean { return "N/A"; } - /** - * Delivers the currently active view. - * - * @return The active view. - */ public synchronized MIView getActiveView() { return this.activeView; } @@ -264,11 +244,6 @@ public final class CurrentCockpitBean { this.fillDashboard(); } - /** - * Getter for the property {@link CurrentCockpitEditorBean#dashboard}. - * - * @return The current value of the property. - */ public synchronized Dashboard getDashboard() { return this.dashboard; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitEditorBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitEditorBean.java index 5e63f81b5c82cc49737d55348d3f6af6497bad82..f07055210be1ab255cbe6424ec15d285ef8c7741 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitEditorBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentCockpitEditorBean.java @@ -204,8 +204,10 @@ public final class CurrentCockpitEditorBean { } catch (final ProjectLoadException ex) { CurrentCockpitEditorBean.LOG.error("An error occured while loading the project.", ex); GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the project."); + } catch (final NullPointerException ex) { + CurrentCockpitEditorBean.LOG.error("An error occured while loading the project.", ex); + GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the project."); } - } /** @@ -287,7 +289,7 @@ public final class CurrentCockpitEditorBean { */ public synchronized void saveProject(final boolean overwriteNewerProject) { try { - this.projectService.saveProject(this.projectName, this.project, this.timeStamp, overwriteNewerProject, this.userBean.getUsername()); + this.projectService.saveProject(this.projectName, this.project, this.timeStamp, overwriteNewerProject, this.userBean.getUsername(), null); GlobalPropertiesBean.showMessage(FacesMessage.SEVERITY_INFO, this.globalPropertiesBean.getMsgProjectSaved()); // Update the time stamp! this.resetTimeStamp(); @@ -328,27 +330,27 @@ public final class CurrentCockpitEditorBean { } } - /** - * Delivers the currently selected view. - * - * @return The currently active view. - */ public synchronized MIView getActiveView() { return this.activeView; } - /** - * This method sets the active view to a new value. - * - * @param view - * The new active view. - */ public synchronized void setActiveView(final MIView view) { this.activeView = view; this.fillDashboard(); } + /** + * Deletes the given view from the model. + * + * @param view + * The view to be removed. + * + */ + public synchronized void deleteView(final MIView view) { + this.project.getViews().remove(view); + } + /** * This method adds the given display to the currently active view. If no view exists, this method does nothing. * diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentControllerBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentControllerBean.java index 1b60b9444681470a2de3fa55d9dbd4b5971e2806..44bc3eae644342d4db7c567a68eea2643853fc4b 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentControllerBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentControllerBean.java @@ -62,23 +62,12 @@ public final class CurrentControllerBean { // No code necessary } - /** - * This method sets the project stored within this bean and returns the new page for the navigation. - * - * @param newName - * The name of the project. - */ public synchronized void setProjectName(final String newName) { // Remember the given parameters this.projectName = newName; } - /** - * This method delivers the project name stored in this bean. - * - * @return The project name for this user. - */ public synchronized String getProjectName() { return this.projectName; } @@ -253,6 +242,8 @@ public final class CurrentControllerBean { } catch (final AnalysisStateException ex) { // Ignore return new Object[0]; + } catch (final NullPointerException ex) { + return new Object[0]; } } @@ -286,11 +277,9 @@ public final class CurrentControllerBean { */ private synchronized void addLogEntry(final String msg) { final String finalMsg = new Date().toString() + " : " + msg; - synchronized (this) { - if (this.logEntries.size() > 50) { - this.logEntries.remove(0); - } - this.logEntries.add(finalMsg); + if (this.logEntries.size() > 50) { + this.logEntries.remove(0); } + this.logEntries.add(finalMsg); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentProjectOverviewBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentProjectOverviewBean.java index 9bf3c9ab2f95dfc05adc8059367b53158b26a30a..9203048d8b61ab667de891e08a816c7d3e162da3 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentProjectOverviewBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentProjectOverviewBean.java @@ -16,7 +16,7 @@ package kieker.webgui.web.beans.view; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; @@ -38,15 +38,10 @@ import org.primefaces.event.SelectEvent; @Component @Scope("view") public final class CurrentProjectOverviewBean { + @Autowired private ProjectsBean projectsBean; - /** - * This list contains all available projects by name. - */ - private List<String> projects = new ArrayList<String>(); - /** - * The name of the "selected" project. - */ + private List<String> projects = Collections.emptyList(); private String projectName; /** @@ -56,21 +51,10 @@ public final class CurrentProjectOverviewBean { // No code necessary } - /** - * Delivers the currently "selected" project name. - * - * @return The name of the project. - */ public String getProjectName() { return this.projectName; } - /** - * Sets the currently "selected" project name. - * - * @param projectName - * The name of the project. - */ public void setProjectName(final String projectName) { this.projectName = projectName; } @@ -85,16 +69,14 @@ public final class CurrentProjectOverviewBean { this.setProjectName((String) event.getObject()); } - /** - * Setter for the property {@link CurrentProjectOverviewBean#projectsBean}. - * - * @param projectsBean - * The new value for the property. - */ public void setProjectsBean(final ProjectsBean projectsBean) { this.projectsBean = projectsBean; } + public List<String> getProjects() { + return this.projects; + } + /** * This method should only be called automatically by Spring to update the projects list. */ @@ -110,13 +92,4 @@ public final class CurrentProjectOverviewBean { this.projects = this.projectsBean.getProjects(); } - /** - * This method delivers all available projects as a list of string. - * - * @return All currently available projects. - */ - public List<String> getProjects() { - return this.projects; - } - } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java index caa0f95b45933168cbe2044af82a7574a5f1376c..f1eb47083164989313f1590176436f15cc23cffd 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentUserManagementBean.java @@ -175,29 +175,14 @@ public final class CurrentUserManagementBean { } } - /** - * This method delivers all available users. - * - * @return All currently available users. - */ public synchronized List<User> getUsers() { return this.availableUsers; } - /** - * Getter for the property {@link CurrentUserManagementBean#selectedUser}. - * - * @return The current value of the property. - */ public synchronized User getSelectedUser() { return this.selectedUser; } - /** - * Getter for the property {@link CurrentUserManagementBean#selectedUserCopy}. - * - * @return The current value of the property. - */ public synchronized User getSelectedUserCopy() { return this.selectedUserCopy; } diff --git a/Kieker.WebGUI/src/main/resources/global.properties b/Kieker.WebGUI/src/main/resources/global.properties index 58f3a8d074638c8b2165ff73df6343a9a66260b3..01314c96ce7cc368885479b1b845edeb3361cb87 100644 --- a/Kieker.WebGUI/src/main/resources/global.properties +++ b/Kieker.WebGUI/src/main/resources/global.properties @@ -14,7 +14,7 @@ kieker.webgui.config.lookAndFeel.facesContextKey = theme kieker.webgui.config.analysisEditor.gridSize.cookieName = analysisEditor.gridSize kieker.webgui.config.analysisEditor.gridColor.cookieName = analysisEditor.gridColor kieker.webgui.config.analysisEditor.defaultGridSize = 50 -kieker.webgui.config.analysisEditor.defaultGridColor = 0080FF +kieker.webgui.config.analysisEditor.defaultGridColor = dbdbdb #------------------------------------------------------------------------------ # diff --git a/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_de.properties b/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_de.properties index 5c3863674fdf176603c92ed148b10db4402c9e90..d827a916efac4408a73222a8c05d7ad2d6a3bc8b 100644 --- a/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_de.properties +++ b/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_de.properties @@ -33,6 +33,7 @@ dependencies = Abh\u00e4ngigkeiten inputPorts = Eingabeports outputPorts = Ausgabeports repositoryPorts = Repositoryports +description = Beschreibung msgProjectModified = Das Projekt wurde in der Zwischenzeit au\u00dferhalb dieses Editors modifiziert. Wollen Sie die \u00c4nderungen \u00fcberschreiben? diff --git a/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_en.properties b/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_en.properties index 4e5c3c68a2939b7fa75ee2000892cf32b56b3116..edf90f756c335687469f692ebcc5cb8618553ea9 100644 --- a/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_en.properties +++ b/Kieker.WebGUI/src/main/resources/lang/AnalysisEditorPage_en.properties @@ -33,7 +33,8 @@ dependencies = Dependencies inputPorts = Input Ports outputPorts = Output Ports repositoryPorts = Repository Ports - +description = Description + msgProjectModified = The project has been modified externally in the meanwhile. Do you want to overwrite the changes? libraries = Libraries diff --git a/Kieker.WebGUI/src/main/resources/lang/ControllerPage_de.properties b/Kieker.WebGUI/src/main/resources/lang/ControllerPage_de.properties index cec041b923abc6460a4fff0054ec377bb33969c1..668c39b739568afeeb60871304c2cf1ed94e281a 100644 --- a/Kieker.WebGUI/src/main/resources/lang/ControllerPage_de.properties +++ b/Kieker.WebGUI/src/main/resources/lang/ControllerPage_de.properties @@ -6,7 +6,7 @@ #------------------------------------------------------------------------------ analysisControllerInstantiateAnalysisController = Analyse Instanziieren -analysisControllerCleaAnalysisController = Analyse Bereinigen +analysisControllerCleaAnalysisController = Analyse Zurücksetzen analysisControllerStartAnalysis = Analyse Starten analysisControllerStopAnalysis = Analyse Stoppen @@ -18,4 +18,11 @@ analysisControllerMsgFailed = Zeigt an, dass der AnalysisController terminiert o control = Steuerung analysisControllerLog = AnalysisController Log -personalLog = Persönlicher Log \ No newline at end of file +personalLog = Persönlicher Log + +state = Status +stateNA = N/A +stateReady = Bereit +stateRunning = Läuft +stateTerminated = Beendet +stateFailed = Absturz \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/resources/lang/ControllerPage_en.properties b/Kieker.WebGUI/src/main/resources/lang/ControllerPage_en.properties index 30bb74895821e04544209a5649159566ff695373..db0e50a153c5cd4287e1102aca510984863512d6 100644 --- a/Kieker.WebGUI/src/main/resources/lang/ControllerPage_en.properties +++ b/Kieker.WebGUI/src/main/resources/lang/ControllerPage_en.properties @@ -6,7 +6,7 @@ #------------------------------------------------------------------------------ analysisControllerInstantiateAnalysisController = Instantiate Analysis -analysisControllerCleaAnalysisController = Clean Analysis +analysisControllerCleaAnalysisController = Reset Analysis analysisControllerStartAnalysis = Start Analysis analysisControllerStopAnalysis = Stop Analysis @@ -18,4 +18,11 @@ analysisControllerMsgFailed = Indicates that the AnalysisController has been ter control = Control analysisControllerLog = AnalysisController Log -personalLog = Personal Log \ No newline at end of file +personalLog = Personal Log + +state = State +stateNA = N/A +stateReady = Ready +stateRunning = Running +stateTerminated = Terminated +stateFailed = Failed \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/resources/lang/LoginPage_de.properties b/Kieker.WebGUI/src/main/resources/lang/LoginPage_de.properties index 7ac6e50e76383af558d33b8759b2e585408206f8..6673d79b39c7d7aea48b4b09e7931feec6c5b642 100644 --- a/Kieker.WebGUI/src/main/resources/lang/LoginPage_de.properties +++ b/Kieker.WebGUI/src/main/resources/lang/LoginPage_de.properties @@ -11,5 +11,8 @@ username = Benutzername password = Passwort login = Anmelden +loginFailed = Login fehlgeschlagen. + +logout = Sie haben sich erfolgreich ausgeloggt. hint = Hinweis: Die Kieker.WebGUI ben\u00f6tigt Cookies und JavaScript, um korrekt zu funktionieren. Bitte stellen Sie sicher, dass beides aktiviert ist. \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/resources/lang/LoginPage_en.properties b/Kieker.WebGUI/src/main/resources/lang/LoginPage_en.properties index faef1b907c2bbeeeba88542541ef27eb6eb9596f..adf89147bfceea390735788fc70da3c8aba2f5b8 100644 --- a/Kieker.WebGUI/src/main/resources/lang/LoginPage_en.properties +++ b/Kieker.WebGUI/src/main/resources/lang/LoginPage_en.properties @@ -12,5 +12,8 @@ username = Username password = Password login = Login +loginFailed = Login failed. + +logout = You have logged out successfully. hint = Hint: The Kieker.WebGUI requires Cookies and JavaScript in order to work correctly. Please make sure that both is enabled. \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/LoginPage.xhtml b/Kieker.WebGUI/src/main/webapp/LoginPage.xhtml index 0a9c6946e3e371f649198eeac7822009070af34c..c6b6a1ee49d6c79083c072eca04921399954304d 100644 --- a/Kieker.WebGUI/src/main/webapp/LoginPage.xhtml +++ b/Kieker.WebGUI/src/main/webapp/LoginPage.xhtml @@ -8,7 +8,7 @@ xmlns:c="http://java.sun.com/jsp/jstl/core"> <h:head/> - + <h:body> <ui:composition template="#{root}/templates/DefaultTemplate.xhtml"> <ui:define name="metadata"> @@ -55,13 +55,13 @@ <c:if test="#{state == 'logout'}"> <div class="hint-panel"> <p:spacer width="0" height="25"/> - <h:outputText value="Sie haben sich erfolgreich ausgeloggt."/><br/> + <h:outputText value="#{localizedLoginMessages.logout}"/><br/> </div> </c:if> <c:if test="#{state == 'fail'}"> <div class="hint-panel"> <p:spacer width="0" height="25" /> - <h:outputText style="color: red" value="Anmeldung fehlgeschlagen."/><br/> + <h:outputText style="color: red" value="#{localizedLoginMessages.loginFailed}"/><br/> </div> </c:if> @@ -72,6 +72,7 @@ </form> </ui:define> </ui:composition> + </h:body> </html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/dialogs/SettingsDialog.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/SettingsDialog.xhtml index bc4bdcdf4f6804e2f2cdbcd6834ec13c899ef6bb..5244b01b9ce537c591f046cf362fd85402b89f1c 100644 --- a/Kieker.WebGUI/src/main/webapp/dialogs/SettingsDialog.xhtml +++ b/Kieker.WebGUI/src/main/webapp/dialogs/SettingsDialog.xhtml @@ -39,7 +39,13 @@ </p:tab> <p:tab title="#{localizedMessages.analysisController}" disabled="true"> </p:tab> - <p:tab title="#{localizedMessages.cockpitEditor}" disabled="true"> + <p:tab title="#{localizedMessages.cockpitEditor}"> + <h:panelGrid columns="2" cellpadding="10" columnClasses="rightAlignedColumn, normalColumn"> + <h:outputText value="Show components without displays:"/> + <p:selectBooleanCheckbox> + + </p:selectBooleanCheckbox> + </h:panelGrid> </p:tab> <p:tab title="#{localizedMessages.cockpit}" disabled="true"> </p:tab> diff --git a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js index 20f468e342589dbe5aa650658478891981e68ea9..a45c120ba25a1fa8c084d43f217f97bead9a0508 100644 --- a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js +++ b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js @@ -55,6 +55,9 @@ function GraphFlow(){ // VARIABLES // ///////////////////////////////////////////// + /** Overall size modifier: the width of node labels in pixels */ + var vertexLabelSize = 12; + var visContainer = 'infovis'; /** Colors */ @@ -72,31 +75,33 @@ function GraphFlow(){ edgeColor = "#114270", edgeColorFocus = "#0098BE"; + /** Custom Node Edges **/ + var customEdgeMap = { + 'none' : + {'edge' : 'flowArrow', + 'getOffset' : function(){return {'x' : 0, 'y' : -2}} + }, + 'inputPort' : + {'edge' : 'flowArrow', + 'getOffset' : function(){return {'x' : -vertexLabelSize, 'y' : vertexLabelSize / 2}} + }, + 'outputPort' : + {'edge' : 'flowArrow', + 'getOffset' : function(){return {'x' : vertexLabelSize, 'y' : vertexLabelSize / 2}} + } + }; + customEdgeMap['repositoryPort'] = customEdgeMap['outputPort']; + /** Icon Images */ var nodeIcons = []; - /** Overall size modifier: the width of node labels in pixels */ - var vertexLabelSize = 12; - - /** FlowGraph Object */ + /** GraphFlow Object */ var fd; /** Nodes and edges that are highlighted when the mouse moves over them */ var hover = null; var markedNode = null; - /** This array stores all Nodes and is initialized with a dummy, - used for drawing edges between a node and the mousepointer. Empty - elements are dynamically reserved for additional nodes. - */ - var json; - - /** Used for dynamically adding and removing space for node creation/deletion - resulting in better performance when manipulating the json array. - */ - var jsonCapacity = {'occupied' : 0, - 'max' : 10}; - /** selected node: {id : the id of the selected node, from : the data.$type of the selected node, label: the label of a selected edge} @@ -106,9 +111,9 @@ function GraphFlow(){ */ var selectedNode = null; - /** This points to a DOM-node (not the json-array node!) which is - an invisible dummy for moving an edge with the mouse - */ + /** This points to an an invisible dummy node which is + used for moving an edge with the mouse + */ var mouseNode = null; /** true if the mouse is over a port/edge */ @@ -126,16 +131,7 @@ function GraphFlow(){ /** Grid dummy-node which is drawn over the graph if it is visible */ - var grid = { 'data': {'$dim' : vertexLabelSize*4, - '$type' : 'grid', - '$color' : '#AAAAFF', - '$width' : document.getElementById(visContainer).clientWidth, - '$height': document.getElementById(visContainer).clientHeight - }, - 'id': '#DUMMY_GRID_NODE', - 'visible': false, - 'snap' : false - }; + var grid; /** Stores information about the canvas, such as its dimensions and its position. This information is needed to correctly draw the Grid and may come in handy in @@ -154,9 +150,7 @@ function GraphFlow(){ 'nodeOffsetY' : 0, // how far a node will be dragged 'dragX' : null, - 'dragY' : null, - // dragged nodefamily and ports - 'draggedNodes' : null}; + 'dragY' : null}; ///////////////////////////////////////////// // FUNCTIONS // @@ -204,10 +198,9 @@ function GraphFlow(){ * @param yPosition - the vertical position of the node * @param node - an object which at least contains an 'id' and may have a 'data' field * @param type - the type of the defined custom node (basic types are: inputPort, nodeFamily, ...) - * @param noPlot - if false, a refresh is required to apply the changes * @param forced - if true, does not throw a listener event */ - this.addCustomNode = function(xPosition, yPosition, node, type, noPlot, forced){ + this.addCustomNode = function(xPosition, yPosition, node, type, forced){ // validate arguments if(!validArg("addCustomNode()", xPosition, "number") || @@ -227,12 +220,10 @@ function GraphFlow(){ var newNode = { "adjacencies": [], "data": { - "$dim": vertexLabelSize, + "$dim": vertexLabelSize, "$type": type, "$icon": nodeIcons[nodeType], "$nodeType": nodeType, - "$xPos": xPosition, - "$yPos": yPosition, "$custom": true }, "id": node.id, @@ -251,15 +242,10 @@ function GraphFlow(){ } } - // add node to json array - json.push(newNode); - // apply changes immediately - if(!noPlot){ - fd.graph.addNode(newNode); - fd.graph.getNode(newNode.id).pos.setc(xPosition, yPosition); - fd.plot(); - } + fd.graph.addNode(newNode); + fd.graph.getNode(newNode.id).pos.setc(xPosition, yPosition); + fd.plot(); // call listener if(!forced){ @@ -287,6 +273,7 @@ function GraphFlow(){ // show text only if it is big enough canvas.showLabels = (canvas.scaleOffsetX > canvas.labelThreshold); + fd.plot(); } /** @@ -314,36 +301,14 @@ function GraphFlow(){ fd.canvas.translate(transX / scale, transY / scale); // update grid dimensions - grid.data.$width = container.clientWidth; - grid.data.$height = container.clientHeight; + grid.data.$width = widthNew; + grid.data.$height = heightNew; - // apply changes to the grid if visible - if(grid.visible){ - var domGrid = fd.graph.getNode(grid.id); - domGrid.data.$width = widthNew; - domGrid.data.$height = heightNew; - } + fd.plot(); } - fd.plot(); } - /** - Concatenates nodefamily 'id's and their x- and y-position - to a string, separating each element with a space. - TODO: save bend points of edges - @return - the resulting string - */ - this.saveNodePositions = function(){ - var positions = ""; - var node; - - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ - node = json[n]; - positions += node.id + " " + node.data.$xPos + " " + node.data.$yPos + " "; - } - - return positions; - } + /** Changes one or more properties of an edge immediately. @@ -351,9 +316,8 @@ function GraphFlow(){ @param targetID - the ID of the node where the edge ends @param properties - a data object that may contain any field from data as well as "id". Data fields must start with a $. - @param noPlot - if true, the graph will not be plotted anew */ - this.setEdgeData = function(sourceID, targetID, properties, noPlot){ + this.setEdgeData = function(sourceID, targetID, properties){ // check arguments if(!validArg("setEdgeData()", sourceID, "string") || @@ -361,17 +325,7 @@ function GraphFlow(){ return; } - var node = getNode(sourceID), - domEdge = fd.graph.getAdjacence(sourceID, targetID), - edge; - - // find edge in json-array - for(var e in node.adjacencies){ - if(e.nodeTo == targetID){ - edge = e; - break; - } - } + var edge = fd.graph.getAdjacence(sourceID, targetID); // iterate through properties object var value; @@ -384,24 +338,20 @@ function GraphFlow(){ if(field == '$type'){ // apply new value to data edge.Edge[field] = value; - if(!noPlot){ domEdge.Edge[field] = value;} } else{ // apply new value to data edge.data[field] = value; - if(!noPlot){ domEdge.data[field] = value;} } } - // make changes to name or id else{ edge[field] = value; - if(!noPlot){ domEdge[field] = value;} } } // apply visual changes - if(!noPlot){ fd.plot();} + fd.plot(); } /** @@ -410,9 +360,8 @@ function GraphFlow(){ @properties - a data object that may contain any field from node.data as well as "name" and "id". Data fields must start with a $. - @noPlot - if true, the graph will not be plotted anew */ - this.setNodeData = function(nodeID, properties, noPlot){ + this.setNodeData = function(nodeID, properties){ // check argument if(!validArg("setNodeData()", nodeID, "string")){ @@ -420,8 +369,7 @@ function GraphFlow(){ } var value; - var node = getNode(nodeID), - domNode = fd.graph.getNode(nodeID); + var node = fd.graph.getNode(nodeID); // iterate through properties object for(var field in properties){ @@ -439,301 +387,487 @@ function GraphFlow(){ } // apply new value to data node.data[field] = value; - if(!noPlot){ domNode.data[field] = value;} } // make changes to name or id else{ node[field] = value; - if(!noPlot){ domNode[field] = value;} } } // recalculate node dimensions in case we changed the font or name if(!node.data.$custom){ - updateNodeWidth(node, domNode); + updateNodeWidth(node); } // apply visual changes - if(!noPlot){ fd.plot();} + fd.plot(); } /** Recalculates the width of a node and repositions the ports. Applies the change immediately. - @param jsonNode - the node in the json array - @param domNode - the node of the actual displayed graph + @param node - the node of the graph */ - function updateNodeWidth(jsonNode, domNode){ - var data = jsonNode.data; + function updateNodeWidth(node){ + var data = node.data; // reserve icon space var iconSpace = 0; - if(nodeIcons[data.$nodeType]){iconSpace = 6;} - + if(nodeIcons[data.$nodeType]){iconSpace = 4;} // calculate width of name - var width = (jsonNode.name.length+4+iconSpace) * vertexLabelSize; + var width = 0; - // check if classname is longer than width - if(data.$nodeClass){ - var classWidth = (data.$nodeClass.length+6+iconSpace)*(vertexLabelSize-2); - width = Math.max(width, classWidth); + var font = data.$font; + if(font){ + font = (data.$dim * 0.83) + font; + }else{ + font = (data.$dim * 0.83) + "px Lucida Console"; } - // update width - jsonNode.data.$width = width; - domNode.data.$width = width; + // calculate width of longest text line + var textArray = node.name; + for(var t in textArray){ + width = Math.max(width, graph.getTextWidth(textArray[t], font)); + } + + // calculate nodeFamily dimensions + width += (4 + iconSpace) * vertexLabelSize; + + // check if the width changed at all + if(node.data.$width == width){ + return; + } + + // calculate how much bigger/smaller the width got + var delta = (width - node.data.$width) / 2; + // update width + node.data.$width = width; width /= 2; // update port positions - var port, domPort, relX, pos, offset, x, y; - for(var p = data.$portIndex+ jsonCapacity.max, l = p + data.$portCount; p < l; p++){ - port = json[p]; - domPort = fd.graph.getNode(port.id); - if(port.data.$relativeX){ - relX = port.data.$relativeX; - if(relX < 0){ - offset = -width; - }else{ - offset = width; - } - - // update relative position - port.data.$relativeX = offset; - domPort.data.$relativeX = offset; - } + var children = data.$children, + parentX = node.pos.getc(true).x, + child, + childPos; + + for(var c in children){ + child = children[c].pos; + childPos = child.getc(true); - // update position - pos = domPort.pos.getc(true); - x = pos.x+offset-relX; - y = pos.y; - domPort.pos.setc(x, y); - port.data.$xPos = x; - port.data.$yPos = y; - } - } - - /** - Reads nodefamily positions out of a string, which was created with - the saveNodePositions() function and moves all nodes to the respective - positions. - @param positions - the string which contains node ids and positions - @param smoothTransition - no functionality at the moment - */ - this.loadNodePositions = function(positions, smoothTransition){ - var pos = positions.split(" "); - var node, x, y; - - for(var i = 0, l = pos.length; i < l; i+=3){ - // look for the node - node = fd.graph.getNode(pos[i]); - - // if node exists, set positions - if(node){ - x = parseFloat(pos[i+1]); - y = parseFloat(pos[i+2]); - - prepareNodeMove(node); - moveNode(x,y); - saveNodeMove(); + if( parentX - childPos.x > 0){ + child.setc(childPos.x - delta, childPos.y); + } + else{ + child.setc(childPos.x + delta, childPos.y); } - } - - //TODO: smooth animation - if(false){ - fd.animate({ - modes: ['linear'], - transition: $jit.Trans.Cubic.easeInOut, - duration: 1000 - }); - } - else{ - fd.plot(); } } + /** - Extracts certain node and edge information and fuses it to a single - String, which will be argument of a listener event and can be used - by an autolayouting algorithm. + Extracts certain node and edge information and fuses it to two + Strings whose elements look like this: + NodeString: isCustomNode, width, height, parentNodeIndex + EdgeString: srcNodeIndex, srcPortIndex, tarNodeIndex0, tarNodeIndex2, ... + + The resulting strings will be arguments of a listener event and can be used + by the KIELER autolayouting algorithm. */ this.autoLayout = function(){ - // this array will contain XMI-Strings - var indexMap = []; // KGraphs use indices instead of IDs - var n, l; + // link node IDs to their index in the graph + var indexMap = {}, + index = 0, + c; - // determine node indices - for(n = 0, l = jsonCapacity.occupied; n < l; n++){ - indexMap[json[n].id] = n; - } + // link port IDs to their family index + var portMap = {}; - // determine port indices - var node, indexCounter = 0; - for(n = jsonCapacity.max, l = json.length; n < l; n++){ - node = json[n]; - if(node.data.$type == "crossBox"){ - indexCounter = 0; + // map nodeIDs to indices + iterateAllNodes(function(node){ + + c = node.data.$custom; + if(c || node.data.$type == 'nodeFamily'){ + indexMap[node.id] = [index, c, node, -1]; + index++; } - else{ - indexMap[node.id] = indexCounter; - indexCounter++; - } - } - - // prepare lots of loop variables - var nodes = ""+ vertexLabelSize, - edges = ""; - - var data, p, pl, a, al, height; - var repoCount, inputCount, outputCount; - var repoY = 0, inputY = 0, outputY = 0; - - // now convert the json array to two simple integer arrays - for(n = 0, l = jsonCapacity.occupied; n < l; n++){ - data = json[n].data; - nodes += " " + data.$width; - height = data.$height; - nodes += " " + height; - height /= 2; - - // count ports - inputCount = 0; - repoCount = 0; - outputCount = 0; - for(p = jsonCapacity.max + data.$portIndex+1, pl = p + data.$portCount -1; p < pl; p++){ - data = json[p].data; - switch(data.$type){ - case "repositoryPort" : - repoCount ++; - if(data.$relativeY){ - repoY = data.$relativeY + height; - } - break; - case "inputPort" : - inputCount ++; - if(data.$relativeY){ - inputY = data.$relativeY + height; - } - break; - case "outputPort" : - outputCount ++; - if(data.$relativeY){ - outputY = data.$relativeY + height; + }); + + // store children/parent relationships + var children, child, pIndex; + + iterateAllNodes(function(node){ + children = node.data.$children; + pIndex = 0; + index = indexMap[node.id]; + + for(c in children){ + // push index of child node to local Array + c = children[c]; + child = indexMap[c.id]; + + // child is a custom node or nodeFamily + if(child){ + child[3] = index[0]; + } + // child is a port + else if(c.data.$type != "crossBox"){ + portMap[c.id] = [index[0], pIndex]; + pIndex ++; + } + } + }); + + var edges = []; + var nodes = [vertexLabelSize]; + + var node, data, localArr; + var nodeY, width, height, nodeIndex; + var edge, adja, a, port; + + // write node data to string + for(index in indexMap){ + index = indexMap[index]; + + nodeIndex = index[0]; + node = index[2]; + data = node.data; + nodeY = node.pos.y; + width = Math.round(data.$width); + height = Math.round(data.$height); + + // start node data with its dimensions + localArr = ['c']; // [0] 'c' if it is a custom node + localArr.push(width); // [1] node width + localArr.push(height); // [2] node height + localArr.push(index[3]); // [3] parent index + + // node is a CustomNode + if(index[1]){ + + // extract edges + edge = [nodeIndex, -1]; + adja = node.adjacencies; + + for(a in adja){ + a = adja[a].data.$direction; + if(a[0] == node.id){ + + // edge is connected to a port + port = portMap[a[1]]; + if(port){ + edge.push(port[0]); + edge.push(port[1]); + } + // edge is connected to a custom node + else{ + edge.push(indexMap[a[1]][0]); + edge.push(-1); } - break; + } } - // check outgoing edges - adja = json[p].adjacencies; - if(adja){ - for( a = 0, al = adja.length; a < al; a++){ - node = adja[a]; - edges += n + " " - + indexMap[node.data.$targetFamily] + " " - + indexMap[node.nodeFrom] + " " - + indexMap[node.nodeTo] + " "; + if(edge.length != 2){ + edges.push(edge.join(" ")); + } + + } + // node is a NodeFamily + else{ + localArr[0] = 'f'; // [0] 'f' if it is a nodeFamily + // info about ports: their number and position + localArr.push(0); // [4] input count + localArr.push(0); // [5] input first y-pos + + localArr.push(0); // [6] repository count + localArr.push(0); // [7] repository first y-pos + + localArr.push(0); // [8] output count + localArr.push(0); // [9] output first y-pos + + // iterate ports and children + children = data.$children; + pIndex = -1; + + for(c in children){ + child = children[c]; + switch(child.data.$type){ + case "inputPort" : + if(localArr[4]++ == 0){ + localArr[5] = Math.round(children[c].pos.y - nodeY + height); + } + break; + + case "repositoryPort" : + if(localArr[6]++ == 0){ + localArr[7] = Math.round(children[c].pos.y - nodeY + height); + } + break; + + case "outputPort" : + if(localArr[8]++ == 0){ + localArr[9] = Math.round(children[c].pos.y - nodeY + height); + } + break; + + default : break; } + + // extract port edges + edge = [nodeIndex, pIndex]; + adja = child.adjacencies; + for(a in adja){ + a = adja[a].data.$direction; + + if(a[0] == child.id){ + // edge is connected to a port + port = portMap[a[1]]; + if(port){ + edge.push(port[0]); + edge.push(port[1]); + } + // edge is connected to a custom node + else{ + edge.push(indexMap[a[1]][0]); + edge.push(-1); + } + } + } + if(edge.length != 2){ + edges.push(edge.join(" ")); + } + + pIndex++; } } - nodes += " " +inputCount + " " - + inputY + " " - + repoCount + " " - + repoY + " " - + outputCount + " " - + outputY; + + // convert node data to string and push it to Array + nodes.push(localArr.join(" ")); + } + // fuse nodes array to a single string + nodes = nodes.join(";"); + edges = edges.join(";"); + + console.log(nodes); + console.log(edges); + callListener("autoLayout", [nodes, edges]); } /** - Assumes that the graph has not been altered since the last call of autolayout(). - Reads a string containing new x,y positions, which are separated by spaces and - moves nodefamilies to the specified positions. + Assumes that the graph has not been altered since the last call of autolayout() + or saveGraphPositions(). + Reads a string containing new x,y positions, as well as dimensons which are + separated by spaces and moves nodefamilies to the specified positions. - @param positions - the position string + @param input - the layout string */ - this.loadPositionsFromLayout = function(input){ - // split string by spaces - var bendPoints, positions; + this.loadPositions = function(input){ + console.log(input); + + var edgeInfo, nodeInfo; { var inputSplit = input.split("#"); - positions = inputSplit[0].split(" "); + + // catch Java Errors here + if(inputSplit[0] == "Error"){ + callListener("onError", ["Error in GraphFlowLayouter.jar : " + inputSplit[1]]); + return; + } + + nodeInfo = inputSplit[0].split(";"); // bend points are optional if(inputSplit[1] && inputSplit[1].length > 0){ - bendPoints = inputSplit[1].split(" "); + edgeInfo = inputSplit[1].split(";"); } } + + // link node IDs to their index in the graph + var indexMap = {}, + index = 0, + c; + + // map indices to nodeIDs + iterateAllNodes(function(node){ + + c = node.data.$custom; + if(c || node.data.$type == 'nodeFamily'){ + indexMap[index] = [c, node]; + index++; + } + }); + // prepare loop variables var node, data, adja, x, y, p = 0; + var width, height; + var xOffset = -grid.data.$width/2, yOffset = -grid.data.$height/2; - //// - // Node Positions + var nodeProps; + var gn, n, l; // iterate nodefamiles - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ + for(n = 0, l = nodeInfo.length - 1; n < l; n++){ + + // catch a layout String which is too long + if(!indexMap[n]){ + callListener("onError", ["Error in loadGraphPositions() : Non-existent Nodes in layout string!"]); + fd.plot(); + return; + } + + nodeProps = nodeInfo[n].split(" "); + p = 0; + // extract positions from string array - x = parseFloat(positions[p++]) + xOffset; - y = parseFloat(positions[p++]) + yOffset; - - // find node in graph and move it - // we do it in this complicated way to - // make smooth node positioning possible - node = fd.graph.getNode(json[n].id); - prepareNodeMove(node); - moveNode(x,y); - saveNodeMove(); - data = json[n].data; - } - - //// - // BendPoints - if(bendPoints){ - - var adja, a, al - e = 0, - bendList = []; - make_bendPoints:{ - // look for ports with edges - for(var po = jsonCapacity.max+1, l = json.length; po < l; po++){ - adja = json[po].adjacencies; - if(adja){ - // iterate through outgoing edges - for(a = 0, al = adja.length; a < al; a++){ - if(e == bendPoints.length){ - break make_bendPoints; - } - + x = parseFloat(nodeProps[p++]) + xOffset; + y = parseFloat(nodeProps[p++]) + yOffset; + width = parseFloat(nodeProps[p++]); + height = parseFloat(nodeProps[p]); + + // find node in graph and move/resize it + node = indexMap[n][1]; + + // is custom node + if(indexMap[n][0]){ + node.pos.setc(x, y); + node.setData('width', width, 'end'); + node.setData('height', height, 'end'); + } + // is nodeFamily + else{ + moveNode(node, x, y); + } + } + + if(edgeInfo){ + var adja, a; + + var e = 0; + var b, bendArray, bendPoints; + var el = edgeInfo.length; + + // iterate all nodes, looking for adjacencies + iterateAllNodes(function(node){ + + // stop if we have more edges than + // defined by out layout string + if(e >= el){ + fd.plot(); + return; + } + + adja = node.adjacencies; + + for(a in adja){ + a = adja[a].data.$direction; + if(a[0] == node.id){ + if(edgeInfo[e] != "" ){ // read from bend point string - while(bendPoints[e] != ";" && bendPoints[e] != ""){ - x = parseFloat(bendPoints[e++]) + xOffset; - y = parseFloat(bendPoints[e++]) + yOffset; - bendList.push({'x':x, 'y':y}); - } - if(bendList.length > 0){ - setBendPoints(adja[a].nodeFrom, adja[a].nodeTo, bendList); - // prepare a new set of bend points - bendList = []; + bendArray = edgeInfo[e].split(" "); + bendPoints = []; + b = 0; + l = bendArray.length; + + while(b < l && bendArray[b] != "" ){ + x = parseFloat(bendArray[b++]) + xOffset; + y = parseFloat(bendArray[b++]) + yOffset; + bendPoints.push({'x':x, 'y':y}); } - // increment if we have a separating semicolon - e++; + setBendPoints(a[0], a[1], bendPoints); + }else{ + setBendPoints(a[0], a[1], null); } + e++; } } - } + }); } - // may be animated in the future + + /* + fd.animate({ + modes: ['node-property:width:height'], + transition: $jit.Trans.Cubic.easeInOut, + duration: 1000 + }); */ fd.plot(); + return; } + + /** + Concatenates node positions and dimensions as well as + bendPoints to a single Layout-String, similar to that + of the GraphFlowLayouter. + @return - the resulting string + */ + this.savePositions = function(){ + var nodeLayout = [], + edgeLayout = []; + var nodeProps, edgeProps; + + var data, nodePos; + var a, adja; + var b, bendPoints; + + // map nodeIDs to indices + iterateAllNodes(function(node){ + data = node.data; + + // retrieve position and dimension of all relevant nodes + if(node.data.$custom || data.$type == 'nodeFamily'){ + nodePos = node.pos.getc(true); + + nodeProps = [ + Math.round(nodePos.x), + Math.round(nodePos.y), + data.$width, + data.$height]; + nodeLayout.push(nodeProps.join(" ")); + } + + // retrieve bendPoints of edges + adja = node.adjacencies; + + for(a in adja){ + data = adja[a].data; + + if(data.$direction[0] == node.id){ + // extract bendPoints + edgeProps = []; + bendPoints = data.$bendPoints; + + for(b in bendPoints){ + edgeProps.push(bendPoints[b].x); + edgeProps.push(bendPoints[b].y); + } + + edgeLayout.push(edgeProps.join(" ")); + } + } + }); + + // fuse all information to a single string + nodeLayout = nodeLayout.join(";"); + edgeLayout = edgeLayout.join(";"); + nodeLayout += "#;" + edgeLayout + ";"; + + callListener("onSavePositions", [nodeLayout]); + + return nodeLayout; + } + + + /** Checks an input color-string for validation. Sends an onError-event if the string is not valid. @@ -784,30 +918,7 @@ function GraphFlow(){ } var id = node.id; - /* - findDuplicate:{ - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ - if(json[n].id == id){ - valid = false; - break findDuplicate; - } - } - - for(var n = jsonCapacity.max, l = json.length; n < l; n++){ - if(json[n].id == id){ - valid = false; - break findDuplicate; - } - } - } - - if(!valid){ - callListener("onError", ["Error in function "+ callFunction - + ": Invalid Node '"+ node - + "'. The ID '"+ id +"' is already taken."]); - } - */ return valid; } @@ -833,38 +944,23 @@ function GraphFlow(){ /** Changes the color of the grid. @param newColor - the new color of the grid - @param noPlot - if true, the graph will not be plotted anew */ - this.setGridColor = function(newColor, noPlot){ + this.setGridColor = function(newColor){ if(validArgColor('setGridColor()', newColor)){ - grid.data.$color = newColor; - // apply changes immediately - if(!noPlot && grid.visible){ - var domGrid = fd.graph.getNode(grid.id); - domGrid.data.$color = newColor; - - fd.plot(); - } + grid.data.$color = newColor; + fd.plot(); } } /** Changes the size of the grid. @param newSize - the new size of the grid - @param noPlot - if true, the graph will not be plotted anew */ - this.setGridSize = function(newSize, noPlot){ + this.setGridSize = function(newSize){ if(validArg('setGridSize()', newSize, 'number')){ grid.data.$dim = newSize; - - // apply changes immediately - if(!noPlot &&grid.visible){ - var domGrid = fd.graph.getNode(grid.id); - domGrid.data.$dim = newSize; - - fd.plot(); - } + fd.plot(); } } @@ -873,28 +969,16 @@ function GraphFlow(){ @param snap - must be true if Nodes should snap */ this.setGridSnap = function(snap){ - grid.snap = snap; + grid.data.$snap = snap; } /** Changes the visibility of the grid. @param visibility - must be true to display the graph - @param noPlot - if true, the graph will not be plotted anew */ - this.setGridVisible = function(visibility, noPlot){ - grid.visible = visibility; - - // apply changes immediately - if(!noPlot){ - if(visibility){ - fd.graph.addNode(grid); - } - else{ - fd.graph.removeNode(grid.id); - } - // apply visual changes - fd.plot(); - } + this.setGridVisible = function(visibility){ + grid.data.$visible = visibility; + fd.plot(); } /** @@ -903,19 +987,19 @@ function GraphFlow(){ */ this.scaleToFit = function(){ // do nothing if the graph is empty - if(jsonCapacity.occupied == 0){ + if(fd.graph.nodes.length == 1){ return; } // init loop variables - var data = json[0].data, - width = data.$width/2, - height = data.$height/2; + var data, + width = 0, + height = 0; - var left = data.$xPos - width, - right = data.$xPos + width, - top = data.$yPos - height, - bottom = data.$yPos + height; + var left = Number.POSITIVE_INFINITY, + right = Number.NEGATIVE_INFINITY, + top = Number.POSITIVE_INFINITY, + bottom = Number.NEGATIVE_INFINITY; // init the outer bounds of the displayed graph var leftMost = left, @@ -924,42 +1008,18 @@ function GraphFlow(){ bottomMost = bottom; // check nodeFamilies for position - for(var n = 1, l= jsonCapacity.occupied; n < l; n++){ - data = json[n].data, - width = data.$width/2, - height = data.$height/2; - - left = data.$xPos - width, - right = data.$xPos + width, - top = data.$yPos - height, - bottom = data.$yPos + height; + iterateAllNodes(function(node){ + data = node.data; - // update bounds - if(left < leftMost){ - leftMost = left; - } - if(right > rightMost){ - rightMost = right; - } - if(top < topMost){ - topMost = top; - } - if(bottom > bottomMost){ - bottomMost = bottom; - } - } - // check custom nodes for position - for(var n = jsonCapacity.max+1, l= json.length; n < l; n++){ - data = json[n].data; + if(data.$custom || data.$type == "nodeFamily"){ - if(data.$custom){ - width = data.$width/2, + width = data.$width/2; height = data.$height/2; - left = data.$xPos - width, - right = data.$xPos + width, - top = data.$yPos - height, - bottom = data.$yPos + height; + left = node.pos.x - width, + right = node.pos.x + width, + top = node.pos.y - height, + bottom = node.pos.y + height; // update bounds if(left < leftMost){ @@ -975,7 +1035,7 @@ function GraphFlow(){ bottomMost = bottom; } } - } + }); // scaling values var canvas = fd.canvas, @@ -986,7 +1046,7 @@ function GraphFlow(){ // translation values var midX = (leftMost + rightMost) / 2, - midY = (topMost + bottomMost) / 2 -vertexLabelSize; + midY = (topMost + bottomMost) / 2 - vertexLabelSize; // translate to origin, scale, and translate to the center of the graph @@ -1002,13 +1062,14 @@ function GraphFlow(){ /** - Assigns an iconPath to a type of node. Needs a refresh() to take effect. + Assigns an iconPath to a type of node. @param nodeType - the type of the node. Typically 'Repository', 'Filter', or 'Reader' @param path - the path to the image. If null, an existing icon will be deleted */ this.setNodeIcon = function(nodeType, path){ + // TODO: give refrence instead of icon to nodes if(!validArg('setNodeIcon()', nodeType, 'string')){ return; } @@ -1017,23 +1078,18 @@ function GraphFlow(){ delete nodeIcons[nodeType]; // remove icons from displayed graph and shrink nodes - var jsonNode, domNode, data; - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ - + var data; + + iterateAllNodes(function(node){ // get data - jsonNode = json[n]; - data = jsonNode.data; + data = node.data; // update node width and port positions if(data.$nodeType == nodeType){ - - domNode = fd.graph.getNode(jsonNode.id); delete data.$icon; - delete domNode.data.$icon; - updateNodeWidth(jsonNode, domNode); + updateNodeWidth(node); } - } - fd.plot(); + }); } else{ if(!validArg('setNodeIcon()', path, 'string')){ @@ -1061,23 +1117,17 @@ function GraphFlow(){ nodeIcons[nodeType] = icon; if(!prevImage){ - - var jsonNode, domNode, data; - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ + var data; + iterateAllNodes(function(node){ // get data - jsonNode = json[n]; - data = jsonNode.data; - + data = node.data; // update node width and port positions if(data.$nodeType == nodeType){ - - domNode = fd.graph.getNode(jsonNode.id); data.$icon = icon; - domNode.data.$icon = icon; - updateNodeWidth(jsonNode, domNode); + updateNodeWidth(node); } - } + }); } fd.plot(); }; @@ -1102,27 +1152,6 @@ function GraphFlow(){ } - /** - Reloads the graph, restoring all positions and displaying all - changes to the graph that happened since the last refresh. - This function needs to be called whenever nodes or egdges are - added or deleted! - */ - this.refresh = function(){ - // reload graph - var mouseIndex = jsonCapacity.max; - - fd.loadGraphFlowJSON(json, mouseIndex); - - if(grid.visible){ - fd.graph.addNode(grid); - } - fd.plot(); - - // set the mouseNode to the freshly created graph node - mouseNode = fd.graph.getNode(json[mouseIndex].id); - } - /** Adds a functionality to the following MouseEvents: onClick, @@ -1235,25 +1264,23 @@ function GraphFlow(){ @param nodeFunction - a single parameter function, called on a node. */ this.iterateAllNodes = function(nodeFunction){ + // check arguments - if(validArg('iterateAllNodes()', nodeFunction, 'function')){ + if(!validArg('iterateAllNodes()', nodeFunction, 'function')){ return; } - - var node; - for(var n=0, l=jsonCapacity.occupied; n < l; n++){ - node = json[n]; - nodeFunction(node); - } - for(var n=jsonCapacity.max+1, l= json.length; n < l; n++){ - node = json[n]; - nodeFunction(node); - } + + // filter out dummy nodes + fd.graph.eachNode(function(node){ + if(node && node.id != "#DUMMY_MOUSE_NODE" && node.id != "#DUMMY_GRID_NODE"){ + nodeFunction(node); + } + }); + } /** Changes the colors of the entire graph. - Requires a refresh(). @param nodeType - the name of the nodeType, whose fill and stroke color are changed @param fillColor - the fill color of nodes. If null, restore Node Color from global Array. @param strokeColor - the stroke color of nodes. If null, restore Stroke Color from global Array. @@ -1279,42 +1306,31 @@ function GraphFlow(){ nodeColorFocus = focusColor; } - var data, a, al, adja; - // change family colors - if(nodeType == "nodeFamily"){ - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ - data = json[n].data; - // change only if node is not marked - if(json[n] != markedNode){ - data.$fillColor = nodeFillColor["nodeFamily"]; - data.$color = nodeStrokeColor["nodeFamily"]; - } - } - } - else{ - // change colors of ports or custom nodes - for(var n = jsonCapacity.max+1, l = json.length; n < l; n++){ - data = json[n].data; - - if(data.$type == nodeType){ - data.$fillColor = nodeFillColor[nodeType]; - data.$color = nodeStrokeColor[nodeType]; - } - // change edge colors - if(edgeColor){ - adja = json[n].adjacencies; // TODO: data.adjacencies? - for(a = 0, al = adja.length; a < al; a++){ - adja[a].data.$color = edgeColor; - } + // change colors + iterateAllNodes(function(node){ + data = node.data; + + if(data.$type == nodeType && node != markedNode.node){ + data.$fillColor = nodeFillColor[nodeType]; + data.$color = nodeStrokeColor[nodeType]; + } + // change edge colors + if(edgeColor){ + //TODO: this + /* + adja = json[n].adjacencies; // TODO: data.adjacencies? + for(a = 0, al = adja.length; a < al; a++){ + adja[a].data.$color = edgeColor; } + */ } - } + }); } /** Permits or prohibits node and edge deletion/creation and hides the deletion-cross - accordingly. Requires a refresh() to hide/show the deletion-crosses. + accordingly. @param deleteCreate - if true, one can change the graph in any way @param move - if true, one can change the graph in any way */ @@ -1323,19 +1339,21 @@ function GraphFlow(){ if(deleteCreate != readOnly.deleteCreate){ // set crossBoxes (in)visible var data; - for(var n=jsonCapacity.max+1, l= json.length; n < l; n++){ - data = json[n].data; + + iterateAllNodes(function(node){ + data = node.data; if(data.$type == "crossBox"){ data.$visible = deleteCreate; - } - } + }); + readOnly.deleteCreate = deleteCreate; } if(move != undefined){ readOnly.move = move; } + fd.plot(); } /** @@ -1394,21 +1412,6 @@ function GraphFlow(){ return; } - // check if we have enough space reserved - var max = jsonCapacity.max; - var occ = jsonCapacity.occupied; - if(occ == max){ - var families = json.slice(0, max); - var ports = json.slice(max); - - for(var n = 0; n < max; n++){ - families.push(null); - } - max *= 2; - jsonCapacity.max = max; - json = families.concat(ports); - } - var maxPorts = Math.max(countInput, countRepo+countOutput+0.5), size = vertexLabelSize*2; @@ -1419,69 +1422,75 @@ function GraphFlow(){ // check if this nodeType has a defined icon if(nodeIcons[nodeType]){ - iconSpace = 6; + iconSpace = 4; } - - var width = (nodeFamily.name.length+4+iconSpace)*vertexLabelSize, - height = size + - Math.max( 2*size, size/2 + maxPorts * size); - // the classname may be longer than the diplayed name - if( nodeFamily.nodeClass){ - width = Math.max(width, (nodeFamily.nodeClass.length+6+iconSpace)*(vertexLabelSize-2)); + // set up font + var font = nodeFamily.font; + if(!font){ font = "Lucida Console";} + font = "px " + font; + + var width = 0, height; + + // calculate width of longest text line + var textArray = nodeFamily.name.split("\n"); + for(var t in textArray){ + width = Math.max(width, graph.getTextWidth(textArray[t], (size * 0.83) + font)); } + // calculate nodeFamily dimensions + width += (4 + iconSpace) * vertexLabelSize; + height = size + Math.max( 2 * size, size/2 + maxPorts * size); + // add big node box // change node color, depending on its type var nodeColor = nodeFillColor["nodeFamily"], strokeColor = nodeStrokeColor["nodeFamily"]; - var font = nodeFamily.font; - if(!font){font = "Lucida Console"} var newNode = { "data": { "$dim": size, "$type": "nodeFamily", - "$jsonIndex": occ, - "$portCount": countRepo+countInput+countOutput, - "$portIndex": json.length - max, "$icon": nodeIcons[nodeType], "$width": width, "$height": height, "$color": strokeColor, "$fillColor": nodeColor, - "$nodeClass": nodeFamily.nodeClass, "$nodeType": nodeType, - "$xPos": xPosition, - "$yPos": yPosition, - "$font": "px "+font, + "$children" : [], + "$font": font, "$movable" : true, "$tooltip": nodeFamily.tooltip }, "id": nodeFamily.id, - "name": nodeFamily.name + "name": textArray//nodeFamily.name }; - json[occ] = newNode; - // add closeButton var closeButton ={ "data": { "$dim": size, "$type": "crossBox", - "$family": newNode, - "$xPos": xPosition+ width/2, - "$yPos": yPosition- height/2, - "$relativeX": width/2, - "$relativeY": -height/2, "$color": strokeColor, "$fillColor": nodeColor, - "$visible": readOnly.deleteCreate + "$visible": readOnly.deleteCreate, + "$movable": false }, "id": nodeFamily.id+".close", "name": "x" }; - json.push(closeButton); - json[occ].data.$portCount++; + + // set up some more data + var g = fd.graph; + g.addNode(newNode); + g.addNode(closeButton); + newNode = g.getNode(nodeFamily.id); + closeButton = g.getNode(closeButton.id); + closeButton.data.$family = newNode; + + // set node positions + newNode.pos.setc(xPosition, yPosition); + closeButton.pos.setc(xPosition + width/2, yPosition - height/2); + newNode.data.$children.push(closeButton); // Loop Info: // This loop adds all port types to the temporary port array. @@ -1526,8 +1535,8 @@ function GraphFlow(){ // continue only if ports exist if(loopPorts != null && loopPorts.length > 0){ - x = xPosition+ relativeX; - y = yPosition+ relativeY; + x = xPosition + relativeX; + y = yPosition + relativeY; for(var p=0; p < loopPorts.length; p++){ var port = loopPorts[p]; @@ -1540,20 +1549,23 @@ function GraphFlow(){ "data": { "$dim": size, "$type": loopType, - "$xPos": x, - "$yPos": y, "$color": nodeStrokeColor[loopType], "$fillColor": nodeColor, "$tooltip": port.tooltip, + "$movable" : false, "$symbol": port.symbol}, "id": nodeFamily.id+"."+port.id, "name": port.name}; - if(p == 0){ + /*if(p == 0){ newPort.data.$relativeX= relativeX; newPort.data.$relativeY= relativeY; - } - json.push(newPort); + }*/ + g.addNode(newPort); + newPort = g.getNode(newPort.id); + newPort.pos.setc(x, y); + newNode.data.$children.push(newPort); + y += size; } } @@ -1564,7 +1576,8 @@ function GraphFlow(){ if(!forced){ callListener("onCreateNode", [newNode]); } - jsonCapacity.occupied++; + fd.plot(); + } /** @@ -1573,7 +1586,7 @@ function GraphFlow(){ @param forced - if true, the node will be removed unconditionally and no event listeners will be called */ - this.removeNode = function(nodeFamily, forced){ + this.removeNode = function(nodeFamily, removeChildren, forced){ // check for valid arguments if(!validArgNode("removeNode()", nodeFamily)){ @@ -1585,119 +1598,44 @@ function GraphFlow(){ } // unmark node - if (markedNode && markedNode.id == nodeFamily.id){ + if (markedNode && markedNode.node.id == nodeFamily.id){ markedNode = null; } - // removalFunction for custom nodes - if(nodeFamily.data.$custom){ - var index = nodeFamily.data.$jsonIndex; - delete json[index]; - json.splice(index, 1); - return; - } - - var deleteFrom = nodeFamily.data.$portIndex + jsonCapacity.max, - deleteUntil = deleteFrom+ nodeFamily.data.$portCount, - familyIndex = nodeFamily.data.$jsonIndex, - occ = --jsonCapacity.occupied; // decrement occupied spaces + var g = fd.graph; - // delete nodeFamily and close button - delete json[familyIndex]; - delete json[deleteFrom]; - - // delete ports - for(var n = deleteFrom+1; n < deleteUntil; n++){ - var portID = json[n].id; - - // remove all incoming edges - for(var e = jsonCapacity.max+1, l = json.length; e < l; e++){ - var incNode = json[e]; - if(incNode){ - removeEdge(incNode.id, portID, true); - } + // remove all children from graph + var children = nodeFamily.data.$children; + if(removeChildren && children){ + var child; + for(var c in children){ + g.removeNode(children[c].id); } - delete json[n]; } + // remove node itself + g.removeNode(nodeFamily.id) - // remove space that was used for ports - var deletionSum = deleteUntil-deleteFrom; - json.splice(deleteFrom, deletionSum); - selectedNode = null; - - // update nodeFamily indices and remove the deletion gap - // in the array space by shifting all following families up - var data; - for(var n = familyIndex; n < occ; n++){ - json[n] = json[n+1]; - data = json[n].data; - data.$jsonIndex--; - data.$portIndex-= deletionSum; - - } - json[occ] = null; - - // check if we should remove some space - var max = jsonCapacity.max; - if( (occ*4) < max && max > 10){ - var ports = json.slice(max); - - max /= 2; - jsonCapacity.max = max; - var families = json.slice(0, max); - json = families.concat(ports); - } + fd.plot(); return; } - /** - Prepares a drag operation for a node, caching all graph nodes that need to be moved. - This speeds up the moveNode() function considerably. - @param node - the node which will be moved - */ - function prepareNodeMove(node){ - - var nodes = []; - - // memorize the nodeFamily - nodes.push(node); - - // memorize all ports and the crossbox if it is a nodefamily - if(!node.data.$custom){ - var familyIndex = node.data.$jsonIndex, - moveFrom = node.data.$portIndex+ jsonCapacity.max, - moveUntil = moveFrom+ node.data.$portCount, - subnode; - - for(var i= moveFrom; i< moveUntil; i++){ - subnode = fd.graph.getNode(json[i].id); - nodes.push(subnode); - } - } - - navi.draggedNodes = nodes; - } /** - Moves a nodeFamily and its subnodes to the specified position. + Moves a nodeFamily and its children to the specified position. + @param node - the node to be moved @param xPos - the horizontal position of the moved node. 0 is the center of the canvas' starting position @param yPos - the vertical position of the moved node. 0 is the center of the canvas' starting position */ - function moveNode(xPos, yPos){ - var nodes = navi.draggedNodes, - node = nodes[0], - dim = node.data.$dim; - var x = xPos, - y = yPos; - + function moveNode(node, x, y){ + // snap to grid - if(grid.snap){ + if(grid.data.$snap){ var gridDim = grid.data.$dim, - left = (xPos - node.data.$width/2), - top = (yPos - node.data.$height/2), - right = (xPos + node.data.$width/2), - bottom = (yPos + node.data.$height/2), + left = (x - node.data.$width/2), + top = (y - node.data.$height/2), + right = (x + node.data.$width/2), + bottom = (y + node.data.$height/2), offLeft = Math.abs(left % gridDim), offTop = Math.abs(top % gridDim), @@ -1749,108 +1687,29 @@ function GraphFlow(){ } } - - // set position of nodeFamily - node.pos.setc(x, y); + // parent position + var pos = node.pos.getc(true); + + var deltaX = x - pos.x, + deltaY = y - pos.y; - // set position of ports and crossbox - var nodeX, nodeY; - for(var i= 1, l = nodes.length; i < l; i++){ - node = nodes[i]; - - if(node.data.$relativeX){ - nodeX = x+ node.data.$relativeX; - nodeY = y+ node.data.$relativeY; - } - node.pos.setc(nodeX,nodeY); - nodeY += dim; - } - } - - /** - Saves the position of a node, so that it will be placed there again, - when the graph is refreshed. This function will only be called once - when a node drag operation has finished. - */ - function saveNodeMove(){ - if(navi.draggedNodes){ - var node = navi.draggedNodes[0], - familyIndex = node.data.$jsonIndex, - pos = node.pos.getc(true); - - var data; - if(familyIndex){ - data = json[familyIndex].data; - } - else{ - data = getNode(node.id).data; - } - - // set pos of family box - data.$xPos = pos.x; - data.$yPos = pos.y; - - // move ports if it is a nodefamily - if(!data.$custom){ - var moveFrom = node.data.$portIndex+ jsonCapacity.max-1, - nodes = navi.draggedNodes; - - // set pos of ports - for(var i= 1, l = nodes.length; i < l; i++){ - data = json[moveFrom+i].data; - pos = nodes[i].pos.getc(true); - - data.$xPos = pos.x; - data.$yPos = pos.y; - } - } - navi.draggedNodes = null; + // move parent + node.pos.setc(x, y); + + // move children in relation to their parent + var children = node.data.$children, + child; + if(children){ + for(var c in children){ + + child = children[c]; + pos = child.pos.getc(true); + moveNode(child, pos.x + deltaX, pos.y + deltaY); + //child.pos.setc(pos.x + deltaX, pos.y + deltaY); + } } } - /** - Adds bendpoints to an edge. - @param sourceID - the id of the node from which the edge starts - @param targetID - the id of the node where the edge ends - @param bendPoints - an array of {x,y} objects. - */ - this.addBendPoints = function(sourceID, targetID, bendPoints){ - // check for valid arguments - if(!validArg("addBendPoints()", sourceID, "string")){ - return; - } - if(!validArg("addBendPoints()", targetID, "string")){ - return; - } - - // look up the source node and the nodeFamilys of both nodes - var adja, loopNode; - var sourceFamilyID = sourceID.substring(0, sourceID.indexOf(".")); - - // look for nodefamilies - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ - - loopNode = json[n]; - if(loopNode.id == sourceFamilyID){ - adja = loopNode.adjacencies; - } - } - - // nothing to delete? - if(source == undefined){ - return; - } - var adja = source.adjacencies; - - for(var a=0; a< adja.length; a++){ - if(adja[a].nodeTo == targetID){ - delete adja[a]; - adja.splice(a,1); - break; - } - } - - } /** * Adds a directed edge between two nodes to the graph. @@ -1859,10 +1718,9 @@ function GraphFlow(){ * @param edgeLabel - the label of the edge. Can be null if no label is required * @param forced - if true, creates the edge unconditionally and does not trigger a listener event - @param noPlot - if true, the graph will not be plotted anew * @return true - if the edge was successfully added */ - this.addEdge = function(sourceID, targetID, edgeLabel, forced, noPlot){ + this.addEdge = function(sourceID, targetID, edgeLabel, forced){ // check for valid arguments if(!validArg("addEdge()", sourceID, "string")){ return false; @@ -1874,104 +1732,82 @@ function GraphFlow(){ edgeLabel = null; } - // look up the source node and the nodeFamilys of both nodes - var source, sourceFamily, targetFamily, target; - - var sourceFamilyID = sourceID.substring(0, sourceID.indexOf(".")), - targetFamilyID = targetID.substring(0, targetID.indexOf(".")), - loopNode; - // look for nodefamilies - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ - - loopNode = json[n]; - - if(loopNode.id == sourceFamilyID){ - sourceFamily = loopNode - } - if(loopNode.id == targetFamilyID){ - targetFamily = loopNode - } - } - - // look for ports - for(var n = jsonCapacity.max, l = json.length; n < l; n++){ - loopNode = json[n]; - - if(loopNode.id == sourceID){ - source = loopNode; - } - if(loopNode.id == targetID){ - target = loopNode; - } - } - - // the standard data set, which may be manipulated by event listeners - var data = {}; - - // call listener if the edge is not connected to the dummy node and check for permission - if(!forced && sourceID != mouseNode.id && targetID != mouseNode.id){ - - // check if ports and families were found - if(!((sourceFamily || source.data.$custom) && source)){ - callListener("onError", ["Error in function addEdge(): The source port '" + sourceID + "' does not exist."]); - return false; - } - if(!((targetFamily || target.data.$custom) && target)){ - callListener("onError", ["Error in function addEdge(): The target port '" + targetID + "' does not exist."]); - return false; - } - - if (!callListener("onCreateEdge", [sourceFamily, targetFamily, source, target, data])){ - return false; - } - } - - // if edge is connected to mouse, there is no targetFamily... - var targetFamilyID = null; - if(targetFamily){ - targetFamilyID = targetFamily.id; - } + // look up the nodes which are to be connected + var g = fd.graph; + var sourcePort = g.getNode(sourceID), + targetPort = g.getNode(targetID); - var adja = source.adjacencies; - // source node does not exist? - if(!adja){ + // check if ports were found + if(!sourcePort){ + callListener("onError", ["Error in function addEdge(): The source node '" + sourceID + "' does not exist."]); return false; } - - var edge ={ - "nodeTo": targetID, - "nodeFrom": sourceID, - "data": {"$direction" : [ sourceID, targetID ], - "$targetFamily" : targetFamilyID, - "$color" : edgeColor} - }; - - // change data if it was specified by the event listener - for(var d in data){ - edge.data[d] = data[d]; + if(!targetPort){ + callListener("onError", ["Error in function addEdge(): The target node '" + targetID + "' does not exist."]); + return false; } - // add label + // the standard data set, which may be manipulated by event listeners + var data = + {"$direction" : [ sourceID, targetID ], + "$color" : edgeColor, + "$type" : customEdgeMap[sourcePort.data.$type].edge, + "$offsetFrom" : + customEdgeMap[sourcePort.data.$type].getOffset(sourcePort, targetPort, data), + "$offsetTo" : + customEdgeMap[targetPort.data.$type].getOffset(sourcePort, targetPort, data)}; + + // add label to data if(edgeLabel){ - edge.data.$label = edgeLabel; + data.$label = edgeLabel; } - // mouse edge + // if it is a dangling edge, no listener needs to be called if(sourceID == mouseNode.id || targetID == mouseNode.id){ - edge.data.$type = "mouseArrow"; + data.$isMouseEdge = true; + + // apply changes + fd.graph.addAdjacence(sourcePort, targetPort, data); + fd.plot(); + return true; } - adja.push(edge); + delete data.$isMouseEdge; - // apply changes immediately - - if(!noPlot){ - var domSource = fd.graph.getNode(sourceID), - domTarget = fd.graph.getNode(targetID); - fd.graph.addAdjacence(domSource, domTarget, edge.data); - fd.plot(); + // call listener if the edge is not connected to the dummy node and check for permission + if(!forced){ + // look for nodeFamilies if connected nodes are ports + var sourceFamily, targetFamily; + if(!(sourcePort.data.$custom && targetPort.data.$custom)){ + var children; + iterateAllNodes(function(node){ + + // look for nodeFamilies + if(node.data.$type == "nodeFamily"){ + children = node.data.$children; + + // look through the ports + for(var c in children){ + if(children[c].id == sourceID){ + sourceFamily = node; + } + else if(children[c].id == targetID){ + targetFamily = node; + data.$targetFamily = node.id + } + } + } + }); + } + + if (!callListener("onCreateEdge", [sourceFamily, targetFamily, sourcePort, targetPort, data])){ + return false; + } } + // apply changes + fd.graph.addAdjacence(sourcePort, targetPort, data); + fd.plot(); return true; } @@ -1981,9 +1817,8 @@ function GraphFlow(){ @param sourceID - the ID of the connected outputPort @param targetID - the ID of the connected inputPort @param bendPoints - an array of {"x":..., "y":...} objects - @param noPlot - if true, the graph will not be plotted anew */ - this.setBendPoints = function(sourceID, targetID, bendPoints, noPlot){ + this.setBendPoints = function(sourceID, targetID, bendPoints){ // check for valid arguments if(!validArg("setBendPoints()", sourceID, "string")){ return false; @@ -1992,22 +1827,11 @@ function GraphFlow(){ return false; } - var adja = getNode(sourceID).adjacencies; - // look for the specific edge - for(var a = 0, l = adja.length; a < l; a++){ - if(adja[a].nodeTo == targetID){ - adja[a].data.$bendPoints = bendPoints; - - // update displayed graph (no need for refresh then) - if(!noPlot){ - fd.graph.getAdjacence(sourceID, targetID).data.$bendPoints = bendPoints; - } - break; - } - } + // change data + fd.graph.getAdjacence(sourceID, targetID).data.$bendPoints = bendPoints; // plot visual changes - if(!noPlot){ fd.plot(); } + fd.plot(); } /** @@ -2016,9 +1840,8 @@ function GraphFlow(){ @param targetID - the id of the target Node @param forced - if true, removes the edge unconditionally and does not trigger a listener event - @param noPlot - if true, the graph will not be plotted anew */ - this.removeEdge = function(sourceID, targetID, forced, noPlot){ + this.removeEdge = function(sourceID, targetID, forced){ // check for valid arguments if(!validArg("removeEdge()", sourceID, "string")){ return; @@ -2027,87 +1850,65 @@ function GraphFlow(){ return; } - // look up the source node and the nodeFamilys of both nodes - var source, sourceFamily, targetFamily, target; + // look up the source node and the nodeFamilies of both nodes + var g = fd.graph, + source = g.getNode(sourceID), + target = g.getNode(targetID); - var sourceFamilyID = sourceID.substring(0, sourceID.indexOf(".")), - targetFamilyID = targetID.substring(0, targetID.indexOf(".")), - loopNode; - - // look for ports - for(var n = jsonCapacity.max, l = json.length; n < l; n++){ - loopNode = json[n]; - if(loopNode){ - if(loopNode.id == sourceID){ - source = loopNode; - } - if(loopNode.id == targetID){ - target = loopNode; - } - } - } - - if(!forced){ - // look for nodefamilies - for(var n = 0, l = jsonCapacity.occupied; n < l; n++){ - - loopNode = json[n]; - - if(loopNode.id == sourceFamilyID){ - sourceFamily = loopNode - } - if(loopNode.id == targetFamilyID){ - targetFamily = loopNode - } - } - - // call listener and ask for permission to delete - if(sourceID != mouseNode.id && targetID != mouseNode.id){ - if(!callListener("onRemoveEdge", [sourceFamily, targetFamily, source, target])){ - return; - } - } - } + var adja = g.getAdjacence(sourceID, targetID); // nothing to delete? - if(!source || !source.adjacencies){ + if(!source || !adja){ return; } - var adja = source.adjacencies; - - for(var a=0; a< adja.length; a++){ - if(adja[a].nodeTo == targetID){ - delete adja[a]; - adja.splice(a,1); - break; + + if(!forced && sourceID != mouseNode.id && targetID != mouseNode.id){ + + // look for nodeFamilies if connected nodes are ports + var targetFamily = g.getNode(adja.data.$targetFamily); + var sourceFamily; + if(!(source.data.$custom && target.data.$custom)){ + var children; + iterateAllNodes(function(node){ + + // look for nodeFamilies + if(node.data.$type == "nodeFamily"){ + children = node.data.$children; + + // look through the ports + for(var c in children){ + if(children[c].id == sourceID){ + sourceFamily = node; + break; + } + } + } + }); + } + // call listener and ask for permission to delete + if(!callListener("onRemoveEdge", [sourceFamily, targetFamily, source, target])){ + return; } } - // apply changes immediately - - if(!noPlot){ - fd.graph.removeAdjacence(sourceID, targetID); - fd.plot(); - } + // apply changes + fd.graph.removeAdjacence(sourceID, targetID); + fd.plot(); } /** - Returns a node from the json array + Returns a node from the graph @param nodeID - the id of the desired node @return - the node object or null if the node does not exist */ this.getNode = function(nodeID){ + // check for valid arguments if(!validArg("getNode()", nodeID, "string")){ return; } - for(var n=0, l = json.length; n < l; n++){ - var node = json[n]; - if(node && node.id == nodeID){ - return json[n]; - } - } - return null; + + return fd.graph.getNode(nodeID); } @@ -2121,17 +1922,18 @@ function GraphFlow(){ // animation parameters var trans = $jit.Trans.Quint.easeOut, dur= 200; + // clean up the old highlight - if(hover != null){ + if(hover){ - if(hover.nodeFrom != undefined){ + if(hover.nodeFrom){ hover.setData('lineWidth', 1, 'end'); hover.setData('color', edgeColor, 'end'); } else{ var type = hover.data.$type; - if(markedNode != null && hover.id == markedNode.id){ - hover.setData('color', markedNode.data.$color, 'end'); + if(markedNode != null && hover.id == markedNode.node.id){ + hover.setData('color', markedNode.strokeColor, 'end'); } else{ hover.setData('color', nodeStrokeColor[type], 'end'); @@ -2201,47 +2003,48 @@ function GraphFlow(){ } // clean up the old marking - if(markedNode != null){ + if(markedNode){ - if(markedNode.nodeFrom != undefined){ + if(markedNode.node.nodeFrom){ // ignore edges } else{ - var type = markedNode.data.$type; - markedNode.data.$color = nodeStrokeColor[type]; + var type = markedNode.node.data.$type; + markedNode.node.setData('color', nodeStrokeColor[type], 'end'); // change FillColor only if it exists if(nodeFillColor[type]){ - markedNode.data.$fillColor = nodeFillColor[type]; + markedNode.node.setData('fillColor', nodeFillColor[type], 'end'); } } markedNode = null; } // do we highlight something new? - if(node && node != null){ - // convert dom node to json node + if(node){ if(node.nodeFrom != undefined){ // ignore edges }else{ - var jsonNode = getNode(node.id); - if(!jsonNode){ - callListener("onError", ["Error in function markNode(): Marked Node was deleted."]); - return; - } - if(strokeColor != null){ - jsonNode.data.$color = strokeColor; + node.setData('color', strokeColor, 'end'); } // change FillColor only if it exists if(fillColor != null && nodeFillColor[node.data.$type]){ - jsonNode.data.$fillColor = fillColor; + node.setData('fillColor', fillColor, 'end'); } } - markedNode = jsonNode; + markedNode = { 'strokeColor' : strokeColor, 'fillColor' : fillColor, 'node' : node}; } + + // we need a 0-frame animation to change the colors + fd.animate({ + modes: ['edge-property:color', + 'node-property:color'], + transition: $jit.Trans.Quint.easeOut, + duration: 0 + }); } /** @@ -2298,34 +2101,72 @@ function GraphFlow(){ } } } + + /** + * Tells the Graph information about a CustomNode, as it may be implemented using Plugins. + * @param nodeType - the name of the nodeType + * @param fillColor - + * @param strokeColor - color of the outline of the custom node + * @param edgeOffsetFun(ajacency, isSource) - a function which calculates the offset of a connecting edge + * @param edgeType - the type of edge which is generated when calling connectEdge() on a custom node + */ + this.registerCustomNode = function(nodeType, fillColor, strokeColor, edgeOffsetFun, edgeType){ + + // define the color + setNodeStyle(nodeType, fillColor, strokeColor); + + // define the edge and offset + customEdgeMap[nodeType] = {'edge' : edgeType, 'getOffset' : edgeOffsetFun}; + } + /** Initializes the Graph, enabling canvas navigation and tooltips. - Also the json array is initialized with a dummy mouse node and + Also the graph is initialized with a dummy mouse node and what happens on various mouse events is determined. */ - this.initGraph = function(){ - - if(!json){ - json = [ null, null, null, null, null, null, null, null, null, null, - { - "adjacencies": [], - "data": { - "$dim": 0, - "$type": "none", - "&xPos": 0, - "&typeSelected" : null, - "&yPos": 0 - }, - "id": "#DUMMY_MOUSE_NODE", - "name": "", - "alpha": 0 - }]; + this.initGraph = function(jsonArray){ + var json = []; + + // init json Array + if(jsonArray){ + json = jsonArray; } + + // define mouseNode + json.push({ + "adjacencies": [], + "data": { + "$dim": 0, + "$type": "none", + "&xPos": 0, + "&typeSelected" : null, + "&yPos": 0 + }, + "id": "#DUMMY_MOUSE_NODE", + "name": "", + "alpha": 0 + }); + + // define gridNode + json.push({ + 'data': { + '$dim' : vertexLabelSize*4, + '$type' : 'grid', + '$color' : '#AAAAFF', + '$width' : document.getElementById(visContainer).clientWidth, + '$height': document.getElementById(visContainer).clientHeight, + '$visible' : false, + '$snap' : false + }, + 'id': '#DUMMY_GRID_NODE', + }); + + - fd = new $jit.FlowGraph({ - width : grid.data.$width, - height : grid.data.$height, + fd = new $jit.GraphFlow({ + width : document.getElementById(visContainer).clientWidth, + height : document.getElementById(visContainer).clientHeight, //id of the visualization container injectInto: visContainer, @@ -2432,15 +2273,6 @@ function GraphFlow(){ * EVENT: OnMouseMove */ onMouseMove: function(node, eventInfo, e) { - /*if(!node && navi.isDragging){ - var mousePos = eventInfo.getPos(), - deltaX = mousePos.x - navi.dragX, - deltaY = mousePos.y - navi.dragY; - fd.canvas.translate(deltaX, deltaY); - deltaX = mousePos.x; - deltaY = mousePos.y; - } - */ // are we dragging an edge with the mouse ? if(selectedNode){ var pos = eventInfo.getPos(); @@ -2473,8 +2305,8 @@ function GraphFlow(){ if(node == false || node.id == mouseNode.id || !node.data.$movable){ - navi.dragX = e.layerX//e.pageX; - navi.dragY = e.layerX//e.pageY; + navi.dragX = e.layerX; //e.pageX; + navi.dragY = e.layerY; //e.pageY; navi.isDragging = true; return; } @@ -2499,9 +2331,6 @@ function GraphFlow(){ navi.borderRight = grid.data.$width - (node.data.$width / 2 + navi.nodeOffsetX) * fd.canvas.scaleOffsetX; navi.borderBottom = grid.data.$height - (node.data.$height / 2 + navi.nodeOffsetY) * fd.canvas.scaleOffsetX; - // we memorize all subnodes of the dragged nodefamily, to speed up - // dragging - prepareNodeMove(node); } callListener("onDragStart", [node, eventInfo, e]); }, @@ -2510,8 +2339,8 @@ function GraphFlow(){ * EVENT: OnDragMove */ onDragMove: function(node, eventInfo, e) { - if(selectedNode || !readOnly.move || !node || - node.id == mouseNode.id || !node.data.$movable){ + if(!node || !node.data.$movable || selectedNode || !readOnly.move){ + // || node.id == mouseNode.id){ return; } @@ -2519,7 +2348,7 @@ function GraphFlow(){ var pos = eventInfo.getPos(), x = pos.x + navi.nodeOffsetX, y = pos.y + navi.nodeOffsetY; - moveNode(x, y); + moveNode(node, x, y); // move screen if near edge var screenX = e.layerX, @@ -2547,9 +2376,6 @@ function GraphFlow(){ * EVENT: OnDragEnd */ onDragEnd: function(node, eventInfo, e) { - if(node.data.$movable){ - saveNodeMove(); - } fd.plot(); callListener("onDragEnd", [node, eventInfo, e]); @@ -2568,6 +2394,13 @@ function GraphFlow(){ */ onClick: function(node, eventInfo, e){ + var isNotDragging = true; + + // set mouse position (required for dragging edges) + var pos = eventInfo.getPos(); + mouseNode.pos.setc(pos.x, pos.y-2); + + // finished dragging the screen if(!node){ var deltaX = e.layerX - navi.dragX, @@ -2575,18 +2408,20 @@ function GraphFlow(){ navi.centerX -= deltaX; navi.centerY -= deltaY; + isNotDragging = (Math.abs(deltaX) < 5 && Math.abs(deltaY) < 5); + // remove selection and mouse-edge upon clicking anywhere - if(selectedNode){ - connectEdge(null); - } + if(selectedNode){ + connectEdge(null); + } + fd.plot(); } - else if(mouseOverNode && readOnly.deleteCreate){ + else if(!node.nodeFrom && readOnly.deleteCreate){ var incomingEdge = false; switch(node.data.$type){ case "crossBox": - removeNode(node.data.$family); - refresh(); + removeNode(node.data.$family, true); break; case "nodeFamily": @@ -2597,18 +2432,11 @@ function GraphFlow(){ case "outputPort": case "repositoryPort": connectEdge(node.id, incomingEdge); - // set mouse node position - if(selectedNode){ - var pos = node.pos.getc(true); - // set mouse position - mouseNode.pos.setc(pos.x, pos.y); - fd.plot(); - } break; } } - else if(mouseOverEdge && readOnly.deleteCreate){ + else if(node.nodeFrom && readOnly.deleteCreate){ // no selection yet if(selectedNode == null){ @@ -2621,16 +2449,16 @@ function GraphFlow(){ // create dangling edge connectEdge(source, false, label); - // set mouse position - var pos = eventInfo.getPos(); - mouseNode.pos.setc(pos.x, pos.y-2); fd.plot(); return; } } - callListener("onClick", [node, eventInfo, e]); + if(isNotDragging){ + callListener("onClick", [node, eventInfo, e]); + } + navi.isDragging = false; }, @@ -2640,6 +2468,7 @@ function GraphFlow(){ onMouseWheel: function(e, delta) { // update whether labels should be displayed fd.canvas.showLabels = (fd.canvas.scaleOffsetX > fd.canvas.labelThreshold); + fd.plot(); } }, @@ -2651,14 +2480,23 @@ function GraphFlow(){ }); // load JSON data. - refresh(); + fd.loadJSON(json, 0); + + + // set pointers to grid and mouse node + mouseNode = fd.graph.getNode("#DUMMY_MOUSE_NODE"); + grid = fd.graph.getNode("#DUMMY_GRID_NODE"); // set zoom threshold for displaying text fd.canvas.labelThreshold = 1/vertexLabelSize; fd.canvas.showLabels = true; + + console.log(fd.graph); } // initialize graph initGraph(); return this; -} \ No newline at end of file + +} + \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/js/jit.js b/Kieker.WebGUI/src/main/webapp/js/jit.js index 6712e46afc73a4420d67bb74df05ed9da40d2a4a..f6159958e6478c1289fd347dc461045dc103b1f0 100644 --- a/Kieker.WebGUI/src/main/webapp/js/jit.js +++ b/Kieker.WebGUI/src/main/webapp/js/jit.js @@ -2172,6 +2172,7 @@ Extras.Classes.Events = new Class({ if(canvasWidget == rt.parentNode) return; rt = rt.parentNode; } + if(this.hovered) { this.config.onMouseLeave(this.hovered, event, evt); @@ -2191,6 +2192,7 @@ Extras.Classes.Events = new Class({ onMouseMove: function(e, win, event) { var label, evt = $.event.get(e, win); + if(this.pressed) { this.moved = true; this.config.onDragMove(this.pressed, event, evt); @@ -2210,9 +2212,11 @@ Extras.Classes.Events = new Class({ return; } else { this.config.onMouseLeave(hn, event, evt); + this.hovered = false; } } + if(this.hovered = (event.getNode() || (this.config.enableForEdges && event.getEdge()))) { this.config.onMouseEnter(this.hovered, event, evt); } else { @@ -2265,7 +2269,7 @@ Extras.Classes.Events = new Class({ Used by: - <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>, <FlowGraph> + <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle> See also: @@ -2373,7 +2377,7 @@ Extras.Classes.Tips = new Class({ Used by: - <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>, <FlowGraph> + <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle> See also: @@ -4001,21 +4005,6 @@ $jit.Graph = new Class({ return this.nodes[obj.id]; }, - /** A slight extension of addNode. Restores the node's positions for GraphFlow graphs */ - addGraphFlowNode: function(obj) { - var node = this.addNode(obj); - var x = node.data.$xPos, - y = node.data.$yPos; - if(isNaN(0-x)){ - x = 0; - } - if(isNaN(0-y)){ - y = 0; - } - node.pos.setc(x,y); - return node; - }, - /* Method: addAdjacence @@ -6209,87 +6198,6 @@ var NodeHelper = { 'contains': function(npos, pos, dim) { return NodeHelper.circle.contains(npos, pos, dim); } - }, - /* - Object: NodeHelper.roundRect - */ - 'roundRect': { - /* - Method: render - - Renders a rounded rectangle into the canvas. - - Parameters: - - type - (string) Possible options are 'fill' or 'stroke'. - pos - (object) An *x*, *y* object with the position of the center of the rectangle. - width - (number) The width of the rectangle. - height - (number) The height of the rectangle. - roundness - the radius of the rounded corners. - canvas - (object) A <Canvas> instance. - - Example: - (start code js) - NodeHelper.rectangle.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas); - (end code) - */ - 'render': function(type, pos, width, height, roundness, canvas){ - var hWidth = width/2; - hHeight= height/2; - ctx = canvas.getCtx(), - rWidth = hWidth - roundness, - rHeight = hHeight - roundness; - x = pos.x - rWidth, - y = pos.y - rHeight; - ctx.save(); - - var pif = Math.PI/2, - pit = 3 * pif; - ctx.beginPath(); - // upper left - ctx.arc(x , y , roundness, Math.PI, pit, false); - x = pos.x + rWidth, - ctx.lineTo(x, pos.y - hHeight); - - // upper right - ctx.arc(x , y , roundness, pit, 0, false); - y = pos.y + rHeight, - ctx.lineTo(pos.x + hWidth, y); - - // lower right - ctx.arc(x , y , roundness,0, pif, false); - x = pos.x - rWidth, - ctx.lineTo(x, pos.y + hHeight); - - // lower left - ctx.arc(x , y , roundness, pif, Math.PI, false); - ctx.closePath(); - - ctx[type](); - ctx.restore(); - - }, - /* - Method: contains - - Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. - - Parameters: - - npos - (object) An *x*, *y* object with the <Graph.Node> position. - pos - (object) An *x*, *y* object with the position to check. - width - (number) The width of the rendered rectangle. - height - (number) The height of the rendered rectangle. - - Example: - (start code js) - NodeHelper.rectangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40); - (end code) - */ - 'contains': function(npos, pos, width, height){ - return Math.abs(pos.x - npos.x) <= width / 2 - && Math.abs(pos.y - npos.y) <= height / 2; - } } }; @@ -6431,125 +6339,6 @@ var EdgeHelper = { return EdgeHelper.line.contains(posFrom, posTo, pos, epsilon); } }, - /* - Object: EdgeHelper.flowarrow - */ - 'flowarrow': { - /* - Method: render - - Renders an arrow into the canvas. This arrow is slightly sharper than the standard arrow - - Parameters: - - from - (object) An *x*, *y* object with the starting position of the arrow. - to - (object) An *x*, *y* object with the ending position of the arrow. - dim - (number) The dimension of the arrow. - swap - (boolean) Whether to set the arrow pointing to the starting position or the ending position. - canvas - (object) A <Canvas> instance. - - Example: - (start code js) - EdgeHelper.flowarrow.render({ x: 10, y: 30 }, { x: 10, y: 50 }, 13, false, viz.canvas); - (end code) - */ - 'render': function(from, to, dim, swap, canvas){ - var ctx = canvas.getCtx(); - // invert edge direction - if (swap) { - var tmp = from; - from = to; - to = tmp; - } - var vect = new Complex(to.x - from.x, to.y - from.y); - vect.$scale(dim / vect.norm()); - var intermediatePoint = new Complex(to.x - vect.x, to.y - vect.y), - normal = new Complex(-vect.y / 4, vect.x / 4), - v1 = intermediatePoint.add(normal), - v2 = intermediatePoint.$add(normal.$scale(-1)); - - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - ctx.beginPath(); - ctx.moveTo(v1.x, v1.y); - ctx.lineTo(v2.x, v2.y); - ctx.lineTo(to.x, to.y); - ctx.closePath(); - ctx.fill(); - }, - /* - Method: contains - - Simply copied from rectangle. - Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. - - Parameters: - - posFrom - (object) An *x*, *y* object with a <Graph.Node> position. - posTo - (object) An *x*, *y* object with a <Graph.Node> position. - pos - (object) An *x*, *y* object with the position to check. - epsilon - (number) The dimension of the shape. - - Example: - (start code js) - EdgeHelper.flowarrow.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30); - (end code) - */ - 'contains': function(posFrom, posTo, pos, dim) { - - // is mouse pos within line bounds ? - { - var temp, - minX = posFrom.x, - maxX = posTo.x; - if(minX > maxX){ - temp = maxX; - maxX = minX; - minX = temp; - } - - temp = pos.x; - if(temp < minX-dim || temp > maxX+dim){ - return false; - } - - var minY = posFrom.y, - maxY = posTo.y; - if(minY > maxY){ - temp = maxY; - maxY = minY; - minY = temp; - } - - temp = pos.y; - if(temp < minY-dim || temp > maxY+dim){ - return false; - } - } - - // calculate normal vector of edge - var n = {"x" : (posTo.y - posFrom.y), "y": (posFrom.x - posTo.x)}, - nAbs = Math.sqrt(n.x * n.x + n.y * n.y); - - if(nAbs != 0){ - n.x /= nAbs; - n.y /= nAbs; - } - - // use Hesse-Normal-Form for calculating the distance between edge and mouse pos - var d = (pos.x-posFrom.x)*n.x + (pos.y-posFrom.y)*n.y; - - // is mouse pos close to line ? - if( Math.abs(d) <= dim){ - - return true; - } - - return false; - } - }, /* Object: EdgeHelper.hyperline */ @@ -7179,7 +6968,8 @@ Graph.Plot = { (end code) */ - plot: function(opt, animating) { + plot: function(opt, animating) { + var viz = this.viz, aGraph = viz.graph, canvas = viz.canvas, @@ -7189,7 +6979,7 @@ Graph.Plot = { min = Math.min, opt = opt || this.viz.controller; opt.clearCanvas && canvas.clear(); - + var root = aGraph.getNode(id); if(!root) return; @@ -7226,71 +7016,6 @@ Graph.Plot = { node.visited = !T; }); }, - - /* - Method: plot - - Plots a <Graph>. - - Parameters: - - opt - (optional) Plotting options. Most of them are described in <Options.Fx>. - - Example: - - (start code js) - var viz = new $jit.Viz(options); - viz.fx.plot(); - (end code) - - */ - plotGraphFlow: function(opt, animating) { - var viz = this.viz, - aGraph = viz.graph, - canvas = viz.canvas, - id = viz.root, - that = this, - ctx = canvas.getCtx(), - min = Math.min, - opt = opt || this.viz.controller; - //opt.clearCanvas && canvas.clear(); - - var root = aGraph.getNode(id); - if(!root) return; - - var T = !!root.visited; - aGraph.eachNode(function(node) { - var nodeAlpha = node.getData('alpha'); - node.eachAdjacency(function(adj) { - var nodeTo = adj.nodeTo; - if(!!nodeTo.visited === T && node.drawn && nodeTo.drawn) { - !animating && opt.onBeforePlotLine(adj); - ctx.save(); - ctx.globalAlpha = min(nodeAlpha, - nodeTo.getData('alpha'), - adj.getData('alpha')); - that.plotLine(adj, canvas, animating); - ctx.restore(); - !animating && opt.onAfterPlotLine(adj); - } - }); - ctx.save(); - if(node.drawn) { - !animating && opt.onBeforePlotNode(node); - that.plotNode(node, canvas, animating); - !animating && opt.onAfterPlotNode(node); - } - /*if(!that.labelsHidden && opt.withLabels) { - if(node.drawn && nodeAlpha >= 0.95) { - that.labels.plotLabel(canvas, node, opt); - } else { - that.labels.hideLabel(node, false); - } - }*/ - ctx.restore(); - node.visited = !T; - }); - }, /* Plots a Subtree. @@ -8035,58 +7760,6 @@ var Loader = { this.root = json[i? i : 0].id; } }, - - /** Shamelessly copied from construct(), but accepts empty nodes as well*/ - constructGraphFlow: function(json) { - var ans = new Graph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label); - //make graph - (function (ans, json) { - var getNode = function(id) { - for(var i=0, l=json.length; i<l; i++) { - if(json[i] != null && json[i].id == id) { - return json[i]; - } - } - // The node was not defined in the JSON - // Let's create it - var newNode = { - "id" : id, - "name" : id - }; - return ans.addGraphFlowNode(newNode); - }; - - for(var i=0, l=json.length; i<l; i++) { - if(json[i] != null){ - ans.addGraphFlowNode(json[i]); - var adj = json[i].adjacencies; - if (adj) { - for(var j=0, lj=adj.length; j<lj; j++) { - var node = adj[j], data = {}; - if(typeof adj[j] != 'string') { - data = $.merge(node.data, {}); - node = node.nodeTo; - } - ans.addAdjacence(json[i], getNode(node), data); - } - } - } - } - })(ans, json); - - return ans; - }, - - /** A specialized version that accepts null nodes and refreshes the graph afterwards*/ - loadGraphFlowJSON: function(json, i) { - this.json = json; - //if they're canvas labels erase them. - if(this.labels && this.labels.clearLabels) { - this.labels.clearLabels(true); - } - this.graph = this.constructGraphFlow(json); - this.root = json[i].id; - }, /* Method: toJSON @@ -17172,25 +16845,25 @@ $jit.Hypertree.$extend = true; /////////////////////////////////////////////////////////////////// /* - * File: Layouts.FlowGraph.js + * File: Layouts.GraphFlow.js * */ /* - * Class: Layouts.FlowGraph + * Class: Layouts.GraphFlow * * Implements a Force Directed Layout. * * Implemented By: * - * <FlowGraph> + * <GraphFlow> * * Credits: * * Marcus Cobden <http://marcuscobden.co.uk> * */ -Layouts.FlowGraph = new Class({ +Layouts.GraphFlow = new Class({ getOptions: function(random) { var s = this.canvas.getSize(); var w = s.width, h = s.height; @@ -17213,11 +16886,11 @@ Layouts.FlowGraph = new Class({ }); /* - * File: FlowGraph.js + * File: GraphFlow.js */ /* - Class: FlowGraph + Class: GraphFlow A visualization that lays graphs using a Force-Directed layout algorithm. (for now) @@ -17252,19 +16925,19 @@ Layouts.FlowGraph = new Class({ canvas - Access a <Canvas> instance. graph - Access a <Graph> instance. - op - Access a <FlowGraph.Op> instance. - fx - Access a <FlowGraph.Plot> instance. - labels - Access a <FlowGraph.Label> interface implementation. + op - Access a <GraphFlow.Op> instance. + fx - Access a <GraphFlow.Plot> instance. + labels - Access a <GraphFlow.Label> interface implementation. */ -$jit.FlowGraph = new Class( { +$jit.GraphFlow = new Class( { - Implements: [ Loader, Extras, Layouts.FlowGraph ], + Implements: [ Loader, Extras, Layouts.GraphFlow ], initialize: function(controller) { - var $FlowGraph = $jit.FlowGraph; + var $GraphFlow = $jit.GraphFlow; var config = { iterations: 1, levelDistance: 0 @@ -17295,11 +16968,13 @@ $jit.FlowGraph = new Class( { 'drawn': true } }; + + this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge); - this.labels = new $FlowGraph.Label[canvasConfig.Label.type](this); - this.fx = new $FlowGraph.Plot(this, $FlowGraph); - this.op = new $FlowGraph.Op(this); + this.labels = new $GraphFlow.Label[canvasConfig.Label.type](this); + this.fx = new $GraphFlow.Plot(this, $GraphFlow); + this.op = new $GraphFlow.Op(this); this.json = null; this.busy = false; // initialize extras @@ -17314,7 +16989,8 @@ $jit.FlowGraph = new Class( { */ refresh: function() { //this.compute(); - this.plot(); + this.canvas.clear(); + this.fx.plot(); }, reposition: function() { @@ -17353,7 +17029,7 @@ $jit.FlowGraph = new Class( { In this example I calculate the end positions and then animate the graph to those positions (start code js) - var fg = new $jit.FlowGraph(...); + var fg = new $jit.GraphFlow(...); fg.computeIncremental({ iter: 20, property: 'end', @@ -17370,7 +17046,7 @@ $jit.FlowGraph = new Class( { In this example I calculate all positions and (re)plot the graph (start code js) - var fg = new FlowGraph(...); + var fg = new GraphFlow(...); fg.computeIncremental({ iter: 20, property: ['end', 'start', 'current'], @@ -17385,6 +17061,7 @@ $jit.FlowGraph = new Class( { (end code) */ + /* computeIncremental: function(opt) { opt = $.merge( { iter: 1, // 20 @@ -17395,16 +17072,16 @@ $jit.FlowGraph = new Class( { this.config.onBeforeCompute(this.graph.getNode(this.root)); this.compute(opt.property, opt); - }, + },*/ /* Method: plot - Plots the FlowGraph graph. This is a shortcut to *fx.plot*. + Plots the GraphFlow graph. This is a shortcut to *fx.plot*. */ plot: function() { this.canvas.clear(); - this.fx.plotGraphFlow(); + this.fx.plot(); }, /* @@ -17420,17 +17097,17 @@ $jit.FlowGraph = new Class( { }); -$jit.FlowGraph.$extend = true; +$jit.GraphFlow.$extend = true; -(function(FlowGraph) { +(function(GraphFlow) { /* Method: calculateAnchorPoints - Calculates the anchor points for an edge of the old FlowGraph. + Calculates the anchor points for an edge of the old GraphFlow. Deprecated! */ - FlowGraph.calculateAnchorPoints = function(nodeFrom, nodeTo){ + GraphFlow.calculateAnchorPoints = function(nodeFrom, nodeTo){ var sizeModifier = 12; if(typeof(vertexLabelSize) != 'undefined'){ sizeModifier = vertexLabelSize; @@ -17487,7 +17164,7 @@ $jit.FlowGraph.$extend = true; }, /* - Class: FlowGraph.Op + Class: GraphFlow.Op Custom extension of <Graph.Op>. @@ -17500,14 +17177,14 @@ $jit.FlowGraph.$extend = true; <Graph.Op> */ - FlowGraph.Op = new Class( { + GraphFlow.Op = new Class( { Implements: Graph.Op }); /* - Class: FlowGraph.Plot + Class: GraphFlow.Plot Custom extension of <Graph.Plot>. @@ -17520,13 +17197,117 @@ $jit.FlowGraph.$extend = true; <Graph.Plot> */ - FlowGraph.Plot = new Class( { - Implements: Graph.Plot + GraphFlow.Plot = new Class( { + Implements: Graph.Plot, + + /* + Animates a <GraphFlow>, using the plotGraphFlow function instead of plot. + */ + animate: function(opt, versor) { + opt = $.merge(this.viz.config, opt || {}); + var that = this, + viz = this.viz, + graph = viz.graph, + interp = this.Interpolator, + animation = opt.type === 'nodefx'? this.nodeFxAnimation : this.animation; + //prepare graph values + var m = this.prepare(opt.modes); + + //animate + animation.setOptions($.merge(opt, { + $animating: false, + compute: function(delta) { + graph.eachNode(function(node) { + for(var p in m) { + interp[p](node, m[p], delta, versor); + } + }); + viz.canvas.clear(); + that.plot(opt, this.$animating, delta); + this.$animating = true; + }, + complete: function() { + viz.canvas.clear(); + that.plot(opt); + opt.onComplete(); + opt.onAfterCompute(); + } + })).start(); + }, + + /* + + Method: plot + + Plots a <GraphFlow>. Paints edges above nodes and ignores drawing undefined nodes. + + Parameters: + + opt - (optional) Plotting options. Most of them are described in <Options.Fx>. + + Example: + + (start code js) + var viz = new $jit.Viz(options); + viz.fx.plot(); + (end code) + + */ + plot: function(opt, animating) { + var viz = this.viz, + aGraph = viz.graph, + canvas = viz.canvas, + id = viz.root, + that = this, + ctx = canvas.getCtx(), + min = Math.min, + opt = opt || this.viz.controller; + //opt.clearCanvas && canvas.clear(); + + var root = aGraph.getNode(id); + if(!root) return; + var T = !!root.visited; + + var edges = []; + + aGraph.eachNode(function(node) { + var nodeAlpha = node.getData('alpha'); + node.eachAdjacency(function(adj) { + // memorize all edges, because they will be drawn above everything else + if(!!adj.nodeTo.visited === T && node.drawn && adj.nodeTo.drawn) { + edges.push(adj); + } + }); + ctx.save(); + if(node.drawn) { + !animating && opt.onBeforePlotNode(node); + that.plotNode(node, canvas, animating); + !animating && opt.onAfterPlotNode(node); + } + ctx.restore(); + node.visited = !T; + }); + var paintEdge = function(adj) { + var nodeTo = adj.nodeTo; + !animating && opt.onBeforePlotLine(adj); + ctx.save(); + ctx.globalAlpha = min(nodeTo.getData('alpha'), + adj.getData('alpha')); + that.plotLine(adj, canvas, animating); + ctx.restore(); + !animating && opt.onAfterPlotLine(adj); + }; + + // paint all edges above nodes + for(var e in edges){ + paintEdge(edges[e]); + } + } }); /* - Class: FlowGraph.Label + Class: GraphFlow.Label Custom extension of <Graph.Label>. Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions. @@ -17540,10 +17321,10 @@ $jit.FlowGraph.$extend = true; <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>. */ - FlowGraph.Label = {}; + GraphFlow.Label = {}; /* - FlowGraph.Label.Native + GraphFlow.Label.Native Custom extension of <Graph.Label.Native>. @@ -17556,12 +17337,12 @@ $jit.FlowGraph.$extend = true; <Graph.Label.Native> */ - FlowGraph.Label.Native = new Class( { + GraphFlow.Label.Native = new Class( { Implements: Graph.Label.Native }); /* - FlowGraph.Label.SVG + GraphFlow.Label.SVG Custom extension of <Graph.Label.SVG>. @@ -17574,7 +17355,7 @@ $jit.FlowGraph.$extend = true; <Graph.Label.SVG> */ - FlowGraph.Label.SVG = new Class( { + GraphFlow.Label.SVG = new Class( { Implements: Graph.Label.SVG, initialize: function(viz) { @@ -17613,7 +17394,7 @@ $jit.FlowGraph.$extend = true; }); /* - FlowGraph.Label.HTML + GraphFlow.Label.HTML Custom extension of <Graph.Label.HTML>. @@ -17626,7 +17407,7 @@ $jit.FlowGraph.$extend = true; <Graph.Label.HTML> */ - FlowGraph.Label.HTML = new Class( { + GraphFlow.Label.HTML = new Class( { Implements: Graph.Label.HTML, initialize: function(viz) { @@ -17665,8 +17446,93 @@ $jit.FlowGraph.$extend = true; } }); + + GraphFlow.NodeHelper = { + /* + Object: NodeHelper.roundRect + */ + 'roundRect': { + /* + Method: render + + Renders a rounded rectangle into the canvas. + + Parameters: + + type - (string) Possible options are 'fill' or 'stroke'. + pos - (object) An *x*, *y* object with the position of the center of the rectangle. + width - (number) The width of the rectangle. + height - (number) The height of the rectangle. + roundness - the radius of the rounded corners. + canvas - (object) A <Canvas> instance. + + Example: + (start code js) + NodeHelper.rectangle.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas); + (end code) + */ + 'render': function(type, pos, width, height, roundness, canvas){ + var hWidth = width/2; + hHeight= height/2; + ctx = canvas.getCtx(), + rWidth = hWidth - roundness, + rHeight = hHeight - roundness; + x = pos.x - rWidth, + y = pos.y - rHeight; + ctx.save(); + + var pif = Math.PI/2, + pit = 3 * pif; + ctx.beginPath(); + // upper left + ctx.arc(x , y , roundness, Math.PI, pit, false); + x = pos.x + rWidth, + ctx.lineTo(x, pos.y - hHeight); + + // upper right + ctx.arc(x , y , roundness, pit, 0, false); + y = pos.y + rHeight, + ctx.lineTo(pos.x + hWidth, y); + + // lower right + ctx.arc(x , y , roundness,0, pif, false); + x = pos.x - rWidth, + ctx.lineTo(x, pos.y + hHeight); + + // lower left + ctx.arc(x , y , roundness, pif, Math.PI, false); + ctx.closePath(); + + ctx[type](); + ctx.restore(); + + }, + /* + Method: contains + + Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise. + + Parameters: + + npos - (object) An *x*, *y* object with the <Graph.Node> position. + pos - (object) An *x*, *y* object with the position to check. + width - (number) The width of the rendered rectangle. + height - (number) The height of the rendered rectangle. + + Example: + (start code js) + NodeHelper.rectangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40); + (end code) + */ + 'contains': function(npos, pos, width, height){ + return Math.abs(pos.x - npos.x) <= width / 2 + && Math.abs(pos.y - npos.y) <= height / 2; + } + } + }; + /* - Class: FlowGraph.Plot.NodeTypes + Class: GraphFlow.Plot.NodeTypes This class contains a list of <Graph.Node> built-in types. Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'. @@ -17676,7 +17542,7 @@ $jit.FlowGraph.$extend = true; Example: (start code js) - FlowGraph.Plot.NodeTypes.implement({ + GraphFlow.Plot.NodeTypes.implement({ 'mySpecialType': { 'render': function(node, canvas) { //print your custom node to canvas @@ -17690,57 +17556,11 @@ $jit.FlowGraph.$extend = true; (end code) */ - FlowGraph.Plot.NodeTypes = new Class({ + GraphFlow.Plot.NodeTypes = new Class({ 'none': { 'render': $.empty, 'contains': $.lambda(false) }, - 'flowbox': { - 'render': function(node, canvas){ - // colors - var vertexFillColor = "#F0F0F0"; - - var pos = node.pos.getc(true), - length = node.getData('labelLength'), - dim = node.getData('dim'), - height= 4*dim, - cSize = height/8, - width= (length+2)*dim, - posX = pos.x , - posY = pos.y; - var bx = posX+width/2-cSize, - by = posY-height/2+cSize, - // edge box - ey = posY+ 3*cSize, - // canvas - ctx = canvas.getCtx(); - - // draw Stroke ( in the color, specified in node properties) - this.nodeHelper.rectangle.render('fill', {x: posX, y: posY}, width+4, height+4, canvas); - - // fill box - ctx.fillStyle = vertexFillColor; - this.nodeHelper.rectangle.render('fill', {x: posX, y: posY}, width, height, canvas); - - // draw close-button area - ctx.fillStyle = '#F62929'; - this.nodeHelper.square.render('fill', {x: bx, y: by}, cSize, canvas); - - // draw edge-button area - ctx.fillStyle = '#2929F6'; - this.nodeHelper.circle.render('fill', {x: posX, y: ey}, cSize, canvas); - ctx.fillStyle = '#FFFFFF'; - this.nodeHelper.circle.render('fill', {x: posX, y: ey}, cSize/4, canvas); - }, - 'contains': function(node, pos){ - - var npos = node.pos.getc(true), - dim = node.getData('dim'), - width = ((node.getData('labelLength')+2)*dim)/2, - height = 2*dim; - return Math.abs(pos.x - npos.x) <= width && Math.abs(pos.y - npos.y) <= height; - } - }, /** The nodeFamily is a grey rectangle with a dark stroke. Width, height, and fillColor of the rectangle must @@ -17762,11 +17582,11 @@ $jit.FlowGraph.$extend = true; posY = pos.y; var ctx = canvas.getCtx(); // draw Stroke ( in the color, specified in node properties) - this.nodeHelper.roundRect.render('fill', {x: posX, y: posY}, width+4, height+4, rounded, canvas); + GraphFlow.NodeHelper.roundRect.render('fill', {x: posX, y: posY}, width+4, height+4, rounded, canvas); // fill box ctx.fillStyle = fillColor; - this.nodeHelper.roundRect.render('fill', {x: posX, y: posY}, width, height, rounded, canvas); + GraphFlow.NodeHelper.roundRect.render('fill', {x: posX, y: posY}, width, height, rounded, canvas); //this.nodeHelper.roundRect.render('fill', {x: posX, y: posY+rounded*2}, width, height-4*rounded, rounded, canvas); @@ -17785,7 +17605,7 @@ $jit.FlowGraph.$extend = true; var textSize = 0.83 * dim; if(canvas.showLabels){ - if(name != undefined){ + if(name){ ctx.fillStyle = data.$color; ctx.font = textSize + node.data.$font; textWidth = ctx.measureText(name).width/2; @@ -17794,24 +17614,6 @@ $jit.FlowGraph.$extend = true; ctx.fillText(name, midX, midY); } - - // paint class - - var nodeClass = data.$nodeClass; - if(nodeClass != undefined){ - nodeClass = "<"+nodeClass+">"; - ctx.font = (textSize - 3.22) + data.$font; - - var classWidth = ctx.measureText(nodeClass).width/2; - midX = tX - classWidth; - midY += textSize; - - ctx.fillText(nodeClass, midX, midY); - - if(textWidth < classWidth){ - textWidth = classWidth; - } - } } // draw icon @@ -17847,7 +17649,6 @@ $jit.FlowGraph.$extend = true; } var size = node.data.$dim; - if(canvas.showLabels){ var pos = node.pos.getc(true), hSize = size/2, @@ -18011,7 +17812,9 @@ $jit.FlowGraph.$extend = true; 'grid': { 'render': function(grid, canvas){ - + if(!grid.data.$visible){ + return; + } var scale = 1/canvas.scaleOffsetX, centerX = - canvas.translateOffsetX*scale, centerY = - canvas.translateOffsetY*scale, @@ -18048,8 +17851,346 @@ $jit.FlowGraph.$extend = true; } }); + /* - Class: FlowGraph.Plot.EdgeTypes + * GraphFlow.EdgeHelper + * + * provides some functions for drawing edges and checking if the mouse is within an edge + */ + GraphFlow.EdgeHelper = { + /* + * Checks if pos is anywhere near an edge that may contain bend points + */ + 'contains' : function(adj, pos) { + + if(adj.data.$isMouseEdge){ + return false; + } + + var dim = adj.getData('dim'), + data = adj.data, + inverse = data.$direction[0] != adj.nodeFrom.id, + posFrom = adj.nodeFrom.pos.getc(true), + posTo = adj.nodeTo.pos.getc(true), + offF = data.$offsetFrom, + offT = data.$offsetTo; + + var from = {"x": posFrom.x, "y" : posFrom.y}; + var to = {"x": posTo.x, "y" : posTo.y}; + + // swap if the arrow points in inverse order + if(inverse){ + var temp = to; + to = from; + from = temp; + } + + // add offset + from.x += offF.x; + from.y += offF.y; + to.x += offT.x; + to.y += offT.y; + + // check if mouse is between bendpoints + var bend = adj.data.$bendPoints, + toBend; + + if(bend){ + for(var b = 0, l = bend.length; b < l; b++){ + toBend = bend[b]; + if (GraphFlow.EdgeHelper.isOverEdge(from, toBend, pos, dim)){ + return true; + } + from = bend[b]; + } + + } + return GraphFlow.EdgeHelper.isOverEdge(from, to, pos, dim); + }, + + 'isOverEdge' : function(edgeFrom, edgeTo, checkPos, threshold) { + var cx = checkPos.x, + cy = checkPos.y, + efx = edgeFrom.x, + efy = edgeFrom.y, + etx = edgeTo.x, + ety = edgeTo.y; + + + // is checkPos within line bounds ? + { + var temp, + minX = efx, + maxX = etx; + if(minX > maxX){ + temp = maxX; + maxX = minX; + minX = temp; + } + + temp = cx; + if(temp < minX - threshold || temp > maxX + threshold){ + return false; + } + + var minY = efy, + maxY = ety; + if(minY > maxY){ + temp = maxY; + maxY = minY; + minY = temp; + } + + temp = cy; + if(temp < minY - threshold || temp > maxY + threshold){ + return false; + } + } + + // calculate normal vector of edge + var nx = ety - efy, + ny = efx - etx, + nAbs = Math.sqrt(nx * nx + ny * ny); + + if(nAbs != 0){ + nx /= nAbs; + ny /= nAbs; + } + + // use Hesse-Normal-Form for calculating the distance between edge and mouse pos + var d = (cx - efx)*nx + (cy - efy)*ny; + + // is mouse pos close to line ? + return Math.abs(d) <= threshold ; + }, + + /* + * Draws a straight edge with an arrow head + * + * parameters: + * canvas - the canvas object onto which the edge is drawn + * from - the starting point of the edge + * to - the end point of the edge + * lineType - 0 : normal line + * 1 : dashed line + * 2 : dotted line + * 3 : dashedDotted line + * + * (optional) + * headLength - the length of the arrow head + * headWidth - the width of the arrow head + */ + 'drawEdge' : function(canvas, from, to, lineType, dim, headLength, headWidth){ + + var ctx = canvas.getCtx(); + ctx.beginPath(); + + if(!lineType || lineType == 0){ + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + } + else if(lineType == 1){ + GraphFlow.EdgeHelper.dashedLine(ctx, from, to, dim); + } + else if(lineType == 2){ + GraphFlow.EdgeHelper.dottedLine(ctx, from, to, dim); + } + else if(lineType == 3){ + GraphFlow.EdgeHelper.dashedDottedLine(ctx, from, to, dim); + } + + ctx.stroke(); + + if(!headLength || !headWidth){ + return; + } + + var vect = new Complex(to.x - from.x, to.y - from.y); + vect.$scale(headLength / vect.norm()); + + var intermediatePoint = new Complex(to.x - vect.x, to.y - vect.y); + var normal = new Complex(-vect.y, vect.x); + normal.$scale(headWidth / (2 * normal.norm())); + + var v1 = intermediatePoint.add(normal), + v2 = intermediatePoint.$add(normal.$scale(-1)); + + ctx.beginPath(); + ctx.moveTo(v1.x, v1.y); + ctx.lineTo(v2.x, v2.y); + ctx.lineTo(to.x, to.y); + ctx.closePath(); + ctx.fill(); + }, + + /* + * Draws a simple dashed line between two points + * + * parameters: + * ctx - the canvas context object + * from - a {x,y} object marking the start position of the line + * to - a {x,y} object marking the end position of the line + * dim - the length of each dash + */ + 'dashedLine' : function(ctx, from, to, dim){ + var vx = to.x - from.x, + vy = to.y - from.y, + abs = Math.sqrt(vx * vx + vy * vy), + maxSegments = 2 * abs / dim; + + var dx = from.x, + dy = from.y; + + // set starting point of line + ctx.save(); + ctx.beginPath(); + ctx.moveTo(dx, dy); + + // only draw dashed if we have enough length + if(maxSegments > 1){ + vx *= dim / abs; + vy *= dim / abs; + + var vx2 = vx / 2, + vy2 = vy / 2; + + dx += vx; + dy += vy; + + // draw segments + var segments = 2; + while(segments < maxSegments){ + + ctx.lineTo (dx, dy); + dx += vx2; + dy += vy2; + + ctx.moveTo(dx, dy); + dx += vx; + dy += vy; + + segments+= 3; + } + // always draw the last section + ctx.moveTo(to.x - vx, to.y - vy); + } + ctx.lineTo (to.x, to.y); + ctx.stroke(); + ctx.restore(); + }, + + /* + * Draws a simple dotted line between two points + * + * parameters: + * ctx - the canvas context object + * from - a {x,y} object marking the start position of the line + * to - a {x,y} object marking the end position of the line + * dim - the distance between the dots + */ + 'dottedLine' : function(ctx, from, to, dim){ + var vx = to.x - from.x, + vy = to.y - from.y, + abs = Math.sqrt(vx * vx + vy * vy), + maxSegments = (abs / dim) - 1; + + var dx = from.x, + dy = from.y; + + var xDot = vx / abs, + yDot = vy / abs; + + vx *= dim / abs; + vy *= dim / abs; + + dx += vx; + dy += vy; + + ctx.save(); + ctx.beginPath(); + + // draw segments + var segments = 0; + while(segments < maxSegments){ + ctx.moveTo(dx, dy); + ctx.lineTo (dx + xDot, dy + yDot); + + dx += vx; + dy += vy; + segments++; + } + ctx.stroke(); + ctx.restore(); + }, + + /* + * Draws a line between two points, alternating between a dot and + * a dash + * + * parameters: + * ctx - the canvas context object + * from - a {x,y} object marking the start position of the line + * to - a {x,y} object marking the end position of the line + * dim - the length of each dash + */ + 'dashedDottedLine' : function(ctx, from, to, dim){ + var vx = to.x - from.x, + vy = to.y - from.y, + abs = Math.sqrt(vx * vx + vy * vy), + maxSegments = (abs / ( 2* dim)) - 1; + + var dx = from.x, + dy = from.y; + + // set starting point of line + ctx.save(); + ctx.beginPath(); + ctx.moveTo(dx, dy); + + // only draw dashed if we have enough length + if(maxSegments > 1){ + var xDot = vx / abs, + yDot = vy / abs; + + vx *= dim / abs; + vy *= dim / abs; + + var vx2 = vx / 2, + vy2 = vy / 2; + + dx += vx; + dy += vy; + + // draw segments + var segments = 0; + while(segments < maxSegments){ + + ctx.lineTo (dx, dy); + dx += vx2; + dy += vy2; + + ctx.moveTo(dx, dy); + ctx.lineTo(dx + xDot, dy + yDot); + dx += vx2; + dy += vy2; + + ctx.moveTo(dx, dy); + dx += vx; + dy += vy; + + segments++; + } + // always draw the last section + ctx.moveTo(to.x - vx, to.y - vy); + } + ctx.lineTo (to.x, to.y); + ctx.stroke(); + ctx.restore(); + } + } + + /* + Class: GraphFlow.Plot.EdgeTypes This class contains a list of <Graph.Adjacence> built-in types. Edge types implemented are 'none', and 'flowarrow'. @@ -18059,7 +18200,7 @@ $jit.FlowGraph.$extend = true; Example: (start code js) - FlowGraph.Plot.EdgeTypes.implement({ + GraphFlow.Plot.EdgeTypes.implement({ 'mySpecialType': { 'render': function(adj, canvas) { //print your custom edge to canvas @@ -18073,18 +18214,23 @@ $jit.FlowGraph.$extend = true; (end code) */ - FlowGraph.Plot.EdgeTypes = new Class({ + GraphFlow.Plot.EdgeTypes = new Class({ + 'none': $.empty, 'flowArrow': { 'render': function(adj, canvas) { - var dim = adj.Edge.dim, - inverse = adj.data.$direction[0] != adj.nodeFrom.id, + var data = adj.data, + dim = adj.Edge.dim, + inverse = data.$direction[0] != adj.nodeFrom.id, posFrom = adj.nodeFrom.pos.getc(true), - posTo = adj.nodeTo.pos.getc(true); + posTo = adj.nodeTo.pos.getc(true), + offF = data.$offsetFrom, + offT = data.$offsetTo; + + var from = {"x": posFrom.x, "y" : posFrom.y}; + var to = {"x": posTo.x, "y" : posTo.y}; - var from = {"x": posFrom.x, "y" : posFrom.y+dim/2}; - var to = {"x": posTo.x, "y" : posTo.y+dim/2}; // swap points if the edge direction is "wrong" if(inverse){ var temp = to; @@ -18092,11 +18238,14 @@ $jit.FlowGraph.$extend = true; from = temp; } - to.x -= dim; - from.x += dim; + // add offset + from.x += offF.x; + from.y += offF.y; + to.x += offT.x; + to.y += offT.y; // draw potential bend points - var bend = adj.data.$bendPoints, + var bend = data.$bendPoints, toBend; if(bend){ for(var b = 0, l = bend.length; b < l; b++){ @@ -18105,12 +18254,13 @@ $jit.FlowGraph.$extend = true; from = bend[b]; } } - this.edgeHelper.flowarrow.render(from, to, dim, false, canvas); + + // draw the last line + GraphFlow.EdgeHelper.drawEdge(canvas, from, to, 0, dim, dim, dim /2); // add the label var label = adj.data.$label; if(label != undefined && canvas.showLabels){ - var ctx = canvas.getCtx(); ctx.font = (1.23 * dim)+"px Arial"; var midX = (from.x + to.x - ctx.measureText(label).width) / 2, @@ -18120,85 +18270,11 @@ $jit.FlowGraph.$extend = true; } }, - 'contains': function(adj, pos) { - var dim = adj.getData('dim'), - inverse = adj.data.$direction[0] != adj.nodeFrom.id, - posFrom = adj.nodeFrom.pos.getc(true), - posTo = adj.nodeTo.pos.getc(true); - - var from = {"x": posFrom.x, "y" : posFrom.y+dim/2}; - var to = {"x": posTo.x, "y" : posTo.y+dim/2}; - - // swap if the arrow points in inverse order - if(inverse){ - var temp = to; - to = from; - from = temp; - } - to.x -= dim; - from.x += dim; - - // check if mouse is between bendpoints - var bend = adj.data.$bendPoints, - toBend, - contains = false; - if(bend){ - for(var b = 0, l = bend.length; b < l; b++){ - toBend = bend[b]; - contains |= this.edgeHelper.flowarrow.contains(from, toBend, pos, dim); - from = bend[b]; - } - - } - return contains || this.edgeHelper.flowarrow.contains(from, to, pos, dim); - } - }, - - 'mouseArrow': { - 'render': function(adj, canvas) { - var dim = adj.getData('dim'), - direction = adj.data.$direction, - inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id), - posFrom = adj.nodeFrom.pos.getc(true), - posTo = adj.nodeTo.pos.getc(true); - - var from = {"x": posFrom.x, "y" : posFrom.y+1}; - var to = {"x": posTo.x, "y" : posTo.y+dim/2}; - - if(direction[0] == adj.nodeFrom.id){ - to.x -= dim; - } - else{ - to.x += dim; - } - - this.edgeHelper.flowarrow.render(from, to, dim, inv, canvas); - - // add the label - var label = adj.data.$label; - if(label != undefined && canvas.showLabels){ - var ctx = canvas.getCtx(); - ctx.font = (1.23 * dim)+"px Arial"; - - var midX = (from.x + to.x - ctx.measureText(label).width) / 2, - midY = (from.y + to.y -dim) / 2; - try{ - ctx.fillText(label, midX, midY); - } - catch(e){ - // do nothing. This "fixes" the - // "An invalid or illegal string was specified" - // bug in FireFox - } - } - }, - 'contains': function(adj, pos) { - return false; - } + 'contains': GraphFlow.EdgeHelper.contains } }); -})($jit.FlowGraph); +})($jit.GraphFlow); })(); \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/pages/AnalysisEditorPage.xhtml b/Kieker.WebGUI/src/main/webapp/pages/AnalysisEditorPage.xhtml index b16d5161955d609d8de9c97d01cb41932e5d0022..7a355b3b0cb4056fcc69ac976f930842ec51c535 100644 --- a/Kieker.WebGUI/src/main/webapp/pages/AnalysisEditorPage.xhtml +++ b/Kieker.WebGUI/src/main/webapp/pages/AnalysisEditorPage.xhtml @@ -10,9 +10,8 @@ <h:head/> <h:body> - <ui:composition template="/templates/PagesTemplate.xhtml"> - + <ui:param name="unsavedModifications" value="#{currentAnalysisEditorBean.unsavedModification}"/> <ui:param name="projectName" value="#{currentAnalysisEditorBean.projectName}"/> <ui:param name="pagename" value="analysisEditor"/> @@ -62,6 +61,12 @@ autoLayoutListener = function(nodes, edges) { autoLayoutCommand([{name : 'nodes', value : nodes}, {name : 'edges', value : edges}]); } + + function preSaveProject() { + var layoutString = graph.savePositions(); + preSaveProjectCommand([{name : 'layoutString', value : layoutString}]); + } + </script> </ui:define> @@ -75,6 +80,7 @@ <p:remoteCommand name="edgeCreateCommand" action="#{currentAnalysisEditorGraphBean.edgeCreated()}"/> <p:remoteCommand name="edgeRemoveCommand" action="#{currentAnalysisEditorGraphBean.edgeRemoved()}"/> <p:remoteCommand name="autoLayoutCommand" action="#{currentAnalysisEditorGraphBean.autoLayout()}"/> + <p:remoteCommand name="preSaveProjectCommand" action="#{currentAnalysisEditorBean.preSaveProject()}"/> </h:form> </ui:define> @@ -82,7 +88,7 @@ <ui:define name="furtherMenuBarEntries"> <p:submenu label="#{localizedMessages.file}"> <c:if test="#{sec:areAnyGranted('User, Administrator')}"> - <p:menuitem styleClass="element-with-whitespace" icon="ui-icon-save" value=" #{localizedMessages.saveProject}" update=":messages" ajax="true" action="#{currentAnalysisEditorBean.saveProject(false)}" disabled="#{empty currentAnalysisEditorBean.project}"/> + <p:menuitem styleClass="element-with-whitespace" icon="ui-icon-save" value=" #{localizedMessages.saveProject}" update=":messages" ajax="true" onstart="preSaveProject()" action="#{currentAnalysisEditorBean.saveProject(false)}" disabled="#{empty currentAnalysisEditorBean.project}"/> <p:menuitem styleClass="element-with-whitespace" icon="ui-icon-saveAs" value=" #{localizedMessages.saveProjectAs}" update=":messages" ajax="true" disabled="#{true or empty currentAnalysisEditorBean.project}"/> <p:separator /> </c:if> @@ -118,7 +124,7 @@ <p:tooltip for="btnScaleToFit" value="#{localizedAnalysisEditorPageMessages.analysisEditorScaleToFit}"/> <p:tooltip for="btnGrid" value="#{localizedAnalysisEditorPageMessages.grid}"/> <p:tooltip for="btnSnap" value="#{localizedAnalysisEditorPageMessages.snap}"/> - <p:tooltip for="btnAutoLayout" value="#{localizedAnalysisEditorPageMessages.autoLayout}"/> + <p:tooltip for="btnAutoLayout" value="#{localizedAnalysisEditorPageMessages.autoLayout}"/> </ui:define> <ui:define name="centerContent"> @@ -138,7 +144,7 @@ <h:outputText id="classNameProperty" value="#{localizedAnalysisEditorPageMessages.className}" rendered="#{rowIndex == 0}"/> <h:outputText id="nameProperty" value="#{localizedAnalysisEditorPageMessages.name}" rendered="#{rowIndex == 1}"/> <h:outputText id="normalProperty" value="#{property.name}" rendered="#{rowIndex > 1}"/> - <p:tooltip for="classNameProperty" value="#{localizedAnalysisEditorPageMessages.tooltipClassName}" rendered="#{rowIndex == 0}"/> + <p:tooltip for="classNameProperty" value="#{localizedAnalysisEditorPageMessages.tooltipClassName}" rendered="#{rowIndex == 0}"/> <p:tooltip for="nameProperty" value="#{localizedAnalysisEditorPageMessages.tooltipName}" rendered="#{rowIndex == 1}"/> <p:tooltip for="normalProperty" value="#{currentAnalysisEditorBean.getDescription(currentAnalysisEditorBean.selectedPlugin, property.name)}" rendered="#{rowIndex > 1}"/> </p:column> @@ -154,8 +160,8 @@ <p:inputText value="#{property.value}" /> </p:inplace> <p:tooltip for="className" value="#{localizedAnalysisEditorPageMessages.tooltipClassName}" rendered="#{rowIndex == 0}"/> - <p:tooltip for="nameEditor" value="#{localizedAnalysisEditorPageMessages.tooltipName}" rendered="#{rowIndex == 1}"/> - <p:tooltip for="normalEditor" value="#{currentAnalysisEditorBean.getDescription(currentAnalysisEditorBean.selectedPlugin, property.name)}" rendered="#{rowIndex > 1}"/> + <p:tooltip for="nameEditor" value="#{localizedAnalysisEditorPageMessages.tooltipName}" rendered="#{rowIndex == 1}"/> + <p:tooltip for="normalEditor" value="#{currentAnalysisEditorBean.getDescription(currentAnalysisEditorBean.selectedPlugin, property.name)}" rendered="#{rowIndex > 1}"/> </p:column> </p:dataTable> </h:form> @@ -163,17 +169,24 @@ <c:if test="#{sec:areAnyGranted('User, Administrator')}"> <!-- The following is the toolpalette, presenting the available plugins etc. --> - <p:layoutUnit position="east" size="300" header="#{localizedAnalysisEditorPageMessages.availablePlugins}" resizable="true" collapsible="true"> + <p:layoutUnit position="west" size="300" header="#{localizedAnalysisEditorPageMessages.availablePlugins}" resizable="true" collapsible="true"> <h:form id="toolpalette"> <p:accordionPanel multiple="true" activeIndex="0,1,2"> <p:tab title="#{localizedAnalysisEditorPageMessages.reader}"> <ui:repeat value="#{currentAnalysisEditorBean.availableComponents.readers}" var="reader"> <p:commandLink id="readerLink" value="#{reader.plugin.name}" action="#{currentAnalysisEditorBean.addPlugin(reader)}" update=":messages" disabled="#{not reader.fullyInitialized}" /><br/> <p:tooltip for="readerLink"> - <b><h:outputText value="#{reader.plugin.name} (#{reader.plugin.classname})"/></b> + <b> + <div align="center"> + <h:outputText value="#{reader.plugin.name}"/><br/> + <h:outputText value="(#{reader.plugin.classname})"/> + </div> + </b> <br/> - <h:outputText value="#{reader.description}"/> - <br/><br/> + <b><h:outputText value="#{localizedAnalysisEditorPageMessages.description}:"/></b><br/> + <ul> + <li><h:outputText value="#{reader.description}"/></li> + </ul> <ui:fragment rendered="#{not empty reader.plugin.outputPorts}"> <b><h:outputText value="#{localizedAnalysisEditorPageMessages.outputPorts}:"/></b> <p:dataList value="#{reader.plugin.outputPorts}" var="port"> @@ -194,8 +207,9 @@ </ui:fragment> <ui:fragment rendered="#{not empty reader.dependency}"> <b><h:outputText value="#{localizedAnalysisEditorPageMessages.dependencies}:"/></b> - <br/> - <h:outputText value="#{reader.dependency}"/> + <ul> + <h:outputText value="#{reader.dependency}"/> + </ul> </ui:fragment> </p:tooltip> </ui:repeat> @@ -203,11 +217,18 @@ <p:tab title="#{localizedAnalysisEditorPageMessages.filter}"> <ui:repeat value="#{currentAnalysisEditorBean.availableComponents.filters}" var="filter"> <p:commandLink id="filterLink" value="#{filter.plugin.name}" action="#{currentAnalysisEditorBean.addPlugin(filter)}" update=":messages"/><br/> - <p:tooltip for="filterLink"> - <b><h:outputText value="#{filter.plugin.name} (#{filter.plugin.classname})"/></b> + <p:tooltip for="filterLink" > + <b> + <div align="center"> + <h:outputText value="#{filter.plugin.name}"/><br/> + <h:outputText value="(#{filter.plugin.classname})"/> + </div> + </b> <br/> - <h:outputText value="#{filter.description}"/> - <br/><br/> + <b><h:outputText value="#{localizedAnalysisEditorPageMessages.description}:"/></b><br/> + <ul> + <li><h:outputText value="#{filter.description}"/></li> + </ul> <ui:fragment rendered="#{not empty filter.plugin.inputPorts}"> <b><h:outputText value="#{localizedAnalysisEditorPageMessages.inputPorts}:"/></b> <p:dataList value="#{filter.plugin.inputPorts}" var="port"> @@ -234,8 +255,9 @@ </ui:fragment> <ui:fragment rendered="#{not empty filter.dependency}"> <b><h:outputText value="#{localizedAnalysisEditorPageMessages.dependencies}:"/></b> - <br/> - <h:outputText value="#{filter.dependency}"/> + <ul> + <h:outputText value="#{filter.dependency}"/> + </ul> </ui:fragment> </p:tooltip> </ui:repeat> @@ -244,20 +266,28 @@ <ui:repeat value="#{currentAnalysisEditorBean.availableComponents.repositories}" var="repository"> <p:commandLink id="repositoryLink" value="#{repository.repository.name}" action="#{currentAnalysisEditorBean.addRepository(repository)}" update=":messages"/><br/> <p:tooltip for="repositoryLink"> - <b><h:outputText value="#{repository.repository.name} (#{repository.repository.classname})"/></b> + <b> + <div align="center"> + <h:outputText value="#{repository.repository.name}"/><br/> + <h:outputText value="(#{repository.repository.classname})"/> + </div> + </b> <br/> - <h:outputText value="#{repository.description}"/> - <br/><br/> + <b><h:outputText value="#{localizedAnalysisEditorPageMessages.description}:"/></b><br/> + <ul> + <li><h:outputText value="#{repository.description}"/></li> + </ul> <ui:fragment rendered="#{not empty repository.repository.properties}"> <b><h:outputText value="#{localizedAnalysisEditorPageMessages.configuration}:"/></b> <p:dataList value="#{repository.repository.properties}" var="property"> #{property.name} </p:dataList> </ui:fragment> - <ui:fragment rendered="#{not empty repository.dependency}"> + <ui:fragment rendered="#{not empty filter.dependency}"> <b><h:outputText value="#{localizedAnalysisEditorPageMessages.dependencies}:"/></b> - <br/> - <h:outputText value="#{repository.dependency}"/> + <ul> + <h:outputText value="#{repository.dependency}"/> + </ul> </ui:fragment> </p:tooltip> </ui:repeat> @@ -275,6 +305,6 @@ </ui:define> </ui:composition> - </h:body> + </html> \ No newline at end of file diff --git a/Kieker.WebGUI/src/main/webapp/pages/CockpitEditorPage.xhtml b/Kieker.WebGUI/src/main/webapp/pages/CockpitEditorPage.xhtml index 72dfeee783605c781c32db96616341c78a23ac31..4bc163930e97f587c085393d99a0dff6235f1a6a 100644 --- a/Kieker.WebGUI/src/main/webapp/pages/CockpitEditorPage.xhtml +++ b/Kieker.WebGUI/src/main/webapp/pages/CockpitEditorPage.xhtml @@ -85,7 +85,7 @@ <p:separator/> <p:menuitem icon="ui-icon-copy" styleClass="element-with-whitespace" value=" #{localizedCockpitEditorPageMessages.copyView}" /> <p:menuitem icon="ui-icon-edit" styleClass="element-with-whitespace" value=" #{localizedCockpitEditorPageMessages.renameView}"/> - <p:menuitem icon="ui-icon-delete" styleClass="element-with-whitespace" value=" #{localizedCockpitEditorPageMessages.deleteView}"/> + <p:menuitem icon="ui-icon-delete" styleClass="element-with-whitespace" value=" #{localizedCockpitEditorPageMessages.deleteView}" action="#{currentCockpitEditorBean.deleteView(viewElem)}"/> </p:menu> </p:dataList> </h:form> diff --git a/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml b/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml index b4adb2c50858dade6a3b48df95ab1fa9fd8899af..2b487ce71da1ccb198705a5b88dae82aaa2da8c5 100644 --- a/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml +++ b/Kieker.WebGUI/src/main/webapp/pages/ControllerPage.xhtml @@ -42,15 +42,15 @@ <ui:define name="centerContent"> - <p:tabView id="tabView" style="height: 99%"> - <p:tab title="#{localizedControllerPageMessages.personalLog}"> + <p:tabView id="tabView" style="height: 99%" > + <p:tab title="#{localizedControllerPageMessages.personalLog}" style="height: 100%" > <h:form id="currentViewLog"> <ui:repeat value="#{currentControllerBean.viewLog}" var="entry" varStatus="stat"> <h:outputText value="#{entry}"/><ui:fragment rendered="#{not stat.last}"><br/><br/></ui:fragment> </ui:repeat> </h:form> </p:tab> - <p:tab title="#{localizedControllerPageMessages.analysisControllerLog}"> + <p:tab title="#{localizedControllerPageMessages.analysisControllerLog}" style="height: 100%"> <h:form id="analysisControllerLog"> <ui:repeat value="#{currentControllerBean.analysisLog}" var="entry" varStatus="stat"> <h:outputText value="#{entry}"/><ui:fragment rendered="#{not stat.last}"><br/><br/></ui:fragment> @@ -62,39 +62,45 @@ <ui:define name="furtherLayoutUnits"> <p:layoutUnit position="south" header="#{localizedControllerPageMessages.control}" resizable="true" collapsible="true"> + <h:form id="controllerForm"> - <p:commandButton value="#{localizedControllerPageMessages.analysisControllerInstantiateAnalysisController}" action="#{currentControllerBean.instantiateAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> - <p:commandButton value="#{localizedControllerPageMessages.analysisControllerCleaAnalysisController}" action="#{currentControllerBean.cleanAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> - <p:commandButton value="#{localizedControllerPageMessages.analysisControllerStartAnalysis}" action="#{currentControllerBean.startAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> - <p:commandButton value="#{localizedControllerPageMessages.analysisControllerStopAnalysis}" action="#{currentControllerBean.stopAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> - <p:poll interval="1" update=":ledsForm :tabView:analysisControllerLog"/> - </h:form> - <hr/> - <h:form id="ledsForm"> <div align="center"> - <h:graphicImage id="iconLEDRed1" url="../img/LEDs/Icon_LED_Red.png" height="50px" rendered="#{currentControllerBean.isAnalysisNotAvailable()}"/> - <h:graphicImage id="iconLEDRed1_2" url="../img/LEDs/Icon_LED_Gray.png" height="50px" rendered="#{not currentControllerBean.isAnalysisNotAvailable()}"/> - <p:spacer height="0" width="15px"/> - <h:graphicImage id="iconLEDYellow" url="../img/LEDs/Icon_LED_Yellow.png" height="50px" rendered="#{currentControllerBean.isAnalysisReady()}"/> - <h:graphicImage id="iconLEDYellow_2" url="../img/LEDs/Icon_LED_Gray.png" height="50px" rendered="#{not currentControllerBean.isAnalysisReady()}"/> - <p:spacer height="0" width="15px"/> - <h:graphicImage id="iconLEDGreen" url="../img/LEDs/Icon_LED_Green.png" height="50px" rendered="#{currentControllerBean.isAnalysisRunning()}"/> - <h:graphicImage id="iconLEDGreen_2" url="../img/LEDs/Icon_LED_Gray.png" height="50px" rendered="#{not currentControllerBean.isAnalysisRunning()}"/> - <p:spacer height="0" width="15px"/> - <h:graphicImage id="iconLEDRed2" url="../img/LEDs/Icon_LED_Red.png" height="50px" rendered="#{currentControllerBean.isAnalysisTerminated() or currentControllerBean.isAnalysisFailed()}"/> - <h:graphicImage id="iconLEDRed2_2" url="../img/LEDs/Icon_LED_Gray.png" height="50px" rendered="#{not (currentControllerBean.isAnalysisTerminated() or currentControllerBean.isAnalysisFailed())}"/> - - <p:tooltip for="iconLEDRed1" value="#{localizedControllerPageMessages.analysisControllerMsgNotInstantiated}"/> - <p:tooltip for="iconLEDYellow" value="#{localizedControllerPageMessages.analysisControllerMsgReady}"/> - <p:tooltip for="iconLEDGreen" value="#{localizedControllerPageMessages.analysisControllerMsgRunning}"/> - <p:tooltip for="iconLEDRed2" value="#{localizedControllerPageMessages.analysisControllerMsgFailed}"/> - <p:tooltip for="iconLEDRed1_2" value="#{localizedControllerPageMessages.analysisControllerMsgNotInstantiated}"/> - <p:tooltip for="iconLEDYellow_2" value="#{localizedControllerPageMessages.analysisControllerMsgReady}"/> - <p:tooltip for="iconLEDGreen_2" value="#{localizedControllerPageMessages.analysisControllerMsgRunning}"/> - <p:tooltip for="iconLEDRed2_2" value="#{localizedControllerPageMessages.analysisControllerMsgFailed}"/> + <h:panelGrid columns="4" cellpadding="15"> + <p:commandButton value="#{localizedControllerPageMessages.analysisControllerInstantiateAnalysisController}" action="#{currentControllerBean.instantiateAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> + + <p:commandButton value="#{localizedControllerPageMessages.analysisControllerCleaAnalysisController}" action="#{currentControllerBean.cleanAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> + + <p:commandButton value="#{localizedControllerPageMessages.analysisControllerStartAnalysis}" action="#{currentControllerBean.startAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> + + <p:commandButton value="#{localizedControllerPageMessages.analysisControllerStopAnalysis}" action="#{currentControllerBean.stopAnalysis()}" update=":messages :tabView:currentViewLog" disabled="#{empty currentControllerBean.projectName}"/> + + </h:panelGrid> + <p:poll interval="1" update=":ledsForm :tabView:analysisControllerLog"/> </div> - </h:form> + </h:form> + </p:layoutUnit> + + <p:layoutUnit position="east" size="200" header="#{localizedControllerPageMessages.state}" resizable="true" collapsible="true"> + <div align="center"> + <h:form id="ledsForm"> + <h:panelGrid columns="2" cellpadding="15"> + <h:graphicImage url="#{currentControllerBean.isAnalysisNotAvailable() ? '../img/LEDs/Icon_LED_Red.png' : '../img/LEDs/Icon_LED_Gray.png'}" height="50px"/> + <h:outputText value="#{localizedControllerPageMessages.stateNA}"/> + + <h:graphicImage url="#{currentControllerBean.isAnalysisReady() ? '../img/LEDs/Icon_LED_Yellow.png' : '../img/LEDs/Icon_LED_Gray.png'}" height="50px"/> + <h:outputText value="#{localizedControllerPageMessages.stateReady}"/> + <h:graphicImage url="#{currentControllerBean.isAnalysisRunning() ? '../img/LEDs/Icon_LED_Green.png' : '../img/LEDs/Icon_LED_Gray.png'}" height="50px"/> + <h:outputText value="#{localizedControllerPageMessages.stateRunning}"/> + + <h:graphicImage url="#{currentControllerBean.isAnalysisTerminated() ? '../img/LEDs/Icon_LED_Red.png' : '../img/LEDs/Icon_LED_Gray.png'}" height="50px"/> + <h:outputText value="#{localizedControllerPageMessages.stateTerminated}"/> + + <h:graphicImage url="#{currentControllerBean.isAnalysisFailed() ? '../img/LEDs/Icon_LED_Red.png' : '../img/LEDs/Icon_LED_Gray.png'}" height="50px"/> + <h:outputText value="#{localizedControllerPageMessages.stateFailed}"/> + </h:panelGrid> + </h:form> + </div> </p:layoutUnit> </ui:define> diff --git a/Kieker.WebGUI/src/test/java/kieker/webgui/service/impl/GraphLayoutServiceImplTest.java b/Kieker.WebGUI/src/test/java/kieker/webgui/service/impl/GraphLayoutServiceImplTest.java index 4eb9216be2d44c3d7be81fd28e5dc8de0404265b..4329ced1ebeb673552028450d71e5a0f0c244692 100644 --- a/Kieker.WebGUI/src/test/java/kieker/webgui/service/impl/GraphLayoutServiceImplTest.java +++ b/Kieker.WebGUI/src/test/java/kieker/webgui/service/impl/GraphLayoutServiceImplTest.java @@ -19,6 +19,8 @@ package kieker.webgui.service.impl; import org.junit.Assert; import org.junit.Test; +import kieker.webgui.common.exception.GraphLayoutException; + /** * Test class for {@link GraphLayoutServiceImpl}. * @@ -40,16 +42,11 @@ public class GraphLayoutServiceImplTest { public void test() { final GraphLayoutServiceImpl layouter = new GraphLayoutServiceImpl(); - // We assert that nothing goes wrong here - layouter.layoutGraph( - "12 140 72 0 0 0 0 1 42 240 72 1 42 0 0 1 42 210 132 4 36 0 0 2 60 190 108 3 36 0 0 2 48 420 96 1 54 1 36 1 72 768 144 1 78 1 36 3 72 420 84 1 48 0 36 2 36 792 120 1 66 1 36 2 72 250 72 1 42 1 42 0 72 280 72 0 42 1 42 0 72 270 72 1 42 0 42 0 72", - "0 1 0 0 1 2 1 3 1 2 1 2 2 3 4 0 3 4 3 0 4 10 1 0 4 5 2 0 5 10 1 0 5 8 2 0 6 7 1 0 7 10 1 0 7 8 3 0 8 10 1 0 9 10 0 0 "); - - // Something should go wrong here + // We assert that something goes wrong here try { layouter.layoutGraph(" ", " 1 "); Assert.fail(); - } catch (final Exception ex) { + } catch (final GraphLayoutException ex) { } } }