diff --git a/.travis.yml b/.travis.yml index 34c18307a..5f76e6d27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,9 +17,9 @@ install: - cd ../bundles && ./gradlew --version script: - cd ../web && npm run build-prod -- cd ../bundles && ./gradlew build --continue -- cd ../bundles && ./gradlew check -- cd ../bundles && ./gradlew export +- cd ../bundles && ./gradlew --no-daemon build --continue +- cd ../bundles && ./gradlew --no-daemon check +- cd ../bundles && ./gradlew --no-daemon export - cd .. after_success: - git status diff --git a/bundles/cnf/localrepo/index.xml b/bundles/cnf/localrepo/index.xml deleted file mode 100644 index 8e08e8238..000000000 --- a/bundles/cnf/localrepo/index.xml +++ /dev/null @@ -1,36184 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bundles/cnf/localrepo/index.xml.sha b/bundles/cnf/localrepo/index.xml.sha deleted file mode 100644 index 870ea5775..000000000 --- a/bundles/cnf/localrepo/index.xml.sha +++ /dev/null @@ -1 +0,0 @@ -79659d8793c884ee6d323bd0455d746ac2ff61d150aa6fc4395cbf5f24e7ab75 \ No newline at end of file diff --git a/bundles/cnf/localrepo/org.apache.servicemix.bundles.automaton/org.apache.servicemix.bundles.automaton-1.11.0.jar b/bundles/cnf/localrepo/org.apache.servicemix.bundles.automaton/org.apache.servicemix.bundles.automaton-1.11.0.jar new file mode 100644 index 000000000..06c945392 Binary files /dev/null and b/bundles/cnf/localrepo/org.apache.servicemix.bundles.automaton/org.apache.servicemix.bundles.automaton-1.11.0.jar differ diff --git a/bundles/cnf/localrepo/org.apache.servicemix.bundles.generex/org.apache.servicemix.bundles.generex-1.0.2.jar b/bundles/cnf/localrepo/org.apache.servicemix.bundles.generex/org.apache.servicemix.bundles.generex-1.0.2.jar new file mode 100644 index 000000000..d849a5aa9 Binary files /dev/null and b/bundles/cnf/localrepo/org.apache.servicemix.bundles.generex/org.apache.servicemix.bundles.generex-1.0.2.jar differ diff --git a/bundles/cnf/releaserepo/index.xml b/bundles/cnf/releaserepo/index.xml index 7b708d89e..041233da8 100644 --- a/bundles/cnf/releaserepo/index.xml +++ b/bundles/cnf/releaserepo/index.xml @@ -1,2 +1,2 @@ - + \ No newline at end of file diff --git a/bundles/cnf/releaserepo/index.xml.sha b/bundles/cnf/releaserepo/index.xml.sha index d25c4d07e..60b8be6e1 100644 --- a/bundles/cnf/releaserepo/index.xml.sha +++ b/bundles/cnf/releaserepo/index.xml.sha @@ -1 +1 @@ -588e9daeffa76506497afdf3ef329dcd7523eb8a8431ee9963eab24645a30b73 \ No newline at end of file +f3cdc0cdf7ee64d9e83fce2f4444215c1db183ce1e543b7c40e99d6f80c165d5 diff --git a/bundles/specmate-administration/src/com/specmate/administration/internal/services/StatusService.java b/bundles/specmate-administration/src/com/specmate/administration/internal/services/StatusService.java index 9548ea103..b00949c85 100644 --- a/bundles/specmate-administration/src/com/specmate/administration/internal/services/StatusService.java +++ b/bundles/specmate-administration/src/com/specmate/administration/internal/services/StatusService.java @@ -12,7 +12,6 @@ import com.specmate.administration.api.ESpecmateStatus; import com.specmate.administration.api.IStatusService; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.emfrest.api.IRestService; import com.specmate.emfrest.api.RestServiceBase; import com.specmate.model.administration.AdministrationFactory; @@ -46,7 +45,7 @@ public boolean canGet(Object target) { @Override public boolean canPost(Object target, Object object) { - //return (target instanceof Resource && object instanceof Status); + // return (target instanceof Resource && object instanceof Status); return false; } @@ -60,8 +59,7 @@ public RestResult get(Object target, MultivaluedMap queryPara } @Override - public RestResult post(Object target, Object object, String token) - throws SpecmateException, SpecmateValidationException { + public RestResult post(Object target, Object object, String token) throws SpecmateException { if (target instanceof Resource) { Status status = (Status) object; switch (status.getValue()) { diff --git a/bundles/specmate-auth-test/bnd.bnd b/bundles/specmate-auth-test/bnd.bnd index 94cf1c634..ad9a0546a 100644 --- a/bundles/specmate-auth-test/bnd.bnd +++ b/bundles/specmate-auth-test/bnd.bnd @@ -113,4 +113,10 @@ Test-Cases: \ specmate-auth-api;version=snapshot,\ org.apache.felix.scr;version='[2.0.8,2.0.9)',\ specmate-rest;version=snapshot,\ - specmate-scheduler;version=snapshot \ No newline at end of file + specmate-scheduler;version=snapshot,\ + org.apache.servicemix.bundles.jakarta-regexp;version='[1.4.0,1.4.1)',\ + org.apache.servicemix.bundles.lucene;version='[7.2.0,7.2.1)',\ + org.apache.servicemix.bundles.lucene-queries;version='[7.2.0,7.2.1)',\ + org.apache.servicemix.bundles.lucene-queryparser;version='[7.2.0,7.2.1)',\ + org.apache.servicemix.bundles.lucene-sandbox;version='[7.2.0,7.2.1)',\ + specmate-search;version=snapshot \ No newline at end of file diff --git a/bundles/specmate-auth/src/com/specmate/auth/internal/PersistentSessionService.java b/bundles/specmate-auth/src/com/specmate/auth/internal/PersistentSessionService.java index 6805737ed..e3d5c2883 100644 --- a/bundles/specmate-auth/src/com/specmate/auth/internal/PersistentSessionService.java +++ b/bundles/specmate-auth/src/com/specmate/auth/internal/PersistentSessionService.java @@ -37,6 +37,8 @@ public class PersistentSessionService extends BaseSessionService { public void activate(Map properties) throws SpecmateException, SpecmateValidationException { super.activate(properties); sessionTransaction = persistencyService.openTransaction(); + // Sessions do not adhere to the constraints of general specmate objects + sessionTransaction.enableValidators(false); sessionView = persistencyService.openView(); } @@ -59,7 +61,7 @@ public UserSession create(AccessRights source, AccessRights target, String userN sessionTransaction.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { sessionTransaction.getResource().getContents().add(session); return null; } @@ -99,7 +101,7 @@ public void refresh(String token) throws SpecmateException, SpecmateValidationEx sessionTransaction.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { // If we let each request refresh the session, we get errors from CDO regarding // out-of-date revision changes. // Here we rate limit session refreshes. The better option would be to not store @@ -133,7 +135,7 @@ public void delete(String token) throws SpecmateException, SpecmateValidationExc sessionTransaction.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { SpecmateEcoreUtil.detach(session); return null; } diff --git a/bundles/specmate-common/src/com/specmate/common/SpecmateException.java b/bundles/specmate-common/src/com/specmate/common/SpecmateException.java index ff000203b..1dc94e158 100644 --- a/bundles/specmate-common/src/com/specmate/common/SpecmateException.java +++ b/bundles/specmate-common/src/com/specmate/common/SpecmateException.java @@ -2,23 +2,28 @@ /** * Generic exception in specmate + * * @author junkerm * */ public class SpecmateException extends Exception { /** constructor */ - public SpecmateException(String msg){ + public SpecmateException(String msg) { super(msg); } - + /** constructor */ - public SpecmateException(Exception e){ + public SpecmateException(Exception e) { super(e); } - + /** constructor */ - public SpecmateException(String msg, Exception e){ - super(msg,e); + public SpecmateException(String msg, Exception e) { + super(msg, e); + } + + public SpecmateException(String msg, Throwable t) { + super(msg, t); } } diff --git a/bundles/specmate-common/src/com/specmate/common/SpecmateValidationException.java b/bundles/specmate-common/src/com/specmate/common/SpecmateValidationException.java index b13a0443f..007e21bc6 100644 --- a/bundles/specmate-common/src/com/specmate/common/SpecmateValidationException.java +++ b/bundles/specmate-common/src/com/specmate/common/SpecmateValidationException.java @@ -1,6 +1,8 @@ package com.specmate.common; public class SpecmateValidationException extends Exception { + private String validatorName; + private String validatedObjectName; /** constructor */ public SpecmateValidationException(String msg) { @@ -16,4 +18,18 @@ public SpecmateValidationException(Exception e) { public SpecmateValidationException(String msg, Exception e) { super(msg, e); } + + public SpecmateValidationException(String msg, String validatorName, String validatedObjectName) { + super(msg); + this.validatorName = validatorName; + this.validatedObjectName = validatedObjectName; + } + + public String getValidatorName() { + return validatorName; + } + + public String getValidatedObjectName() { + return validatedObjectName; + } } diff --git a/bundles/specmate-connectors/bnd.bnd b/bundles/specmate-connectors/bnd.bnd index 21dcc0279..cff2dd598 100644 --- a/bundles/specmate-connectors/bnd.bnd +++ b/bundles/specmate-connectors/bnd.bnd @@ -23,7 +23,8 @@ Export-Package: com.specmate.connectors.api net.bytebuddy.byte-buddy,\ net.bytebuddy.byte-buddy-agent,\ specmate-rest;version=latest,\ - specmate-scheduler;version=latest + specmate-scheduler;version=latest,\ + specmate-search;version=latest Private-Package: \ com.specmate.connectors.internal,\ com.specmate.connectors.internal.config,\ diff --git a/bundles/specmate-connectors/src/com/specmate/connectors/api/IProject.java b/bundles/specmate-connectors/src/com/specmate/connectors/api/IProject.java index 2fd31b486..606462d66 100644 --- a/bundles/specmate-connectors/src/com/specmate/connectors/api/IProject.java +++ b/bundles/specmate-connectors/src/com/specmate/connectors/api/IProject.java @@ -1,12 +1,30 @@ package com.specmate.connectors.api; +import java.util.List; + public interface IProject { + /** + * @return the name of the project + */ String getName(); + /** + * @return the defined requirements source for the project, or + * null. + */ IRequirementsSource getConnector(); + /** + * @return the defined sink to which test information is exported, or + * null. + */ IExportService getExporter(); - + + /** + * @return the list of defined library folders for the project, or + * null. + */ + List getLibraryFolders(); } diff --git a/bundles/specmate-connectors/src/com/specmate/connectors/api/IProjectConfigService.java b/bundles/specmate-connectors/src/com/specmate/connectors/api/IProjectConfigService.java index 480d2c81e..546a18f75 100644 --- a/bundles/specmate-connectors/src/com/specmate/connectors/api/IProjectConfigService.java +++ b/bundles/specmate-connectors/src/com/specmate/connectors/api/IProjectConfigService.java @@ -7,8 +7,8 @@ public interface IProjectConfigService { /** The prefix for project configuration keys */ public static final String PROJECT_PREFIX = "project."; - /** The PID of a single project service */ - public static final String PROJECT_PID = "com.specmate.connectors.project"; + /** The PID of the project config factory */ + public static final String PROJECT_CONFIG_FACTORY_PID = "com.specmate.connectors.projectconfigfactory"; /** The configuration key for the id of a connector */ public static final String KEY_CONNECTOR_ID = "connectorID"; @@ -19,6 +19,9 @@ public interface IProjectConfigService { /** the configuration key for the name of a project */ public static final String KEY_PROJECT_NAME = "projectName"; + /** the configuration key for the library folders of a project */ + public static final String KEY_PROJECT_LIBRARY_FOLDERS = "libraryFolders"; + /** The configuration key for the list of projects. */ public static final String KEY_PROJECT_NAMES = PROJECT_PREFIX + "projects"; diff --git a/bundles/specmate-connectors/src/com/specmate/connectors/config/ProjectConfigService.java b/bundles/specmate-connectors/src/com/specmate/connectors/config/ProjectConfigService.java index d41dfe9f0..a1af4fdaf 100644 --- a/bundles/specmate-connectors/src/com/specmate/connectors/config/ProjectConfigService.java +++ b/bundles/specmate-connectors/src/com/specmate/connectors/config/ProjectConfigService.java @@ -87,7 +87,7 @@ private void ensureProjectFolder(String projectName) throws SpecmateException, S EObject obj = SpecmateEcoreUtil.getEObjectWithId(projectName, projects); if (obj == null || !(obj instanceof Folder)) { - + trans.doAndCommit(() -> { Folder folder = BaseFactory.eINSTANCE.createFolder(); folder.setName(projectName); @@ -97,8 +97,6 @@ private void ensureProjectFolder(String projectName) throws SpecmateException, S }); } - - } finally { if (trans != null) { trans.close(); @@ -108,8 +106,7 @@ private void ensureProjectFolder(String projectName) throws SpecmateException, S } /** - * Configures a single project with a given connector and exporter - * description + * Configures a single project with a given connector and exporter description */ private void configureProject(String projectName, Configurable connector, Configurable exporter) throws SpecmateException { @@ -132,9 +129,13 @@ private void configureProject(String projectName, Configurable connector, Config // This ensures that the right connector will be bound to the project. projectConfig.put("connector.target", connectorFilter); - projectConfig.put(KEY_PROJECT_NAME, projectName); + String projectLibraryKey = PROJECT_PREFIX + projectName + KEY_PROJECT_LIBRARY; + String[] libraryFolders = configService.getConfigurationPropertyArray(projectLibraryKey); + if (libraryFolders != null) { + projectConfig.put(KEY_PROJECT_LIBRARY_FOLDERS, libraryFolders); + } - OSGiUtil.configureFactory(configAdmin, PROJECT_PID, projectConfig); + OSGiUtil.configureFactory(configAdmin, PROJECT_CONFIG_FACTORY_PID, projectConfig); } /** @@ -239,13 +240,14 @@ public Object doChange() throws SpecmateException { Folder libraryFolder = null; if (obj == null) { libraryFolder = BaseFactory.eINSTANCE.createFolder(); + libraryFolder.setId(projectLibraryId); projectFolder.getContents().add(libraryFolder); } else { assert (obj instanceof Folder); libraryFolder = (Folder) obj; + libraryFolder.setId(projectLibraryId); } - libraryFolder.setId(projectLibraryId); libraryFolder.setName(libraryName); libraryFolder.setDescription(libraryDescription); } diff --git a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ALMExportService.java b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ALMExportService.java index 3e9bdafd7..cb0988e55 100644 --- a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ALMExportService.java +++ b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ALMExportService.java @@ -8,7 +8,6 @@ import com.specmate.auth.api.IAuthenticationService; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.connectors.api.IProject; import com.specmate.connectors.api.IProjectService; import com.specmate.emfrest.api.IRestService; @@ -41,8 +40,7 @@ public boolean canPost(Object target, Object object) { } @Override - public RestResult post(Object target, Object object, String token) - throws SpecmateException, SpecmateValidationException { + public RestResult post(Object target, Object object, String token) throws SpecmateException { if (isAuthorizedToExport(token)) { TestProcedure testProcedure = (TestProcedure) target; diff --git a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorService.java b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorService.java index 88c876493..35ecd398b 100644 --- a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorService.java +++ b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorService.java @@ -1,99 +1,121 @@ -package com.specmate.connectors.internal; - -import static com.specmate.connectors.internal.config.ConnectorServiceConfig.KEY_POLL_SCHEDULE; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.eclipse.emf.cdo.common.id.CDOWithID; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.ConfigurationPolicy; -import org.osgi.service.component.annotations.Deactivate; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.log.LogService; - -import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; -import com.specmate.connectors.api.IRequirementsSource; -import com.specmate.connectors.internal.config.ConnectorServiceConfig; -import com.specmate.persistency.IPersistencyService; -import com.specmate.persistency.ITransaction; -import com.specmate.scheduler.Scheduler; -import com.specmate.scheduler.SchedulerIteratorFactory; -import com.specmate.scheduler.SchedulerTask; - -@Component(immediate = true, configurationPid = ConnectorServiceConfig.PID, configurationPolicy = ConfigurationPolicy.REQUIRE) -public class ConnectorService { - CDOWithID id; - List requirementsSources = new ArrayList<>(); - private LogService logService; - private IPersistencyService persistencyService; - private ITransaction transaction; - - @Activate - public void activate(Map properties) throws SpecmateValidationException, SpecmateException { - validateConfig(properties); - - String schedule = (String) properties.get(KEY_POLL_SCHEDULE); - if (schedule == null) { - return; - } - - this.transaction = this.persistencyService.openTransaction(); - - new Thread(new Runnable() { - @Override - public void run() { - SchedulerTask connectorRunnable = new ConnectorTask(requirementsSources, transaction, logService); - connectorRunnable.run(); - - Scheduler scheduler = new Scheduler(); - try { - scheduler.schedule(connectorRunnable, SchedulerIteratorFactory.create(schedule)); - } catch (SpecmateException e) { - e.printStackTrace(); - } catch (SpecmateValidationException e) { - e.printStackTrace(); - } - } - }, "connector-service-initializer").start(); - - } - - private void validateConfig(Map properties) throws SpecmateValidationException { - SchedulerIteratorFactory.validate((String) properties.get(KEY_POLL_SCHEDULE)); - logService.log(LogService.LOG_DEBUG, "Connector service config validated."); - } - - @Deactivate - public void deactivate() { - transaction.close(); - } - - @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) - public void addRequirementsConnector(IRequirementsSource source) { - this.requirementsSources.add(source); - } - - public void removeRequirementsConnector(IRequirementsSource source) { - this.requirementsSources.remove(source); - } - - @Reference - public void setLogService(LogService logService) { - this.logService = logService; - } - - @Reference - public void setPersistency(IPersistencyService persistencyService) { - this.persistencyService = persistencyService; - } - - public void unsetPersistency(IPersistencyService persistencyService) { - this.persistencyService = null; - } -} +package com.specmate.connectors.internal; + +import static com.specmate.connectors.internal.config.ConnectorServiceConfig.KEY_POLL_SCHEDULE; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.cdo.common.id.CDOWithID; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.log.LogService; + +import com.specmate.common.SpecmateException; +import com.specmate.common.SpecmateValidationException; +import com.specmate.connectors.api.IRequirementsSource; +import com.specmate.connectors.internal.config.ConnectorServiceConfig; +import com.specmate.persistency.IPersistencyService; +import com.specmate.persistency.ITransaction; +import com.specmate.scheduler.Scheduler; +import com.specmate.scheduler.SchedulerIteratorFactory; +import com.specmate.scheduler.SchedulerTask; +import com.specmate.search.api.IModelSearchService; + +@Component(immediate = true, configurationPid = ConnectorServiceConfig.PID, configurationPolicy = ConfigurationPolicy.REQUIRE) +public class ConnectorService { + CDOWithID id; + List requirementsSources = new ArrayList<>(); + private LogService logService; + private IPersistencyService persistencyService; + private IModelSearchService modelSearchService; + private ITransaction transaction; + + @Activate + public void activate(Map properties) throws SpecmateValidationException, SpecmateException { + validateConfig(properties); + + String schedule = (String) properties.get(KEY_POLL_SCHEDULE); + if (schedule == null) { + return; + } + + this.transaction = this.persistencyService.openTransaction(); + + new Thread(new Runnable() { + @Override + public void run() { + + // Ensure that requirements source are loaded. + while (requirementsSources.size() == 0) { + try { + logService.log(LogService.LOG_INFO, "No requirement sources here yet. Waiting."); + // Requirements Sources could be added after the + // component is activated + Thread.sleep(20 * 1000); + } catch (InterruptedException e) { + logService.log(LogService.LOG_ERROR, e.getMessage()); + } + } + + try { + SchedulerTask connectorRunnable = new ConnectorTask(requirementsSources, transaction, logService); + connectorRunnable.run(); + modelSearchService.startReIndex(); + Scheduler scheduler = new Scheduler(); + scheduler.schedule(connectorRunnable, SchedulerIteratorFactory.create(schedule)); + } catch (SpecmateException e) { + e.printStackTrace(); + logService.log(LogService.LOG_ERROR, e.getLocalizedMessage()); + } catch (SpecmateValidationException e) { + e.printStackTrace(); + logService.log(LogService.LOG_ERROR, e.getLocalizedMessage()); + } + } + }, "connector-service-initializer").start(); + + } + + private void validateConfig(Map properties) throws SpecmateValidationException { + SchedulerIteratorFactory.validate((String) properties.get(KEY_POLL_SCHEDULE)); + logService.log(LogService.LOG_DEBUG, "Connector service config validated."); + } + + @Deactivate + public void deactivate() { + transaction.close(); + } + + @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) + public void addRequirementsConnector(IRequirementsSource source) { + this.requirementsSources.add(source); + } + + public void removeRequirementsConnector(IRequirementsSource source) { + this.requirementsSources.remove(source); + } + + @Reference + public void setLogService(LogService logService) { + this.logService = logService; + } + + @Reference + public void setPersistency(IPersistencyService persistencyService) { + this.persistencyService = persistencyService; + } + + @Reference + public void setModelSearchService(IModelSearchService modelSearchService) { + this.modelSearchService = modelSearchService; + } + + public void unsetPersistency(IPersistencyService persistencyService) { + this.persistencyService = null; + } +} diff --git a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorTask.java b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorTask.java index 6ecfb1f5a..a962d308d 100644 --- a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorTask.java +++ b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ConnectorTask.java @@ -67,7 +67,7 @@ private void syncRequirementsFromSources() { transaction.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { syncContainers(localContainer, tosync, source); return null; } diff --git a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ProjectImpl.java b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ProjectImpl.java index 21a60df8a..0ae2f6426 100644 --- a/bundles/specmate-connectors/src/com/specmate/connectors/internal/ProjectImpl.java +++ b/bundles/specmate-connectors/src/com/specmate/connectors/internal/ProjectImpl.java @@ -1,5 +1,7 @@ package com.specmate.connectors.internal; +import java.util.Arrays; +import java.util.List; import java.util.Map; import org.osgi.service.component.annotations.Activate; @@ -10,18 +12,28 @@ import com.specmate.connectors.api.IExportService; import com.specmate.connectors.api.IProject; +import com.specmate.connectors.api.IProjectConfigService; import com.specmate.connectors.api.IRequirementsSource; import com.specmate.connectors.config.ProjectConfigService; -@Component(service = IProject.class, configurationPid = ProjectConfigService.PROJECT_PID, configurationPolicy = ConfigurationPolicy.REQUIRE) +@Component(service = IProject.class, configurationPid = ProjectConfigService.PROJECT_CONFIG_FACTORY_PID, configurationPolicy = ConfigurationPolicy.REQUIRE) public class ProjectImpl implements IProject { - private String name; + private String name = null; private IRequirementsSource connector = null; - private IExportService exporter; + private IExportService exporter = null; + private List libraryFolders = null; @Activate public void activate(Map properties) { - this.name = (String) properties.get(ProjectConfigService.KEY_PROJECT_NAME); + Object obj = properties.get(ProjectConfigService.KEY_PROJECT_NAME); + if (obj != null && obj instanceof String) { + this.name = (String) properties.get(ProjectConfigService.KEY_PROJECT_NAME); + } + + obj = properties.get(IProjectConfigService.KEY_PROJECT_LIBRARY_FOLDERS); + if (obj != null && obj instanceof String[]) { + libraryFolders = Arrays.asList((String[]) obj); + } } @Override @@ -33,7 +45,7 @@ public void setName(String name) { this.name = name; } - @Reference(name="connector") + @Reference(name = "connector") public void setConnector(IRequirementsSource connector) { this.connector = connector; } @@ -43,16 +55,20 @@ public IRequirementsSource getConnector() { return connector; } - @Reference(cardinality=ReferenceCardinality.OPTIONAL, name="exporter") + @Reference(cardinality = ReferenceCardinality.OPTIONAL, name = "exporter") public void setExporter(IExportService exporter) { this.exporter = exporter; } - + @Override public IExportService getExporter() { return this.exporter; } + @Override + public List getLibraryFolders() { + return libraryFolders; + } } diff --git a/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyDataService.java b/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyDataService.java index 2e7cafc16..7eb6e3d36 100644 --- a/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyDataService.java +++ b/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyDataService.java @@ -94,7 +94,7 @@ public Object doChange() throws SpecmateException { } }); } catch (Exception e) { - logService.log(LogService.LOG_ERROR, e.getMessage()); + logService.log(LogService.LOG_ERROR, e.getCause().getMessage()); } } @@ -154,20 +154,18 @@ private void loadGenericTestData(Folder testFolder) { Requirement requirement1 = RequirementsFactory.eINSTANCE.createRequirement(); requirement1.setId("Requirement-1"); requirement1.setExtId("123"); - requirement1.setName("Zuschlag und Summenprüfung"); + requirement1.setName("Prüfung der Summe"); requirement1.setDescription( - "Das System ermöglicht die Suche nach Säumnis bzw. Prämienzuschlag wenn eine Einzelrechnung vorhanden ist, " - + "eine Reduktion gebucht wurde, und die Betragsart entweder SZ oder BZ ist. Eine Summenprüfung wird " - + "durchgeführt, falls eine Einzelabrechnung vorhanden ist."); + "Das ist die Beschreibung des Requirements."); requirement1.setImplementingBOTeam("Business Analysts"); requirement1.setImplementingITTeam("The IT Nerds"); - requirement1.setImplementingUnit("Allianz IT and Infrastructure"); + requirement1.setImplementingUnit("IT and Infrastructure"); requirement1.setNumberOfTests(4); requirement1.setPlannedRelease("Release 10 - Mount Everest"); requirement1.setStatus("In Progress"); requirement1.setTac("All tests must pass and the code is reviewed"); requirement1.setIsRegressionRequirement(true); - requirement1.setPlatform("ABS"); + requirement1.setPlatform("My Platform"); Requirement requirement2 = RequirementsFactory.eINSTANCE.createRequirement(); requirement2.setId("Requirement-2"); @@ -254,7 +252,7 @@ private void loadGenericTestData(Folder testFolder) { + "durchgeführt, falls eine Einzelabrechnung vorhanden ist."); requirement3.setImplementingBOTeam("Business Analysts"); requirement3.setImplementingITTeam("The IT Nerds"); - requirement3.setImplementingUnit("Allianz IT and Infrastructure"); + requirement3.setImplementingUnit("IT and Infrastructure"); requirement3.setNumberOfTests(4); requirement3.setPlannedRelease("Release 10 - Mount Everest"); requirement3.setStatus("In Progress"); diff --git a/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyProject.java b/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyProject.java index af47337c0..6ac30dd50 100644 --- a/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyProject.java +++ b/bundles/specmate-dummy-data/src/com/specmate/dummydata/DummyProject.java @@ -1,6 +1,7 @@ package com.specmate.dummydata; import java.util.Collection; +import java.util.List; import org.osgi.service.component.annotations.Component; @@ -14,7 +15,7 @@ /** * A project definition for the test-data that authorizes every user. - * + * * @author junkerm */ @Component(immediate = true) @@ -70,4 +71,9 @@ public void export(TestProcedure testProcedure) throws SpecmateException { }; } + @Override + public List getLibraryFolders() { + return null; + } + } diff --git a/bundles/specmate-emfjson/src/com/specmate/emfjson/EMFJsonDeserializer.java b/bundles/specmate-emfjson/src/com/specmate/emfjson/EMFJsonDeserializer.java index 8154fc430..42a6caac8 100644 --- a/bundles/specmate-emfjson/src/com/specmate/emfjson/EMFJsonDeserializer.java +++ b/bundles/specmate-emfjson/src/com/specmate/emfjson/EMFJsonDeserializer.java @@ -1,198 +1,202 @@ -package com.specmate.emfjson; - -import org.apache.commons.lang3.StringUtils; -import org.eclipse.emf.common.util.BasicEList; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EClassifier; -import org.eclipse.emf.ecore.EDataType; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import com.specmate.common.SpecmateException; -import com.specmate.urihandler.IObjectResolver; - -/** - * Deserializes JSON objects to EObjects - * - * @author junkerm - * - */ -public class EMFJsonDeserializer { - - /** Resolver to obtain reference EObjects from the resource based on an uri */ - private IObjectResolver resolver; - - /** The underlying resource from where to retrieve referenced objects */ - private Resource resource; - - /** - * - * @param resolver - * The object resolver to be used - * @param resource - * The resource from where to retieve referenced objects - */ - public EMFJsonDeserializer(IObjectResolver resolver, Resource resource) { - this.resolver = resolver; - this.resource = resource; - } - - /** - * Deserializes an Eobject from a JSON object - * - * @param jsonObj - * The JSON object to be deserialized - * @return The EObject that is represented by the json object - * @throws SpecmateException - */ - public EObject deserializeEObject(JSONObject jsonObj) - throws SpecmateException { - if (jsonObj.has(EMFJsonSerializer.KEY_PROXY) && jsonObj.getBoolean(EMFJsonSerializer.KEY_PROXY)) { - String uriFragment = jsonObj.getString(EMFJsonSerializer.KEY_URI); - return retrieveFromResource(uriFragment); - } else { - return buildFromJson(jsonObj); - } - } - - /** - * Retrieves an EObject directly from the resource based on an URI - * - * @param uri - * The URI used to adress the object - * @return An EObject that has the given URI - * @throws SpecmateException - */ - private EObject retrieveFromResource(String uri) throws SpecmateException { - EObject retrieved = resolver.getObject(uri, resource); - if (retrieved == null) { - throw new SpecmateException( - "Json contained " - + EMFJsonSerializer.KEY_URI - + " entry but no object with this fragment url could be found"); - } else - return retrieved; - } - - /** - * Constructs an EObject recursively from the given JSON object - * - * @param jsonObj - * The JSON object from which to construct the EObject - * @return An EObject representing the jsonObject - * @throws SpecmateException - */ - private EObject buildFromJson(JSONObject jsonObj) throws SpecmateException { - String nsUri = jsonObj.optString(EMFJsonSerializer.KEY_NSURI); - String className = jsonObj.optString(EMFJsonSerializer.KEY_ECLASS); - if (StringUtils.isEmpty(nsUri) || StringUtils.isEmpty(className)) { - throw new SpecmateException("No uri or eclass specified"); - } - - EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(nsUri); - if (ePackage == null) { - throw new SpecmateException("No package registered for " + nsUri); - } - EClassifier classifier = ePackage.getEClassifier(className); - if (classifier == null || !(classifier instanceof EClass)) { - throw new SpecmateException("No class with name " + className - + " in package"); - } - - EClass clazz = (EClass) classifier; - - EObject eObj = ePackage.getEFactoryInstance().create(clazz); - deserializeFeatures(eObj, jsonObj); - - return eObj; - } - - /** - * Deserializes the values of all features of an EObject from the given - * JSONObject - * - * @param eObject - * The EObject for which the feature values should be dserialized - * @param jsonObj - * The JSON object from which to serialize the values - * @throws SpecmateException - */ - private void deserializeFeatures(EObject eObject, JSONObject jsonObj) - throws SpecmateException { - String featureName = null; - for (EStructuralFeature feature : eObject.eClass() - .getEAllStructuralFeatures()) { - featureName = feature.getName(); - if (jsonObj.has(featureName)) { - Object value; - try { - value = jsonObj.get(featureName); - } catch (JSONException e) { - throw new SpecmateException(e); - } - eObject.eSet(feature, deserializeFeature(feature, value)); - } - } - } - - /** - * Deserialized the value of a single feature of an EObject from a JSON - * entity. This entity is either a {@link JSONArray} or a {@link JSONObject} - * depending on the type of the feature. - * - * @param feature - * The which for the value should be deserialized - * @param json - * The json entity ({@link JSONArray} or {@link JSONObject}) from - * which to deserialize - * @return The EObject or the EList obtained from the deserialization - * @throws SpecmateException - */ - private Object deserializeFeature(EStructuralFeature feature, Object json) - throws SpecmateException { - EClassifier type = feature.getEType(); - if (!feature.isMany()) { - return deserializeValue(json, type); - } else { - JSONArray array = (JSONArray) json; - BasicEList list = new BasicEList(); - for (int i = 0; i < array.length(); i++) { - try { - list.add(deserializeValue(array.get(i), type)); - } catch (JSONException e) { - throw new SpecmateException(e); - } - } - return list; - } - } - - /** - * Deserializs a JSON value, depending on the expected type. - * - * @param value - * The JSON value to deserialize - * @param type - * The expected type - * @return The deserialized value, either an EObject or a primitive type - * such as String, etc. - * @throws SpecmateException - */ - private Object deserializeValue(Object value, EClassifier type) - throws SpecmateException { - if (type instanceof EDataType) { - return EcoreUtil.createFromString((EDataType) type, value.toString()); - } else if (type instanceof EClass) { - return deserializeEObject((JSONObject) value); - } else - throw new SpecmateException(type - + " not supported for deserialization"); - } - -} +package com.specmate.emfjson; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import com.specmate.common.SpecmateException; +import com.specmate.urihandler.IObjectResolver; + +/** + * Deserializes JSON objects to EObjects + * + * @author junkerm + * + */ +public class EMFJsonDeserializer { + + /** Resolver to obtain reference EObjects from the resource based on an uri */ + private IObjectResolver resolver; + + /** The underlying resource from where to retrieve referenced objects */ + private Resource resource; + + /** + * + * @param resolver + * The object resolver to be used + * @param resource + * The resource from where to retieve referenced objects + */ + public EMFJsonDeserializer(IObjectResolver resolver, Resource resource) { + this.resolver = resolver; + this.resource = resource; + } + + /** + * Deserializes an Eobject from a JSON object + * + * @param jsonObj + * The JSON object to be deserialized + * @return The EObject that is represented by the json object + * @throws SpecmateException + */ + public EObject deserializeEObject(JSONObject jsonObj) + throws SpecmateException { + if (jsonObj.has(EMFJsonSerializer.KEY_PROXY) && jsonObj.getBoolean(EMFJsonSerializer.KEY_PROXY)) { + String uriFragment = jsonObj.getString(EMFJsonSerializer.KEY_URI); + return retrieveFromResource(uriFragment); + } else { + return buildFromJson(jsonObj); + } + } + + /** + * Retrieves an EObject directly from the resource based on an URI + * + * @param uri + * The URI used to adress the object + * @return An EObject that has the given URI + * @throws SpecmateException + */ + private EObject retrieveFromResource(String uri) throws SpecmateException { + EObject retrieved = resolver.getObject(uri, resource); + if (retrieved == null) { + throw new SpecmateException( + "Json contained " + + EMFJsonSerializer.KEY_URI + + " entry but no object with this fragment url could be found"); + } else + return retrieved; + } + + /** + * Constructs an EObject recursively from the given JSON object + * + * @param jsonObj + * The JSON object from which to construct the EObject + * @return An EObject representing the jsonObject + * @throws SpecmateException + */ + private EObject buildFromJson(JSONObject jsonObj) throws SpecmateException { + String nsUri = jsonObj.optString(EMFJsonSerializer.KEY_NSURI); + String className = jsonObj.optString(EMFJsonSerializer.KEY_ECLASS); + if (StringUtils.isEmpty(nsUri) || StringUtils.isEmpty(className)) { + throw new SpecmateException("No uri or eclass specified"); + } + + EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(nsUri); + if (ePackage == null) { + throw new SpecmateException("No package registered for " + nsUri); + } + EClassifier classifier = ePackage.getEClassifier(className); + if (classifier == null || !(classifier instanceof EClass)) { + throw new SpecmateException("No class with name " + className + + " in package"); + } + + EClass clazz = (EClass) classifier; + + EObject eObj = ePackage.getEFactoryInstance().create(clazz); + deserializeFeatures(eObj, jsonObj); + + return eObj; + } + + /** + * Deserializes the values of all features of an EObject from the given + * JSONObject + * + * @param eObject + * The EObject for which the feature values should be dserialized + * @param jsonObj + * The JSON object from which to serialize the values + * @throws SpecmateException + */ + private void deserializeFeatures(EObject eObject, JSONObject jsonObj) + throws SpecmateException { + String featureName = null; + for (EStructuralFeature feature : eObject.eClass() + .getEAllStructuralFeatures()) { + featureName = feature.getName(); + if (jsonObj.has(featureName)) { + Object value; + try { + value = jsonObj.get(featureName); + } catch (JSONException e) { + throw new SpecmateException(e); + } + eObject.eSet(feature, deserializeFeature(feature, value)); + } + } + } + + /** + * Deserialized the value of a single feature of an EObject from a JSON + * entity. This entity is either a {@link JSONArray} or a {@link JSONObject} + * depending on the type of the feature. + * + * @param feature + * The which for the value should be deserialized + * @param json + * The json entity ({@link JSONArray} or {@link JSONObject}) from + * which to deserialize + * @return The EObject or the EList obtained from the deserialization + * @throws SpecmateException + */ + private Object deserializeFeature(EStructuralFeature feature, Object json) + throws SpecmateException { + EClassifier type = feature.getEType(); + if (!feature.isMany()) { + return deserializeValue(json, type); + } else { + JSONArray array = (JSONArray) json; + BasicEList list = new BasicEList(); + for (int i = 0; i < array.length(); i++) { + try { + list.add(deserializeValue(array.get(i), type)); + } catch (JSONException e) { + throw new SpecmateException(e); + } + } + return list; + } + } + + /** + * Deserializs a JSON value, depending on the expected type. + * + * @param value + * The JSON value to deserialize + * @param type + * The expected type + * @return The deserialized value, either an EObject or a primitive type + * such as String, etc. + * @throws SpecmateException + */ + private Object deserializeValue(Object value, EClassifier type) + throws SpecmateException { + if (type instanceof EDataType) { + String strValue = value.toString(); + if(type.getName().equalsIgnoreCase("EBoolean") && value.toString().equals("")) { + strValue = "false"; + } + return EcoreUtil.createFromString((EDataType) type, strValue); + } else if (type instanceof EClass) { + return deserializeEObject((JSONObject) value); + } else + throw new SpecmateException(type + + " not supported for deserialization"); + } + +} diff --git a/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/IRestService.java b/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/IRestService.java index d92dffd82..6c3991fbb 100644 --- a/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/IRestService.java +++ b/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/IRestService.java @@ -3,7 +3,6 @@ import javax.ws.rs.core.MultivaluedMap; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.rest.RestResult; public interface IRestService extends Comparable { @@ -16,17 +15,15 @@ public interface IRestService extends Comparable { boolean canPost(Object object2, Object object); - RestResult post(Object object2, Object object, String token) - throws SpecmateException, SpecmateValidationException; + RestResult post(Object object2, Object object, String token) throws SpecmateException; boolean canPut(Object object2, Object object); - RestResult put(Object object2, Object object, String token) - throws SpecmateException, SpecmateValidationException; + RestResult put(Object object2, Object object, String token) throws SpecmateException; boolean canDelete(Object object); - RestResult delete(Object object, String token) throws SpecmateException, SpecmateValidationException; + RestResult delete(Object object, String token) throws SpecmateException; int getPriority(); diff --git a/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/RestServiceBase.java b/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/RestServiceBase.java index 533216ada..6fb02e73d 100644 --- a/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/RestServiceBase.java +++ b/bundles/specmate-emfrest-api/src/com/specmate/emfrest/api/RestServiceBase.java @@ -3,7 +3,6 @@ import javax.ws.rs.core.MultivaluedMap; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.rest.RestResult; public abstract class RestServiceBase implements IRestService { @@ -54,8 +53,7 @@ public boolean canPost(Object object2, Object object) { * org.eclipse.emf.ecore.EObject) */ @Override - public RestResult post(Object parent, Object child, String token) - throws SpecmateException, SpecmateValidationException { + public RestResult post(Object parent, Object child, String token) throws SpecmateException { return null; } @@ -76,8 +74,7 @@ public boolean canPut(Object object2, Object object) { * org.eclipse.emf.ecore.EObject) */ @Override - public RestResult put(Object object2, Object object, String token) - throws SpecmateException, SpecmateValidationException { + public RestResult put(Object object2, Object object, String token) throws SpecmateException { return null; } @@ -97,7 +94,7 @@ public boolean canDelete(Object object) { * @see com.specmate.emfrest.api.IRestService#delete(java.lang.Object) */ @Override - public RestResult delete(Object object, String token) throws SpecmateException, SpecmateValidationException { + public RestResult delete(Object object, String token) throws SpecmateException { return null; } diff --git a/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CopyService.java b/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CopyService.java index af284cc11..f314467f7 100644 --- a/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CopyService.java +++ b/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CopyService.java @@ -1,11 +1,13 @@ package com.specmate.emfrest.crud; +import java.util.Arrays; + import org.osgi.service.component.annotations.Component; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.emfrest.api.IRestService; import com.specmate.emfrest.api.RestServiceBase; +import com.specmate.model.base.Folder; import com.specmate.model.processes.Process; import com.specmate.model.requirements.CEGModel; import com.specmate.model.testspecification.TestSpecification; @@ -17,15 +19,14 @@ public class CopyService extends RestServiceBase { public String getServiceName() { return "duplicate"; } - + @Override public boolean canPost(Object target, Object object) { return target instanceof CEGModel || target instanceof Process || target instanceof TestSpecification; } @Override - public RestResult post(Object target, Object child, String token) - throws SpecmateException, SpecmateValidationException { - return CrudUtil.duplicate(target); + public RestResult post(Object target, Object child, String token) throws SpecmateException { + return CrudUtil.duplicate(target, Arrays.asList(TestSpecification.class, Folder.class)); } } diff --git a/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CrudUtil.java b/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CrudUtil.java index a361607cf..ca89fe30e 100644 --- a/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CrudUtil.java +++ b/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/CrudUtil.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.Set; -import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.ws.rs.core.Response; @@ -17,31 +16,22 @@ import org.eclipse.emf.ecore.util.EcoreUtil; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.model.base.IContainer; import com.specmate.model.base.IContentElement; +import com.specmate.model.base.ISpecmateModelObject; import com.specmate.model.support.util.SpecmateEcoreUtil; import com.specmate.rest.RestResult; public class CrudUtil { - - /** Pattern that describes valid object ids */ - private static Pattern idPattern = Pattern.compile("[a-zA-Z_0-9\\-]*"); - private static final String CONTENTS = "contents"; - public static RestResult create(Object parent, EObject toAddObj, String userName) - throws SpecmateValidationException { + public static RestResult create(Object parent, EObject toAddObj, String userName) { if (toAddObj != null && !isProjectModificationRequestAuthorized(parent, toAddObj, true)) { return new RestResult(Response.Status.UNAUTHORIZED, null, userName); } EObject toAdd = toAddObj; - ValidationResult validationResult = validate(parent, toAdd); - if (!validationResult.isValid()) { - throw new SpecmateValidationException(validationResult.getErrorMessage()); - } if (parent instanceof Resource) { ((Resource) parent).getContents().add(toAdd); } else if (parent instanceof EObject) { @@ -69,90 +59,70 @@ public static RestResult update(Object target, EObject update, String userNam return new RestResult<>(Response.Status.OK, target, userName); } - public static RestResult duplicate(Object target) throws SpecmateException { + /** + * Copies an object recursively with all children and adds the copy to the + * parent of the object. The duplicate gets a name that is guaranteed to be + * unique within the parent. + * + * @param target + * The target object that shall be duplicated + * @param childrenCopyBlackList + * A list of element types. Child-Elements of target are only copied + * if the are of a type that is not on the blacklist + * @return + * @throws SpecmateException + */ + public static RestResult duplicate(Object target, List> childrenCopyBlackList) + throws SpecmateException { + EObject original = (EObject) target; - IContentElement copy = (IContentElement) EcoreUtil.copy(original); + ISpecmateModelObject copy = filteredCopy(childrenCopyBlackList, original); IContainer parent = (IContainer) original.eContainer(); + setUniqueCopyId(copy, parent); + parent.getContents().add(copy); + + return new RestResult<>(Response.Status.OK, target); + } + + private static ISpecmateModelObject filteredCopy(List> avoidRecurse, EObject original) { + ISpecmateModelObject copy = (ISpecmateModelObject) EcoreUtil.copy(original); + List retain = copy.getContents().stream() + .filter(el -> !avoidRecurse.stream().anyMatch(avoid -> avoid.isAssignableFrom(el.getClass()))) + .collect(Collectors.toList()); + copy.getContents().clear(); + copy.getContents().addAll(retain); + return copy; + } + + private static void setUniqueCopyId(ISpecmateModelObject copy, IContainer parent) { EList contents = parent.getContents(); - // Change ID String newID = SpecmateEcoreUtil.getIdForChild(parent, copy.eClass()); copy.setId(newID); - + String name = copy.getName().replaceFirst("^Copy [0-9]+ of ", ""); - + String prefix = "Copy "; - String suffix = " of " + name; + String suffix = " of " + name; int copyNumber = 1; - - Set names = contents.stream().map(e -> e.getName()).filter(e -> e.startsWith(prefix) && e.endsWith(suffix)).collect(Collectors.toSet()); + + Set names = contents.stream().map(e -> e.getName()) + .filter(e -> e.startsWith(prefix) && e.endsWith(suffix)).collect(Collectors.toSet()); String newName = ""; do { newName = prefix + copyNumber + suffix; copyNumber++; - } while(names.contains(newName)); - + } while (names.contains(newName)); + copy.setName(newName); - contents.add(copy); - - return new RestResult<>(Response.Status.OK, target); } - + public static RestResult delete(Object target, String userName) throws SpecmateException { if (target instanceof EObject && !(target instanceof Resource)) { SpecmateEcoreUtil.detach((EObject) target); return new RestResult<>(Response.Status.OK, target, userName); } else { - throw new SpecmateException("Attempt to delete non EObject"); - } - } - - private static ValidationResult validate(Object parent, EObject object) { - String id = SpecmateEcoreUtil.getID(object); - if (id == null) { - return new ValidationResult(false, "Object does not have a valid Id"); - } - if (!idPattern.matcher(id).matches()) { - return new ValidationResult(false, "Object id may only contain letters, digits, '_' and '_'"); - } - EObject existing; - try { - existing = SpecmateEcoreUtil.getEObjectWithId(id, getChildren(parent)); - } catch (SpecmateException e) { - return new ValidationResult(false, e.getMessage()); - } - if (existing != null) { - return new ValidationResult(false, "Duplicate id:" + id); - } - return new ValidationResult(true, null); - } - - private static class ValidationResult { - public ValidationResult(boolean isValid, String errorMessage) { - super(); - this.isValid = isValid; - this.errorMessage = errorMessage; - } - - private boolean isValid; - private String errorMessage; - - public boolean isValid() { - return isValid; - } - - public String getErrorMessage() { - return errorMessage; - } - } - - public static List getChildren(Object target) throws SpecmateException { - if (target instanceof Resource) { - return ((Resource) target).getContents(); - } else if (target instanceof EObject) { - return ((EObject) target).eContents(); - } else { - throw new SpecmateException("Object is no resource and no EObject"); + throw new SpecmateException("Attempt to delete non EObject."); } } diff --git a/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/ListService.java b/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/ListService.java index aa610323c..b5d9af87f 100644 --- a/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/ListService.java +++ b/bundles/specmate-emfrest/src/com/specmate/emfrest/crud/ListService.java @@ -10,9 +10,9 @@ import com.specmate.auth.api.IAuthenticationService; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.emfrest.api.IRestService; import com.specmate.emfrest.api.RestServiceBase; +import com.specmate.model.support.util.SpecmateEcoreUtil; import com.specmate.rest.RestResult; @Component(immediate = true, service = IRestService.class) @@ -33,7 +33,7 @@ public boolean canGet(Object target) { @Override public RestResult get(Object target, MultivaluedMap queryParams, String token) throws SpecmateException { - return new RestResult<>(Response.Status.OK, CrudUtil.getChildren(target)); + return new RestResult<>(Response.Status.OK, SpecmateEcoreUtil.getChildren(target)); } @Override @@ -42,8 +42,8 @@ public boolean canPost(Object parent, Object toAdd) { } @Override - public RestResult post(Object parent, Object toAdd, String token) - throws SpecmateException, SpecmateValidationException { + public RestResult post(Object parent, Object toAdd, String token) throws SpecmateException { + return CrudUtil.create(parent, (EObject) toAdd, authService.getUserName(token)); } @@ -51,5 +51,4 @@ public RestResult post(Object parent, Object toAdd, String token) public void setAuthService(IAuthenticationService authService) { this.authService = authService; } - } diff --git a/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/TransactionFactory.java b/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/TransactionFactory.java index 8d704360a..fd75117fe 100644 --- a/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/TransactionFactory.java +++ b/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/TransactionFactory.java @@ -29,6 +29,7 @@ public ITransaction provide() { try { logService.log(LogService.LOG_DEBUG, "Create new transaction."); return persistencyService.openTransaction(); + } catch (SpecmateException e) { logService.log(LogService.LOG_ERROR, "Transaction factory could not create new transaction", e); return null; diff --git a/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/batch/BatchService.java b/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/batch/BatchService.java index fa6ce369b..33a441467 100644 --- a/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/batch/BatchService.java +++ b/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/batch/BatchService.java @@ -10,7 +10,6 @@ import com.specmate.auth.api.IAuthenticationService; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.emfjson.EMFJsonDeserializer; import com.specmate.emfrest.api.IRestService; import com.specmate.emfrest.api.RestServiceBase; @@ -41,8 +40,7 @@ public boolean canPost(Object project, Object batchOperation) { } @Override - public RestResult post(Object projectObj, Object batchOperationObj, String token) - throws SpecmateValidationException, SpecmateException { + public RestResult post(Object projectObj, Object batchOperationObj, String token) throws SpecmateException { Folder project = (Folder) projectObj; EMFJsonDeserializer emfJsonDeserializer = new EMFJsonDeserializer(resolver, project.eResource()); JSONObject batchObj = new JSONObject(new JSONTokener((String) batchOperationObj)); diff --git a/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/rest/SpecmateResource.java b/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/rest/SpecmateResource.java index 636d4b69c..29ee97ddf 100644 --- a/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/rest/SpecmateResource.java +++ b/bundles/specmate-emfrest/src/com/specmate/emfrest/internal/rest/SpecmateResource.java @@ -168,14 +168,12 @@ private Object handleRequest(String serviceName, RestServiceChecker checkRestSer result = executeRestService.executeRestService(service); return result.getResponse(); } - } catch (SpecmateValidationException e) { - transaction.rollback(); - logService.log(LogService.LOG_ERROR, e.getLocalizedMessage()); - return Response.status(Status.BAD_REQUEST).build(); } catch (SpecmateException e) { - transaction.rollback(); - logService.log(LogService.LOG_ERROR, e.getLocalizedMessage()); + logService.log(LogService.LOG_ERROR, e.getMessage()); return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + } catch (SpecmateValidationException e) { + logService.log(LogService.LOG_ERROR, e.getMessage()); + return Response.status(Status.BAD_REQUEST).build(); } } finally { @@ -218,6 +216,6 @@ private interface RestServiceChecker { @FunctionalInterface private interface RestServiceExcecutor { - RestResult executeRestService(IRestService service) throws SpecmateException, SpecmateValidationException; + RestResult executeRestService(IRestService service) throws SpecmateException; } } diff --git a/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/services/HPConnector.java b/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/services/HPConnector.java index 8837c6858..53b5294fd 100644 --- a/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/services/HPConnector.java +++ b/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/services/HPConnector.java @@ -132,8 +132,6 @@ public RestResult get(Object target, MultivaluedMap queryPara } Requirement localRequirement = (Requirement) target; - // TODO: We should check the source of the requirment, there might be - // more sources in future if (localRequirement.getExtId() == null) { return new RestResult<>(Response.Status.OK, localRequirement); } diff --git a/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/util/HPProxyConnection.java b/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/util/HPProxyConnection.java index 2751b85f6..b20ae7332 100644 --- a/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/util/HPProxyConnection.java +++ b/bundles/specmate-hp-connector/src/com/specmate/connectors/hpconnector/internal/util/HPProxyConnection.java @@ -33,10 +33,9 @@ public class HPProxyConnection { private static final String QUERY_PARAM_PASSWORD = "password"; private static final String QUERY_PARAM_USER = "username"; - + /** The source id */ public static final String HPPROXY_SOURCE_ID = "hpproxy"; - /** Error message */ private static final String ERROR_MSG = "Error while retrieving from HP Interface"; @@ -53,7 +52,7 @@ public class HPProxyConnection { /** * Service activation - * + * * @throws SpecmateValidationException */ public HPProxyConnection(String host, String port, int timeout) throws SpecmateValidationException { @@ -116,6 +115,7 @@ public Collection getRequirements(String project) throws SpecmateEx if (response.getStatus() != Response.Status.OK.getStatusCode()) { throw new SpecmateException(ERROR_MSG + ": Status code is " + response.getStatus()); } + response.close(); for (int i = 0; i < jsonRequirements.length(); i++) { JSONObject jsonRequirement = jsonRequirements.getJSONObject(i); diff --git a/bundles/specmate-integration-test/bnd.bnd b/bundles/specmate-integration-test/bnd.bnd index e39ae8de4..a455c7bb6 100644 --- a/bundles/specmate-integration-test/bnd.bnd +++ b/bundles/specmate-integration-test/bnd.bnd @@ -4,7 +4,8 @@ Test-Cases: \ com.specmate.test.integration.HistoryTest,\ com.specmate.test.integration.AuthenticationTest,\ com.specmate.test.integration.CDOPersistencyShutdownTest,\ - com.specmate.test.integration.ProjectConfigServiceTest + com.specmate.test.integration.ProjectConfigServiceTest,\ + com.specmate.test.integration.CDOPersistencyValidationTest -buildpath: \ biz.aQute.launcher,\ specmate-persistency-api;version=latest,\ @@ -45,7 +46,9 @@ Test-Cases: \ specmate-auth;version=latest,\ specmate-dbprovider-h2;version=latest,\ specmate-cdo-server;version=latest,\ - specmate-rest;version=latest + specmate-rest;version=latest,\ + org.apache.servicemix.bundles.generex,\ + org.apache.servicemix.bundles.automaton -runee: JavaSE-1.8 -runfw: org.eclipse.osgi;version='[3.10.2.v20150203-1939,3.10.2.v20150203-1939]' @@ -100,7 +103,8 @@ Bundle-Version: 0.0.0.${tstamp} osgi.identity;filter:='(osgi.identity=specmate-cdo-server)',\ osgi.identity;filter:='(osgi.identity=specmate-config-api)',\ osgi.identity;filter:='(osgi.identity=specmate-config)',\ - osgi.identity;filter:='(osgi.identity=specmate-connectors)' + osgi.identity;filter:='(osgi.identity=specmate-connectors)',\ + osgi.identity;filter:='(osgi.identity=org.apache.servicemix.bundles.generex)' -runbundles: \ javassist;version='[3.18.1,3.18.2)',\ javax.annotation-api;version='[1.2.0,1.2.1)',\ @@ -233,11 +237,14 @@ Bundle-Version: 0.0.0.${tstamp} specmate-metrics;version=snapshot,\ org.h2;version='[1.3.168,1.3.169)',\ specmate-cdo-server;version=snapshot,\ - org.apache.commons.lang3;version='[3.3.2,3.3.3)',\ org.eclipse.emf.cdo.server.db;version='[4.4.0,4.4.1)',\ specmate-rest;version=snapshot,\ specmate-scheduler;version=snapshot,\ - specmate-config;version=snapshot + specmate-config;version=snapshot,\ + org.apache.servicemix.bundles.automaton;version='[1.11.0,1.11.1)',\ + org.apache.servicemix.bundles.generex;version='[1.0.2,1.0.3)',\ + org.apache.commons.collections4;version='[4.0.0,4.0.1)',\ + org.apache.commons.lang3;version='[3.3.2,3.3.3)' -runproperties: \ jetty.http.port=8088,\ diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/AuthenticationTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/AuthenticationTest.java index 8ef063ecb..996b9431d 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/AuthenticationTest.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/AuthenticationTest.java @@ -46,9 +46,11 @@ public void testUnauthorizedPost() throws SpecmateException, SpecmateValidationE RestResult result = clientProjectA.post(listUrl(projectAName), requirementB); assertEquals(Status.OK.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); result = clientProjectA.post(listUrl(projectBName), requirementA); assertEquals(Status.UNAUTHORIZED.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); } @Test @@ -58,8 +60,10 @@ public void testUnauthorizedGet() throws SpecmateException, SpecmateValidationEx RestResult result = clientProjectA.get(detailUrl(projectAName)); assertEquals(Status.OK.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); result = clientProjectA.get(projectBName); assertEquals(Status.UNAUTHORIZED.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); } } diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/CDOPersistencyShutdownTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/CDOPersistencyShutdownTest.java index 696228d16..604411bd5 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/CDOPersistencyShutdownTest.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/CDOPersistencyShutdownTest.java @@ -23,6 +23,7 @@ public CDOPersistencyShutdownTest() throws Exception { @Test public void testCDOPersistencyInternalShutdown() throws SpecmateException, SpecmateValidationException { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Folder folder = getTestFolder(); Assert.assertTrue(transaction.isActive()); @@ -37,6 +38,7 @@ public void testCDOPersistencyInternalShutdown() throws SpecmateException, Specm persistency.start(); transaction = persistency.openTransaction(); + transaction.enableValidators(false); Assert.assertTrue(transaction.isActive()); checkWriteIsPossible(transaction); checkModifyIsPossible(transaction, folder); @@ -46,6 +48,7 @@ public void testCDOPersistencyInternalShutdown() throws SpecmateException, Specm @Test public void testReconfigureDBProvider() throws Exception { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Folder folder = getTestFolder(); Assert.assertTrue(transaction.isActive()); @@ -64,6 +67,7 @@ public void testReconfigureDBProvider() throws Exception { persistency.start(); transaction = persistency.openTransaction(); + transaction.enableValidators(false); Assert.assertTrue(transaction.isActive()); // Check that new database is empty @@ -88,7 +92,7 @@ private void checkWriteIsPossible(ITransaction transaction) throws SpecmateExcep transaction.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { try { transaction.getResource().getContents().add(folder); } catch (Exception e) { @@ -120,7 +124,7 @@ private void checkModifyIsPossible(ITransaction transaction, Folder folder) transaction.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { try { folder.setId(Long.toString(System.currentTimeMillis())); } catch (Exception e) { diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/CDOPersistencyValidationTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/CDOPersistencyValidationTest.java new file mode 100644 index 000000000..515caa129 --- /dev/null +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/CDOPersistencyValidationTest.java @@ -0,0 +1,701 @@ +package com.specmate.test.integration; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.eclipse.emf.ecore.resource.Resource; +import org.junit.Test; + +import com.mifmif.common.regex.Generex; +import com.specmate.common.SpecmateException; +import com.specmate.common.SpecmateValidationException; +import com.specmate.model.base.BaseFactory; +import com.specmate.model.base.Folder; +import com.specmate.model.requirements.CEGConnection; +import com.specmate.model.requirements.CEGNode; +import com.specmate.model.requirements.RequirementsFactory; +import com.specmate.persistency.IChange; +import com.specmate.persistency.ITransaction; +import com.specmate.persistency.validation.ConnectionValidator; +import com.specmate.persistency.validation.IDValidator; +import com.specmate.persistency.validation.NameValidator; +import com.specmate.persistency.validation.TextLengthValidator; +import com.specmate.persistency.validation.TopLevelValidator; + +public class CDOPersistencyValidationTest extends IntegrationTestBase { + + public CDOPersistencyValidationTest() throws Exception { + super(); + } + + @Test + public void testIDValidCharacters() { + try { + ITransaction t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + folder.setId("tEst_1-2"); + t.getResource().getContents().add(folder); + return null; + } + }); + t.close(); + } catch (SpecmateException | SpecmateValidationException e) { + fail(e.getMessage()); + } + } + + @Test + public void testIDInvalidCharacters() { + Generex generex = new Generex("test-[^a-zA-Z_0-9\\-]_case"); + generex.setSeed(System.currentTimeMillis()); + ITransaction t = null; + + for (int i = 0; i < 10; i++) { + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + String id = generex.random(1, 1); + folder.setId(id); + r.getContents().add(folder); + return null; + } + }); + fail("Invalid id not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + } + + @Test + public void testIDEmptyNull() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + r.getContents().add(folder); + return null; + } + }); + fail("Null id not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testIDEmptyString() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + folder.setId(""); + r.getContents().add(folder); + return null; + } + }); + fail("Empty id not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + t.close(); + } + } + + @Test + public void testIDEmptySpace() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + folder.setId(" "); + r.getContents().add(folder); + return null; + } + }); + fail("Space id not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + t.close(); + } + } + + @Test + public void testNameNull() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new NameValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + r.getContents().add(folder); + return null; + } + }); + fail("Null folder name not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testNameEmptyString() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new NameValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + folder.setName(""); + r.getContents().add(folder); + return null; + } + }); + fail("Empty folder name not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testNameSpace() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new NameValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + folder.setName(" "); + r.getContents().add(folder); + return null; + } + }); + fail("Space folder name not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testNameInvalidChars() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new NameValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder folder = BaseFactory.eINSTANCE.createFolder(); + folder.setName("This;"); + r.getContents().add(folder); + return null; + } + }); + fail("Invalid name not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testUniqueID() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder parent = BaseFactory.eINSTANCE.createFolder(); + parent.setId("parent"); + Folder child1 = BaseFactory.eINSTANCE.createFolder(); + child1.setId("child1"); + Folder child2 = BaseFactory.eINSTANCE.createFolder(); + child2.setId("child2"); + + parent.getContents().add(child1); + parent.getContents().add(child2); + r.getContents().add(parent); + return null; + } + }); + } catch (SpecmateException | SpecmateValidationException e) { + fail(e.getCause().getMessage()); + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testUniqueIDUnderSameParent() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder parent = BaseFactory.eINSTANCE.createFolder(); + parent.setId("parent"); + Folder child1 = BaseFactory.eINSTANCE.createFolder(); + child1.setId("child1"); + Folder child2 = BaseFactory.eINSTANCE.createFolder(); + child2.setId("child2"); + + Folder child_clone = BaseFactory.eINSTANCE.createFolder(); + child_clone.setId(child1.getId()); + + parent.getContents().add(child1); + parent.getContents().add(child2); + parent.getContents().add(child_clone); + r.getContents().add(parent); + return null; + } + }); + fail("Add the same node twice in tree"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testSameIDinDifferentBranch() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder parent = BaseFactory.eINSTANCE.createFolder(); + parent.setId("parent"); + Folder child1 = BaseFactory.eINSTANCE.createFolder(); + child1.setId("child1"); + Folder child2 = BaseFactory.eINSTANCE.createFolder(); + child2.setId("child2"); + + Folder grandchild = BaseFactory.eINSTANCE.createFolder(); + grandchild.setId("grandchild"); + + parent.getContents().add(child1); + parent.getContents().add(child2); + child1.getContents().add(grandchild); + child2.getContents().add(grandchild); + r.getContents().add(parent); + return null; + } + }); + } catch (SpecmateException | SpecmateValidationException e) { + fail("Siblings can have children with the same id"); + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testAddIdenticalObject() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder parent = BaseFactory.eINSTANCE.createFolder(); + parent.setId("parent"); + Folder child1 = BaseFactory.eINSTANCE.createFolder(); + child1.setId("child1"); + Folder child2 = BaseFactory.eINSTANCE.createFolder(); + child2.setId("child2"); + + Folder grandchild = BaseFactory.eINSTANCE.createFolder(); + grandchild.setId("grandchild"); + + parent.getContents().add(child1); + parent.getContents().add(child2); + child1.getContents().add(grandchild); + child1.getContents().add(grandchild); // Adding the same object to the list has no effect, i.e. the + // list is rather a set + assertEquals(1, child1.getContents().size()); + r.getContents().add(parent); + return null; + } + }); + } catch (SpecmateException | SpecmateValidationException e) { + fail(e.getMessage()); + } finally { + if (t != null) { + t.close(); + } + } + + } + + @Test + public void testUniqueIDinSameBranch() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new IDValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder parent = BaseFactory.eINSTANCE.createFolder(); + parent.setId("parent"); + Folder child1 = BaseFactory.eINSTANCE.createFolder(); + child1.setId("child1"); + Folder child2 = BaseFactory.eINSTANCE.createFolder(); + child2.setId("child2"); + + Folder grandchild = BaseFactory.eINSTANCE.createFolder(); + grandchild.setId("grandchild"); + Folder grandchild_clone = BaseFactory.eINSTANCE.createFolder(); + grandchild_clone.setId(grandchild.getId()); + + parent.getContents().add(child1); + parent.getContents().add(child2); + child1.getContents().add(grandchild); + child1.getContents().add(grandchild_clone); + assertEquals(2, child1.getContents().size()); + r.getContents().add(parent); + return null; + } + }); + fail("Could add the same node twice in tree"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testTopLevelFolder() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder parent = BaseFactory.eINSTANCE.createFolder(); + parent.setId("parent"); + Folder child1 = BaseFactory.eINSTANCE.createFolder(); + child1.setId("child1"); + Folder child2 = BaseFactory.eINSTANCE.createFolder(); + child2.setId("child2"); + + parent.getContents().add(child1); + parent.getContents().add(child2); + r.getContents().add(parent); + return null; + + } + }); + } catch (SpecmateException | SpecmateValidationException e) { + fail(e.getMessage()); + } finally { + if (t != null) { + t.close(); + } + } + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new TopLevelValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder child3 = BaseFactory.eINSTANCE.createFolder(); + child3.setId("child3"); + + Folder project = (Folder) r.getContents().get(0); + Folder topLevelFolder = (Folder) project.getContents().get(0); + assertTrue(topLevelFolder.getContents().add(child3)); // This is allowed + assertTrue(project.getContents().add(child3)); // This not + return null; + } + }); + fail("Top level folder violation not detected"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testTextLengthTooLong() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new TextLengthValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + Folder f = BaseFactory.eINSTANCE.createFolder(); + StringBuilder s = new StringBuilder(); + for (int i = 0; i < TextLengthValidator.MAX_LENGTH + 1; i++) { + s.append("."); + } + f.setDescription(s.toString()); + r.getContents().add(f); + return null; + } + }); + fail("Could add object with too large text content"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testMissingSourceTarget() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new ConnectionValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + CEGConnection c = RequirementsFactory.eINSTANCE.createCEGConnection(); + c.setId("c1"); + c.setDescription("c1"); + r.getContents().add(c); + return null; + } + }); + fail("Could store connection without source or target"); + } catch (SpecmateException | SpecmateValidationException e) { + // All OK + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testMissingSource() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new ConnectionValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + CEGConnection c = RequirementsFactory.eINSTANCE.createCEGConnection(); + c.setId("c1"); + c.setDescription("c1"); + CEGNode n = RequirementsFactory.eINSTANCE.createCEGNode(); + n.setId("n1"); + n.setDescription("n1"); + c.setTarget(n); + r.getContents().add(c); + r.getContents().add(n); + return null; + } + }); + fail("Could store connection without source"); + } catch (SpecmateException | SpecmateValidationException e) { + assertTrue(e.getMessage().contains("source")); + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testMissingTarget() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new ConnectionValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + CEGConnection c = RequirementsFactory.eINSTANCE.createCEGConnection(); + c.setId("c1"); + c.setDescription("c1"); + CEGNode n = RequirementsFactory.eINSTANCE.createCEGNode(); + n.setId("n1"); + n.setDescription("n1"); + c.setSource(n); + r.getContents().add(c); + r.getContents().add(n); + return null; + } + }); + fail("Could store connection without target"); + } catch (SpecmateException | SpecmateValidationException e) { + assertTrue(e.getMessage().contains("target")); + } finally { + if (t != null) { + t.close(); + } + } + } + + @Test + public void testConnection() { + ITransaction t = null; + + try { + t = persistency.openTransaction(); + t.resetValidarors(); + t.addValidator(new ConnectionValidator()); + Resource r = t.getResource(); + t.doAndCommit(new IChange() { + @Override + public Object doChange() throws SpecmateException { + CEGConnection c = RequirementsFactory.eINSTANCE.createCEGConnection(); + c.setId("c1"); + c.setDescription("c1"); + CEGNode s = RequirementsFactory.eINSTANCE.createCEGNode(); + s.setId("s"); + s.setDescription("s"); + c.setSource(s); + CEGNode t = RequirementsFactory.eINSTANCE.createCEGNode(); + t.setId("t"); + t.setDescription("t"); + c.setTarget(t); + r.getContents().add(c); + r.getContents().add(s); + r.getContents().add(t); + return null; + } + }); + } catch (SpecmateException | SpecmateValidationException e) { + fail(e.getCause().getMessage()); + } finally { + if (t != null) { + t.close(); + } + } + } +} diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/CrudTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/CrudTest.java index ed3158259..56e968a51 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/CrudTest.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/CrudTest.java @@ -20,6 +20,12 @@ public class CrudTest extends EmfRestTest { public CrudTest() throws Exception { super(); } + + private void performDuplicate(String... segments) { + String duplicateUrl = buildUrl("duplicate", segments); + RestResult result = restClient.post(duplicateUrl, null); + Assert.assertEquals(Status.OK.getStatusCode(), result.getResponse().getStatus()); + } /** * Tests posting a folder to the root. Checks, if the return code of the post @@ -32,6 +38,7 @@ public void testPostFolderToRootAndRetrieve() { logService.log(LogService.LOG_DEBUG, "Posting the object " + folder.toString() + " to url " + postUrl); RestResult result = restClient.post(postUrl, folder); Assert.assertEquals(result.getResponse().getStatus(), Status.OK.getStatusCode()); + result.getResponse().close(); String retrieveUrl = detailUrl(getId(folder)); RestResult getResult = restClient.get(retrieveUrl); @@ -39,6 +46,7 @@ public void testPostFolderToRootAndRetrieve() { logService.log(LogService.LOG_DEBUG, "Retrieved the object " + retrievedFolder.toString() + " from url " + retrieveUrl); Assert.assertTrue(EmfRestTestUtil.compare(folder, retrievedFolder, true)); + getResult.getResponse().close(); } /** @@ -53,6 +61,7 @@ public void testPostFolderWithSpecialChars() { logService.log(LogService.LOG_DEBUG, "Posting the object " + folder.toString() + " to url " + postUrl); RestResult result = restClient.post(postUrl, folder); Assert.assertEquals(result.getResponse().getStatus(), Status.OK.getStatusCode()); + result.getResponse().close(); String retrieveUrl = detailUrl(getId(folder)); RestResult getResult = restClient.get(retrieveUrl); @@ -60,6 +69,7 @@ public void testPostFolderWithSpecialChars() { logService.log(LogService.LOG_DEBUG, "Retrieved the object " + retrievedFolder.toString() + " from url " + retrieveUrl); Assert.assertTrue(EmfRestTestUtil.compare(folder, retrievedFolder, true)); + getResult.getResponse().close(); } /** @@ -78,6 +88,7 @@ public void testPostFolderToFolderAndRetrieve() { logService.log(LogService.LOG_DEBUG, "Posting the object " + folder2.toString() + " to url " + postUrl2); RestResult result2 = restClient.post(postUrl2, folder2); Assert.assertEquals(result2.getResponse().getStatus(), Status.OK.getStatusCode()); + result2.getResponse().close(); String retrieveUrl = detailUrl(folderName, folderName2); RestResult getResult = restClient.get(retrieveUrl); @@ -85,6 +96,7 @@ public void testPostFolderToFolderAndRetrieve() { logService.log(LogService.LOG_DEBUG, "Retrieved the object " + retrievedFolder.toString() + " from url " + retrieveUrl); Assert.assertTrue(EmfRestTestUtil.compare(retrievedFolder, folder2, true)); + getResult.getResponse().close(); } /** Tests if retrieving a non-existing object returns 404-Not found */ @@ -99,7 +111,7 @@ public void testMissingFolder() { RestResult getResult = restClient.get(retrieveUrl); Assert.assertEquals(Status.NOT_FOUND.getStatusCode(), getResult.getResponse().getStatus()); - + getResult.getResponse().close(); } /** Tests retrieving a list of child folders from a folder */ @@ -117,6 +129,7 @@ public void testRetrieveChildrenList() { logService.log(LogService.LOG_DEBUG, "Posting the object " + folders[i].toString() + " to url " + postUrl2); RestResult result2 = restClient.post(postUrl2, folders[i]); Assert.assertEquals(result2.getResponse().getStatus(), Status.OK.getStatusCode()); + result2.getResponse().close(); } RestResult listResult = restClient.getList(postUrl2); @@ -126,7 +139,7 @@ public void testRetrieveChildrenList() { for (int i = 0; i < numberOfChildren; i++) { Assert.assertTrue(EmfRestTestUtil.compare(folders[i], childrenList.getJSONObject(i), true)); } - + listResult.getResponse().close(); } /** Tests if an empty folder can be deleted */ @@ -360,7 +373,6 @@ public void testPostProcessNodesAndConnectionToProcess() { public void testPostFolderWithNoId() { JSONObject folder = createTestFolder(); folder.remove(ID_KEY); - postObject(Status.BAD_REQUEST.getStatusCode(), folder); } @@ -425,6 +437,7 @@ public void testGenerateTests() { logService.log(LogService.LOG_DEBUG, "Request test genreation at url " + generateUrl); RestResult result = restClient.post(generateUrl, null); Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); String retrieveUrl = listUrl(requirementId, cegId, testSpecId); RestResult getResult = restClient.getList(retrieveUrl); @@ -434,6 +447,68 @@ public void testGenerateTests() { // Expect 4 children: two test cases and two test parameters Assert.assertEquals(4, retrievedTestChilds.length()); + getResult.getResponse().close(); + } + + @Test + public void testGenerateTestsWithMutExConstraint() { + JSONObject requirement = postRequirementToRoot(); + String requirementId = getId(requirement); + + // Post ceg model + JSONObject cegModel = postCEG(requirementId); + String cegId = getId(cegModel); + + // post node 1 + JSONObject cegNode1 = createTestCegNode("myvar","=A", "OR"); + cegNode1 = postObject(cegNode1, requirementId, cegId); + String cegNode1Id = getId(cegNode1); + JSONObject retrievedCegNode1 = getObject(requirementId, cegId, cegNode1Id); + + // post node 2 + JSONObject cegNode2 = createTestCegNode("myvar","=B","OR"); + cegNode2=postObject(cegNode2,requirementId, cegId); + String cegNode2Id = getId(cegNode2); + JSONObject retrievedCegNode2 = getObject(requirementId, cegId, cegNode2Id); + + // post node 3 + JSONObject cegNode3 = createTestCegNode("result","true","AND"); + cegNode3=postObject(cegNode3,requirementId, cegId); + String cegNode3Id = getId(cegNode3); + JSONObject retrievedCegNode3 = getObject(requirementId, cegId, cegNode3Id); + + // post connection + postCEGConnection(retrievedCegNode1, retrievedCegNode3, false, requirementId, cegId); + postCEGConnection(retrievedCegNode2, retrievedCegNode3, false, requirementId, cegId); + + // Post test specification + JSONObject testSpec = postTestSpecification(requirementId, cegId); + String testSpecId = getId(testSpec); + + // Generate test cases + String generateUrl = buildUrl("generateTests", requirementId, cegId, testSpecId); + logService.log(LogService.LOG_DEBUG, "Request test genreation at url " + generateUrl); + RestResult result = restClient.post(generateUrl, null); + Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), result.getResponse().getStatus()); + + String retrieveUrl = listUrl(requirementId, cegId, testSpecId); + RestResult getResult = restClient.getList(retrieveUrl); + JSONArray retrievedTestChilds = getResult.getPayload(); + logService.log(LogService.LOG_DEBUG, + "Retrieved the object " + retrievedTestChilds.toString() + " from url " + retrieveUrl); + + List testCases = getTestCases(retrievedTestChilds); + + // Expect 3 tests should be generated + Assert.assertEquals(3, testCases.size()); + + int numberOfInconsistentTests = 0; + for (JSONObject testCase : testCases) { + if (!testCase.getBoolean("consistent")) { + numberOfInconsistentTests++; + } + } + Assert.assertEquals(1, numberOfInconsistentTests); } /** @@ -487,6 +562,7 @@ public void testContradictoryModelTestGeneration() { // Generation should succeed Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); String retrieveUrl = listUrl(requirementId, cegId, testSpecId); RestResult getResult = restClient.getList(retrieveUrl); @@ -506,6 +582,7 @@ public void testContradictoryModelTestGeneration() { } } Assert.assertEquals(2, numberOfInconsistentTests); + getResult.getResponse().close(); } /** @@ -552,6 +629,7 @@ public void testConflictingRuleApplicationModelTestGeneration() { // Generation should succeed Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); String retrieveUrl = listUrl(requirementId, cegId, testSpecId); RestResult getResult = restClient.getList(retrieveUrl); @@ -571,6 +649,7 @@ public void testConflictingRuleApplicationModelTestGeneration() { } } Assert.assertEquals(1, numberOfInconsistentTests); + getResult.getResponse().close(); } private List getTestCases(JSONArray array) { @@ -615,6 +694,7 @@ public void testGetListRecursive() { EmfRestTestUtil.compare(retrievedTestSpecifications.getJSONObject(0), testSpecification, true)); Assert.assertTrue( EmfRestTestUtil.compare(retrievedTestSpecifications.getJSONObject(1), testSpecification2, true)); + listResult.getResponse().close(); } protected JSONObject createTestBatchOp(JSONObject target, String type, JSONObject value) { @@ -663,6 +743,7 @@ public void testBatch() { String postUrl = buildUrl("batch", projectId); RestResult result = restClient.post(postUrl, batch); + result.getResponse().close(); JSONObject retrievedFolder = getObject(projectId, folderId); Assert.assertTrue(EmfRestTestUtil.compare(updateFolder, retrievedFolder, true)); @@ -699,4 +780,27 @@ public void testInconsistentProject() { postObject(Status.UNAUTHORIZED.getStatusCode(), cegConnection, project2Id, ceg2Id); } + + @Test + public void testDuplicate() { + JSONObject requirement = postRequirementToRoot(); + String requirementId = getId(requirement); + + // Post ceg model + JSONObject cegModel = postCEG(requirementId); + String cegId = getId(cegModel); + + RestResult result = restClient.getList(listUrl(requirementId)); + JSONArray payload = result.getPayload(); + Assert.assertEquals(1, payload.length()); + + performDuplicate(requirementId, cegId); + + result = restClient.getList(listUrl(requirementId)); + payload = result.getPayload(); + Assert.assertEquals(2, payload.length()); + +// They are not equal, as id and name are different +// Assert.assertTrue(EmfRestTestUtil.compare(payload.getJSONObject(0), payload.getJSONObject(1), true)); + } } diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/EmfRestTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/EmfRestTest.java index 5663345a4..2f03e7783 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/EmfRestTest.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/EmfRestTest.java @@ -157,17 +157,23 @@ protected JSONObject createTestProcessModel() { process.put(BasePackage.Literals.INAMED__NAME.getName(), processName); return process; } - + protected JSONObject createTestCegNode() { + String variable = "Variable" + counter++; + String condition ="Condition" + counter++; + return createTestCegNode(variable,condition,NodeType.OR.getLiteral()); + } + + protected JSONObject createTestCegNode(String variable, String condition, String operation) { String cegName = "TestCegNode" + counter++; JSONObject cegNode = new JSONObject(); cegNode.put(NSURI_KEY, RequirementsPackage.eNS_URI); cegNode.put(ECLASS, RequirementsPackage.Literals.CEG_NODE.getName()); cegNode.put(BasePackage.Literals.IID__ID.getName(), cegName); cegNode.put(BasePackage.Literals.INAMED__NAME.getName(), cegName); - cegNode.put(RequirementsPackage.Literals.CEG_NODE__VARIABLE.getName(), cegName); - cegNode.put(RequirementsPackage.Literals.CEG_NODE__CONDITION.getName(), "5"); - cegNode.put(RequirementsPackage.Literals.CEG_NODE__TYPE.getName(), NodeType.OR.getLiteral()); + cegNode.put(RequirementsPackage.Literals.CEG_NODE__VARIABLE.getName(), variable); + cegNode.put(RequirementsPackage.Literals.CEG_NODE__CONDITION.getName(), condition); + cegNode.put(RequirementsPackage.Literals.CEG_NODE__TYPE.getName(), operation); return cegNode; } @@ -217,6 +223,7 @@ protected JSONObject createTestCEGConnection(JSONObject node1, JSONObject node2, connection.put(NSURI_KEY, RequirementsPackage.eNS_URI); connection.put(ECLASS, RequirementsPackage.Literals.CEG_CONNECTION.getName()); connection.put(BasePackage.Literals.IID__ID.getName(), connectionName); + connection.put(BasePackage.Literals.INAMED__NAME.getName(), connectionName); connection.put(BasePackage.Literals.IMODEL_CONNECTION__SOURCE.getName(), EmfRestTestUtil.proxy(node1)); connection.put(BasePackage.Literals.IMODEL_CONNECTION__TARGET.getName(), EmfRestTestUtil.proxy(node2)); connection.put(RequirementsPackage.Literals.CEG_CONNECTION__NEGATE.getName(), isNegated); @@ -229,6 +236,7 @@ protected JSONObject createTestStepConnection(JSONObject node1, JSONObject node2 connection.put(NSURI_KEY, ProcessesPackage.eNS_URI); connection.put(ECLASS, ProcessesPackage.Literals.PROCESS_CONNECTION.getName()); connection.put(BasePackage.Literals.IID__ID.getName(), connectionName); + connection.put(BasePackage.Literals.INAMED__NAME.getName(), connectionName); connection.put(BasePackage.Literals.IMODEL_CONNECTION__SOURCE.getName(), EmfRestTestUtil.proxy(node1)); connection.put(BasePackage.Literals.IMODEL_CONNECTION__TARGET.getName(), EmfRestTestUtil.proxy(node2)); return connection; @@ -240,6 +248,7 @@ protected JSONObject createTestDecisionConnection(JSONObject node1, JSONObject n connection.put(NSURI_KEY, ProcessesPackage.eNS_URI); connection.put(ECLASS, ProcessesPackage.Literals.PROCESS_CONNECTION.getName()); connection.put(BasePackage.Literals.IID__ID.getName(), connectionName); + connection.put(BasePackage.Literals.INAMED__NAME.getName(), connectionName); connection.put(BasePackage.Literals.IMODEL_CONNECTION__SOURCE.getName(), EmfRestTestUtil.proxy(node1)); connection.put(BasePackage.Literals.IMODEL_CONNECTION__TARGET.getName(), EmfRestTestUtil.proxy(node2)); connection.put(ProcessesPackage.Literals.PROCESS_CONNECTION__CONDITION.getName(), "condition" + counter++); @@ -359,6 +368,8 @@ protected JSONObject postObject(int statusCode, JSONObject object, String... seg try { Thread.sleep(200); } catch (InterruptedException e) { + } finally { + result.getResponse().close(); } return object; } @@ -372,6 +383,7 @@ protected void updateObject(int statusCode, JSONObject object, String... segment logService.log(LogService.LOG_DEBUG, "Updateing the object " + object.toString() + " at url " + updateUrl); RestResult putResult = restClient.put(updateUrl, object); Assert.assertEquals(statusCode, putResult.getResponse().getStatus()); + putResult.getResponse().close(); } protected JSONObject getObject(int statusCode, String... segments) { @@ -389,6 +401,7 @@ protected JSONObject getObjectByUrl(int statusCode, String url) { logService.log(LogService.LOG_DEBUG, "Empty result from url " + url); } Assert.assertEquals(statusCode, getResult.getResponse().getStatus()); + getResult.getResponse().close(); return retrievedObject; } @@ -402,6 +415,7 @@ protected void deleteObject(String... segments) { logService.log(LogService.LOG_DEBUG, "Deleting object with URL " + deleteUrl); RestResult deleteResult = restClient.delete(deleteUrl); Assert.assertEquals(Status.OK.getStatusCode(), deleteResult.getResponse().getStatus()); + deleteResult.getResponse().close(); } protected String listUrl(String... segments) { diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/HistoryTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/HistoryTest.java index a0bd3653e..4d540a4ff 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/HistoryTest.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/HistoryTest.java @@ -22,6 +22,7 @@ private JSONArray getEntries(String type, String... segments) { String historyUrl = buildUrl("history", segments); RestResult result = restClient.get(historyUrl, "type", type); JSONObject history = result.getPayload(); + result.getResponse().close(); return history.getJSONArray(HistoryPackage.Literals.HISTORY__ENTRIES.getName()); } diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/IntegrationTestBase.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/IntegrationTestBase.java index 6366938ab..cffffc8ba 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/IntegrationTestBase.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/IntegrationTestBase.java @@ -74,21 +74,24 @@ protected Dictionary getDBProviderProperties() throws SpecmateEx private void clearPersistency() throws SpecmateException, SpecmateValidationException { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); + transaction.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { transaction.getResource().getContents().clear(); return null; } }); - transaction.close(); - try { Thread.sleep(200); } catch (InterruptedException e) { - + throw new SpecmateException(e); } + + assert (transaction.getResource().getContents().size() == 0); + transaction.close(); } private ConfigurationAdmin getConfigAdmin() throws SpecmateException { diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/ProjectConfigServiceTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/ProjectConfigServiceTest.java index ebfcd924b..6b33feceb 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/ProjectConfigServiceTest.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/ProjectConfigServiceTest.java @@ -104,7 +104,7 @@ private void testAllNewLibraryFolders_initData() throws SpecmateException, Specm trans.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { root.add(testA); root.add(testB); return null; @@ -147,7 +147,7 @@ private void testSomeNewLibraryFolders_initData() throws SpecmateException, Spec trans.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { root.add(testA); root.add(testB); return null; @@ -202,7 +202,7 @@ private void testNoNewLibraryFolders_initData() throws SpecmateException, Specma trans.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { root.add(testA); root.add(testB); return null; @@ -306,7 +306,7 @@ private void testNewAndModifyLibraryFolders_initData() throws SpecmateException, trans.doAndCommit(new IChange() { @Override - public Object doChange() throws SpecmateException, SpecmateValidationException { + public Object doChange() throws SpecmateException { root.add(testA); root.add(testB); return null; @@ -360,7 +360,7 @@ private IProjectConfigService getProjectConfigService() throws SpecmateException projectConfigTracker.open(); IProjectConfigService projectConfigService; try { - projectConfigService = projectConfigTracker.waitForService(1000000); + projectConfigService = projectConfigTracker.waitForService(10000); } catch (InterruptedException e) { throw new SpecmateException(e); } diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/SearchTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/SearchTest.java index 99801aede..9331caa5a 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/SearchTest.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/SearchTest.java @@ -60,14 +60,17 @@ private JSONArray performSearch(String project, String query) { String searchUrl = buildUrl("search", project); RestResult result = restClient.getList(searchUrl, "query", query); Assert.assertEquals(Status.OK.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); JSONArray foundObjects = result.getPayload(); return foundObjects; } + private void performReindex() { String reindexUrl = buildUrl("reindex"); RestResult result = restClient.get(reindexUrl); Assert.assertEquals(Status.NO_CONTENT.getStatusCode(), result.getResponse().getStatus()); + result.getResponse().close(); } private JSONArray queryRelatedRequirements(String... segments) { @@ -75,6 +78,7 @@ private JSONArray queryRelatedRequirements(String... segments) { RestResult result = restClient.getList(relatedUrl); Assert.assertEquals(Status.OK.getStatusCode(), result.getResponse().getStatus()); JSONArray foundObjects = result.getPayload(); + result.getResponse().close(); return foundObjects; } diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/support/DummyProject.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/support/DummyProject.java index 899836f3a..c60792d3a 100644 --- a/bundles/specmate-integration-test/src/com/specmate/test/integration/support/DummyProject.java +++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/support/DummyProject.java @@ -1,6 +1,7 @@ package com.specmate.test.integration.support; import java.util.Collection; +import java.util.List; import com.specmate.common.SpecmateException; import com.specmate.connectors.api.IExportService; @@ -63,4 +64,9 @@ public void export(TestProcedure testProcedure) throws SpecmateException { } }; } + + @Override + public List getLibraryFolders() { + return null; + } } diff --git a/bundles/specmate-migration-test/src/com/specmate/migration/test/AddAttributeTest.java b/bundles/specmate-migration-test/src/com/specmate/migration/test/AddAttributeTest.java index 0b623a648..7a267a30f 100644 --- a/bundles/specmate-migration-test/src/com/specmate/migration/test/AddAttributeTest.java +++ b/bundles/specmate-migration-test/src/com/specmate/migration/test/AddAttributeTest.java @@ -29,6 +29,7 @@ public AddAttributeTest() throws Exception { @Override protected void checkMigrationPostconditions() throws Exception { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Resource resource = transaction.getResource(); EObject root = SpecmateEcoreUtil.getEObjectWithId("root", resource.getContents()); assertNotNull(root); diff --git a/bundles/specmate-migration-test/src/com/specmate/migration/test/AddObjectTest.java b/bundles/specmate-migration-test/src/com/specmate/migration/test/AddObjectTest.java index 4db99bb87..70469c06b 100644 --- a/bundles/specmate-migration-test/src/com/specmate/migration/test/AddObjectTest.java +++ b/bundles/specmate-migration-test/src/com/specmate/migration/test/AddObjectTest.java @@ -25,6 +25,7 @@ public AddObjectTest() throws Exception { @Override protected void checkMigrationPostconditions() throws Exception { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Resource resource = transaction.getResource(); EObject root = SpecmateEcoreUtil.getEObjectWithId("root", resource.getContents()); assertNotNull(root); @@ -61,6 +62,7 @@ public Object doChange() throws SpecmateException { Document doc_retrieved = (Document) document; diagram = SpecmateEcoreUtil.getEObjectWithId("d1", doc_retrieved.eContents()); + assertNotNull(diagram); assertTrue(diagram instanceof Diagram); diff --git a/bundles/specmate-migration-test/src/com/specmate/migration/test/AddSeveralAttributesTest.java b/bundles/specmate-migration-test/src/com/specmate/migration/test/AddSeveralAttributesTest.java index cf682499f..ef3d2e7f4 100644 --- a/bundles/specmate-migration-test/src/com/specmate/migration/test/AddSeveralAttributesTest.java +++ b/bundles/specmate-migration-test/src/com/specmate/migration/test/AddSeveralAttributesTest.java @@ -27,6 +27,7 @@ public AddSeveralAttributesTest() throws Exception { @Override protected void checkMigrationPostconditions() throws Exception { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Resource resource = transaction.getResource(); EObject root = SpecmateEcoreUtil.getEObjectWithId("root", resource.getContents()); assertNotNull(root); diff --git a/bundles/specmate-migration-test/src/com/specmate/migration/test/ChangedTypesTest.java b/bundles/specmate-migration-test/src/com/specmate/migration/test/ChangedTypesTest.java index 09453377e..3443cb220 100644 --- a/bundles/specmate-migration-test/src/com/specmate/migration/test/ChangedTypesTest.java +++ b/bundles/specmate-migration-test/src/com/specmate/migration/test/ChangedTypesTest.java @@ -24,6 +24,7 @@ public ChangedTypesTest() throws Exception { protected void checkMigrationPostconditions() throws Exception { IView view = persistency.openView(); Resource resource = view.getResource(); + EObject root = SpecmateEcoreUtil.getEObjectWithId("root", resource.getContents()); assertNotNull(root); diff --git a/bundles/specmate-migration-test/src/com/specmate/migration/test/MigrationTestBase.java b/bundles/specmate-migration-test/src/com/specmate/migration/test/MigrationTestBase.java index aa4df1a56..26e6f0df2 100644 --- a/bundles/specmate-migration-test/src/com/specmate/migration/test/MigrationTestBase.java +++ b/bundles/specmate-migration-test/src/com/specmate/migration/test/MigrationTestBase.java @@ -217,7 +217,7 @@ protected IPersistencyService getPersistencyService() throws SpecmateException { persistencyTracker.open(); IPersistencyService persistency; try { - persistency = persistencyTracker.waitForService(10000); + persistency = persistencyTracker.waitForService(20000); } catch (InterruptedException e) { throw new SpecmateException(e); } @@ -241,6 +241,7 @@ protected IPackageProvider getTestModelService() throws SpecmateException { private void addBaselinedata() throws Exception { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Resource resource = transaction.getResource(); EObject root = SpecmateEcoreUtil.getEObjectWithName("root", resource.getContents()); diff --git a/bundles/specmate-migration-test/src/com/specmate/migration/test/OnlyMetaChangeTest.java b/bundles/specmate-migration-test/src/com/specmate/migration/test/OnlyMetaChangeTest.java index 5649ed32f..6f9ebb072 100644 --- a/bundles/specmate-migration-test/src/com/specmate/migration/test/OnlyMetaChangeTest.java +++ b/bundles/specmate-migration-test/src/com/specmate/migration/test/OnlyMetaChangeTest.java @@ -21,6 +21,7 @@ public OnlyMetaChangeTest() throws Exception { @Override protected void checkMigrationPostconditions() throws Exception { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Resource resource = transaction.getResource(); EObject root = SpecmateEcoreUtil.getEObjectWithId("root", resource.getContents()); assertNotNull(root); diff --git a/bundles/specmate-migration-test/src/com/specmate/migration/test/RenamedAttributeTest.java b/bundles/specmate-migration-test/src/com/specmate/migration/test/RenamedAttributeTest.java index 134853c36..9fd7ed2f3 100644 --- a/bundles/specmate-migration-test/src/com/specmate/migration/test/RenamedAttributeTest.java +++ b/bundles/specmate-migration-test/src/com/specmate/migration/test/RenamedAttributeTest.java @@ -23,6 +23,7 @@ public RenamedAttributeTest() throws Exception { @Override protected void checkMigrationPostconditions() throws Exception { ITransaction transaction = persistency.openTransaction(); + transaction.enableValidators(false); Resource resource = transaction.getResource(); EObject root = SpecmateEcoreUtil.getEObjectWithId("root", resource.getContents()); assertNotNull(root); diff --git a/bundles/specmate-migration/src/com/specmate/migration/internal/services/Migrator20180925.java b/bundles/specmate-migration/src/com/specmate/migration/internal/services/Migrator20180925.java new file mode 100644 index 000000000..71e614321 --- /dev/null +++ b/bundles/specmate-migration/src/com/specmate/migration/internal/services/Migrator20180925.java @@ -0,0 +1,50 @@ +package com.specmate.migration.internal.services; + +import java.sql.Connection; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.specmate.common.SpecmateException; +import com.specmate.dbprovider.api.IDBProvider; +import com.specmate.dbprovider.api.migration.IAttributeToSQLMapper; +import com.specmate.dbprovider.api.migration.IObjectToSQLMapper; +import com.specmate.migration.api.IMigrator; + +@Component(property = "sourceVersion=20180925", service = IMigrator.class) +public class Migrator20180925 implements IMigrator { + + private IDBProvider dbProvider; + + @Override + public String getSourceVersion() { + return "20180925"; + } + + @Override + public String getTargetVersion() { + return "20181108"; + } + + @Override + public void migrate(Connection connection) throws SpecmateException { + String objectName = "TestSpecificationSkeleton"; + String packageName = "model/testspecification"; + IObjectToSQLMapper oMapper = dbProvider.getObjectToSQLMapper(packageName, getSourceVersion(), + getTargetVersion()); + + oMapper.newObject(objectName); + + IAttributeToSQLMapper aMapper = dbProvider.getAttributeToSQLMapper(packageName, getSourceVersion(), + getTargetVersion()); + aMapper.migrateNewStringAttribute(objectName, "name", ""); + // "language" seems to be a reserved term, hence CDO uses "language0" + aMapper.migrateNewStringAttribute(objectName, "language0", ""); + aMapper.migrateNewStringAttribute(objectName, "code", ""); + } + + @Reference + public void setDBProvider(IDBProvider dbProvider) { + this.dbProvider = dbProvider; + } +} diff --git a/bundles/specmate-model-ecore/model/specmate.ecore b/bundles/specmate-model-ecore/model/specmate.ecore index 2e79b1daa..fd57edef7 100644 --- a/bundles/specmate-model-ecore/model/specmate.ecore +++ b/bundles/specmate-model-ecore/model/specmate.ecore @@ -1,7 +1,7 @@ - + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model" nsURI="http://specmate.com/20181108/model" nsPrefix="com.specmate.model"> + @@ -71,7 +71,7 @@ eType="#//base/ITracingElement" eOpposite="#//base/ITracingElement/tracesTo"/> - @@ -135,9 +135,14 @@ - + + + + - @@ -205,7 +210,7 @@ - - - + diff --git a/bundles/specmate-model-ecore/model/specmate.history b/bundles/specmate-model-ecore/model/specmate.history index 4d9cd39c1..84cdbab14 100644 --- a/bundles/specmate-model-ecore/model/specmate.history +++ b/bundles/specmate-model-ecore/model/specmate.history @@ -2193,8 +2193,6 @@ - - @@ -2282,4 +2280,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/specmate-model-ecore/model/user.ecore b/bundles/specmate-model-ecore/model/user.ecore index 142dfe9ad..1ba01660b 100644 --- a/bundles/specmate-model-ecore/model/user.ecore +++ b/bundles/specmate-model-ecore/model/user.ecore @@ -1,6 +1,6 @@ + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="usermodel" nsURI="http://specmate.com/20181108/model/user" nsPrefix="com.specmate.model"> diff --git a/bundles/specmate-model-ecore/model/user.history b/bundles/specmate-model-ecore/model/user.history index f71792978..0e1d1df4b 100644 --- a/bundles/specmate-model-ecore/model/user.history +++ b/bundles/specmate-model-ecore/model/user.history @@ -312,5 +312,10 @@ - + + + + + + diff --git a/bundles/specmate-model-gen/build.properties b/bundles/specmate-model-gen/build.properties index fb7b5b415..612d368cd 100644 --- a/bundles/specmate-model-gen/build.properties +++ b/bundles/specmate-model-gen/build.properties @@ -2,7 +2,6 @@ bin.includes = specmate-model-gen.jar,\ model/,\ - icons/,\ plugin.xml,\ plugin.properties jars.compile.order = specmate-model-gen.jar diff --git a/bundles/specmate-model-gen/src/com/specmate/model/administration/AdministrationPackage.java b/bundles/specmate-model-gen/src/com/specmate/model/administration/AdministrationPackage.java index 4154f9450..f9eaa2356 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/administration/AdministrationPackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/administration/AdministrationPackage.java @@ -37,7 +37,7 @@ public interface AdministrationPackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/administration"; + String eNS_URI = "http://specmate.com/20181108/model/administration"; /** * The package namespace name. diff --git a/bundles/specmate-model-gen/src/com/specmate/model/base/BasePackage.java b/bundles/specmate-model-gen/src/com/specmate/model/base/BasePackage.java index 53b22a066..413f679a1 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/base/BasePackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/base/BasePackage.java @@ -38,7 +38,7 @@ public interface BasePackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/base"; + String eNS_URI = "http://specmate.com/20181108/model/base"; /** * The package namespace name. diff --git a/bundles/specmate-model-gen/src/com/specmate/model/batch/BatchPackage.java b/bundles/specmate-model-gen/src/com/specmate/model/batch/BatchPackage.java index 6478527c5..89f089447 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/batch/BatchPackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/batch/BatchPackage.java @@ -39,7 +39,7 @@ public interface BatchPackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/batch"; + String eNS_URI = "http://specmate.com/20181108/model/batch"; /** * The package namespace name. diff --git a/bundles/specmate-model-gen/src/com/specmate/model/history/HistoryPackage.java b/bundles/specmate-model-gen/src/com/specmate/model/history/HistoryPackage.java index 933c80912..b61cf55ae 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/history/HistoryPackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/history/HistoryPackage.java @@ -38,7 +38,7 @@ public interface HistoryPackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/history"; + String eNS_URI = "http://specmate.com/20181108/model/history"; /** * The package namespace name. diff --git a/bundles/specmate-model-gen/src/com/specmate/model/processes/ProcessesPackage.java b/bundles/specmate-model-gen/src/com/specmate/model/processes/ProcessesPackage.java index e381675b2..a9689e3ec 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/processes/ProcessesPackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/processes/ProcessesPackage.java @@ -39,7 +39,7 @@ public interface ProcessesPackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/processes"; + String eNS_URI = "http://specmate.com/20181108/model/processes"; /** * The package namespace name. diff --git a/bundles/specmate-model-gen/src/com/specmate/model/requirements/RequirementsPackage.java b/bundles/specmate-model-gen/src/com/specmate/model/requirements/RequirementsPackage.java index 402548068..35943bbae 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/requirements/RequirementsPackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/requirements/RequirementsPackage.java @@ -40,7 +40,7 @@ public interface RequirementsPackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/requirements"; + String eNS_URI = "http://specmate.com/20181108/model/requirements"; /** * The package namespace name. diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestSpecificationSkeleton.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestSpecificationSkeleton.java new file mode 100644 index 000000000..a9906f988 --- /dev/null +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestSpecificationSkeleton.java @@ -0,0 +1,78 @@ +/** + */ +package com.specmate.model.testspecification; + +import com.specmate.model.base.INamed; + +/** + * + * A representation of the model object 'Test Specification Skeleton'. + * + * + *

+ * The following features are supported: + *

+ *
    + *
  • {@link com.specmate.model.testspecification.TestSpecificationSkeleton#getLanguage Language}
  • + *
  • {@link com.specmate.model.testspecification.TestSpecificationSkeleton#getCode Code}
  • + *
+ * + * @see com.specmate.model.testspecification.TestspecificationPackage#getTestSpecificationSkeleton() + * @model + * @generated + */ +public interface TestSpecificationSkeleton extends INamed { + /** + * Returns the value of the 'Language' attribute. + * The default value is "". + * + *

+ * If the meaning of the 'Language' attribute isn't clear, + * there really should be more of a description here... + *

+ * + * @return the value of the 'Language' attribute. + * @see #setLanguage(String) + * @see com.specmate.model.testspecification.TestspecificationPackage#getTestSpecificationSkeleton_Language() + * @model default="" + * @generated + */ + String getLanguage(); + + /** + * Sets the value of the '{@link com.specmate.model.testspecification.TestSpecificationSkeleton#getLanguage Language}' attribute. + * + * + * @param value the new value of the 'Language' attribute. + * @see #getLanguage() + * @generated + */ + void setLanguage(String value); + + /** + * Returns the value of the 'Code' attribute. + * + *

+ * If the meaning of the 'Code' attribute isn't clear, + * there really should be more of a description here... + *

+ * + * @return the value of the 'Code' attribute. + * @see #setCode(String) + * @see com.specmate.model.testspecification.TestspecificationPackage#getTestSpecificationSkeleton_Code() + * @model + * @generated + */ + String getCode(); + + /** + * Sets the value of the '{@link com.specmate.model.testspecification.TestSpecificationSkeleton#getCode Code}' attribute. + * + * + * @param value the new value of the 'Code' attribute. + * @see #getCode() + * @generated + */ + void setCode(String value); + +} // TestSpecificationSkeleton diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationFactory.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationFactory.java index c83e1d005..8c5b3ca59 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationFactory.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationFactory.java @@ -30,6 +30,15 @@ public interface TestspecificationFactory extends EFactory { */ TestSpecification createTestSpecification(); + /** + * Returns a new object of class 'Test Specification Skeleton'. + * + * + * @return a new object of class 'Test Specification Skeleton'. + * @generated + */ + TestSpecificationSkeleton createTestSpecificationSkeleton(); + /** * Returns a new object of class 'Test Parameter'. * diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationPackage.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationPackage.java index 95dcfc041..b5cc56a57 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationPackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/TestspecificationPackage.java @@ -41,7 +41,7 @@ public interface TestspecificationPackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/testspecification"; + String eNS_URI = "http://specmate.com/20181108/model/testspecification"; /** * The package namespace name. @@ -123,6 +123,61 @@ public interface TestspecificationPackage extends EPackage { */ int TEST_SPECIFICATION_OPERATION_COUNT = BasePackage.ICONTAINER_OPERATION_COUNT + 0; + /** + * The meta object id for the '{@link com.specmate.model.testspecification.impl.TestSpecificationSkeletonImpl Test Specification Skeleton}' class. + * + * + * @see com.specmate.model.testspecification.impl.TestSpecificationSkeletonImpl + * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getTestSpecificationSkeleton() + * @generated + */ + int TEST_SPECIFICATION_SKELETON = 1; + + /** + * The feature id for the 'Name' attribute. + * + * + * @generated + * @ordered + */ + int TEST_SPECIFICATION_SKELETON__NAME = BasePackage.INAMED__NAME; + + /** + * The feature id for the 'Language' attribute. + * + * + * @generated + * @ordered + */ + int TEST_SPECIFICATION_SKELETON__LANGUAGE = BasePackage.INAMED_FEATURE_COUNT + 0; + + /** + * The feature id for the 'Code' attribute. + * + * + * @generated + * @ordered + */ + int TEST_SPECIFICATION_SKELETON__CODE = BasePackage.INAMED_FEATURE_COUNT + 1; + + /** + * The number of structural features of the 'Test Specification Skeleton' class. + * + * + * @generated + * @ordered + */ + int TEST_SPECIFICATION_SKELETON_FEATURE_COUNT = BasePackage.INAMED_FEATURE_COUNT + 2; + + /** + * The number of operations of the 'Test Specification Skeleton' class. + * + * + * @generated + * @ordered + */ + int TEST_SPECIFICATION_SKELETON_OPERATION_COUNT = BasePackage.INAMED_OPERATION_COUNT + 0; + /** * The meta object id for the '{@link com.specmate.model.testspecification.impl.TestParameterImpl Test Parameter}' class. * @@ -131,7 +186,7 @@ public interface TestspecificationPackage extends EPackage { * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getTestParameter() * @generated */ - int TEST_PARAMETER = 1; + int TEST_PARAMETER = 2; /** * The feature id for the 'Id' attribute. @@ -204,7 +259,7 @@ public interface TestspecificationPackage extends EPackage { * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getTestCase() * @generated */ - int TEST_CASE = 2; + int TEST_CASE = 3; /** * The feature id for the 'Id' attribute. @@ -286,7 +341,7 @@ public interface TestspecificationPackage extends EPackage { * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getParameterAssignment() * @generated */ - int PARAMETER_ASSIGNMENT = 3; + int PARAMETER_ASSIGNMENT = 4; /** * The feature id for the 'Id' attribute. @@ -368,7 +423,7 @@ public interface TestspecificationPackage extends EPackage { * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getTestProcedure() * @generated */ - int TEST_PROCEDURE = 4; + int TEST_PROCEDURE = 5; /** * The feature id for the 'Id' attribute. @@ -477,7 +532,7 @@ public interface TestspecificationPackage extends EPackage { * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getTestStep() * @generated */ - int TEST_STEP = 5; + int TEST_STEP = 6; /** * The feature id for the 'Id' attribute. @@ -559,7 +614,7 @@ public interface TestspecificationPackage extends EPackage { * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getParameterType() * @generated */ - int PARAMETER_TYPE = 6; + int PARAMETER_TYPE = 7; /** @@ -572,6 +627,38 @@ public interface TestspecificationPackage extends EPackage { */ EClass getTestSpecification(); + /** + * Returns the meta object for class '{@link com.specmate.model.testspecification.TestSpecificationSkeleton Test Specification Skeleton}'. + * + * + * @return the meta object for class 'Test Specification Skeleton'. + * @see com.specmate.model.testspecification.TestSpecificationSkeleton + * @generated + */ + EClass getTestSpecificationSkeleton(); + + /** + * Returns the meta object for the attribute '{@link com.specmate.model.testspecification.TestSpecificationSkeleton#getLanguage Language}'. + * + * + * @return the meta object for the attribute 'Language'. + * @see com.specmate.model.testspecification.TestSpecificationSkeleton#getLanguage() + * @see #getTestSpecificationSkeleton() + * @generated + */ + EAttribute getTestSpecificationSkeleton_Language(); + + /** + * Returns the meta object for the attribute '{@link com.specmate.model.testspecification.TestSpecificationSkeleton#getCode Code}'. + * + * + * @return the meta object for the attribute 'Code'. + * @see com.specmate.model.testspecification.TestSpecificationSkeleton#getCode() + * @see #getTestSpecificationSkeleton() + * @generated + */ + EAttribute getTestSpecificationSkeleton_Code(); + /** * Returns the meta object for class '{@link com.specmate.model.testspecification.TestParameter Test Parameter}'. * @@ -764,6 +851,32 @@ interface Literals { */ EClass TEST_SPECIFICATION = eINSTANCE.getTestSpecification(); + /** + * The meta object literal for the '{@link com.specmate.model.testspecification.impl.TestSpecificationSkeletonImpl Test Specification Skeleton}' class. + * + * + * @see com.specmate.model.testspecification.impl.TestSpecificationSkeletonImpl + * @see com.specmate.model.testspecification.impl.TestspecificationPackageImpl#getTestSpecificationSkeleton() + * @generated + */ + EClass TEST_SPECIFICATION_SKELETON = eINSTANCE.getTestSpecificationSkeleton(); + + /** + * The meta object literal for the 'Language' attribute feature. + * + * + * @generated + */ + EAttribute TEST_SPECIFICATION_SKELETON__LANGUAGE = eINSTANCE.getTestSpecificationSkeleton_Language(); + + /** + * The meta object literal for the 'Code' attribute feature. + * + * + * @generated + */ + EAttribute TEST_SPECIFICATION_SKELETON__CODE = eINSTANCE.getTestSpecificationSkeleton_Code(); + /** * The meta object literal for the '{@link com.specmate.model.testspecification.impl.TestParameterImpl Test Parameter}' class. * diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestSpecificationSkeletonImpl.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestSpecificationSkeletonImpl.java new file mode 100644 index 000000000..81a17295e --- /dev/null +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestSpecificationSkeletonImpl.java @@ -0,0 +1,221 @@ +/** + */ +package com.specmate.model.testspecification.impl; + +import com.specmate.model.base.BasePackage; + +import com.specmate.model.testspecification.TestSpecificationSkeleton; +import com.specmate.model.testspecification.TestspecificationPackage; + +import org.eclipse.emf.ecore.EClass; + +import org.eclipse.emf.internal.cdo.CDOObjectImpl; + +/** + * + * An implementation of the model object 'Test Specification Skeleton'. + * + *

+ * The following features are implemented: + *

+ *
    + *
  • {@link com.specmate.model.testspecification.impl.TestSpecificationSkeletonImpl#getName Name}
  • + *
  • {@link com.specmate.model.testspecification.impl.TestSpecificationSkeletonImpl#getLanguage Language}
  • + *
  • {@link com.specmate.model.testspecification.impl.TestSpecificationSkeletonImpl#getCode Code}
  • + *
+ * + * @generated + */ +public class TestSpecificationSkeletonImpl extends CDOObjectImpl implements TestSpecificationSkeleton { + /** + * The default value of the '{@link #getName() Name}' attribute. + * + * + * @see #getName() + * @generated + * @ordered + */ + protected static final String NAME_EDEFAULT = null; + + /** + * The default value of the '{@link #getLanguage() Language}' attribute. + * + * + * @see #getLanguage() + * @generated + * @ordered + */ + protected static final String LANGUAGE_EDEFAULT = ""; + + /** + * The default value of the '{@link #getCode() Code}' attribute. + * + * + * @see #getCode() + * @generated + * @ordered + */ + protected static final String CODE_EDEFAULT = null; + + /** + * + * + * @generated + */ + protected TestSpecificationSkeletonImpl() { + super(); + } + + /** + * + * + * @generated + */ + @Override + protected EClass eStaticClass() { + return TestspecificationPackage.Literals.TEST_SPECIFICATION_SKELETON; + } + + /** + * + * + * @generated + */ + @Override + protected int eStaticFeatureCount() { + return 0; + } + + /** + * + * + * @generated + */ + public String getName() { + return (String)eDynamicGet(TestspecificationPackage.TEST_SPECIFICATION_SKELETON__NAME, BasePackage.Literals.INAMED__NAME, true, true); + } + + /** + * + * + * @generated + */ + public void setName(String newName) { + eDynamicSet(TestspecificationPackage.TEST_SPECIFICATION_SKELETON__NAME, BasePackage.Literals.INAMED__NAME, newName); + } + + /** + * + * + * @generated + */ + public String getLanguage() { + return (String)eDynamicGet(TestspecificationPackage.TEST_SPECIFICATION_SKELETON__LANGUAGE, TestspecificationPackage.Literals.TEST_SPECIFICATION_SKELETON__LANGUAGE, true, true); + } + + /** + * + * + * @generated + */ + public void setLanguage(String newLanguage) { + eDynamicSet(TestspecificationPackage.TEST_SPECIFICATION_SKELETON__LANGUAGE, TestspecificationPackage.Literals.TEST_SPECIFICATION_SKELETON__LANGUAGE, newLanguage); + } + + /** + * + * + * @generated + */ + public String getCode() { + return (String)eDynamicGet(TestspecificationPackage.TEST_SPECIFICATION_SKELETON__CODE, TestspecificationPackage.Literals.TEST_SPECIFICATION_SKELETON__CODE, true, true); + } + + /** + * + * + * @generated + */ + public void setCode(String newCode) { + eDynamicSet(TestspecificationPackage.TEST_SPECIFICATION_SKELETON__CODE, TestspecificationPackage.Literals.TEST_SPECIFICATION_SKELETON__CODE, newCode); + } + + /** + * + * + * @generated + */ + @Override + public Object eGet(int featureID, boolean resolve, boolean coreType) { + switch (featureID) { + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__NAME: + return getName(); + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__LANGUAGE: + return getLanguage(); + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__CODE: + return getCode(); + } + return super.eGet(featureID, resolve, coreType); + } + + /** + * + * + * @generated + */ + @Override + public void eSet(int featureID, Object newValue) { + switch (featureID) { + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__NAME: + setName((String)newValue); + return; + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__LANGUAGE: + setLanguage((String)newValue); + return; + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__CODE: + setCode((String)newValue); + return; + } + super.eSet(featureID, newValue); + } + + /** + * + * + * @generated + */ + @Override + public void eUnset(int featureID) { + switch (featureID) { + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__NAME: + setName(NAME_EDEFAULT); + return; + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__LANGUAGE: + setLanguage(LANGUAGE_EDEFAULT); + return; + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__CODE: + setCode(CODE_EDEFAULT); + return; + } + super.eUnset(featureID); + } + + /** + * + * + * @generated + */ + @Override + public boolean eIsSet(int featureID) { + switch (featureID) { + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__NAME: + return NAME_EDEFAULT == null ? getName() != null : !NAME_EDEFAULT.equals(getName()); + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__LANGUAGE: + return LANGUAGE_EDEFAULT == null ? getLanguage() != null : !LANGUAGE_EDEFAULT.equals(getLanguage()); + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON__CODE: + return CODE_EDEFAULT == null ? getCode() != null : !CODE_EDEFAULT.equals(getCode()); + } + return super.eIsSet(featureID); + } + +} //TestSpecificationSkeletonImpl diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationFactoryImpl.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationFactoryImpl.java index 10e527740..99229012c 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationFactoryImpl.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationFactoryImpl.java @@ -58,6 +58,7 @@ public TestspecificationFactoryImpl() { public EObject create(EClass eClass) { switch (eClass.getClassifierID()) { case TestspecificationPackage.TEST_SPECIFICATION: return (EObject)createTestSpecification(); + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON: return (EObject)createTestSpecificationSkeleton(); case TestspecificationPackage.TEST_PARAMETER: return (EObject)createTestParameter(); case TestspecificationPackage.TEST_CASE: return (EObject)createTestCase(); case TestspecificationPackage.PARAMETER_ASSIGNMENT: return (EObject)createParameterAssignment(); @@ -108,6 +109,16 @@ public TestSpecification createTestSpecification() { return testSpecification; } + /** + * + * + * @generated + */ + public TestSpecificationSkeleton createTestSpecificationSkeleton() { + TestSpecificationSkeletonImpl testSpecificationSkeleton = new TestSpecificationSkeletonImpl(); + return testSpecificationSkeleton; + } + /** * * diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationPackageImpl.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationPackageImpl.java index 763abcaee..c91dd8e4d 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationPackageImpl.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/impl/TestspecificationPackageImpl.java @@ -30,6 +30,7 @@ import com.specmate.model.testspecification.TestParameter; import com.specmate.model.testspecification.TestProcedure; import com.specmate.model.testspecification.TestSpecification; +import com.specmate.model.testspecification.TestSpecificationSkeleton; import com.specmate.model.testspecification.TestStep; import com.specmate.model.testspecification.TestspecificationFactory; import com.specmate.model.testspecification.TestspecificationPackage; @@ -56,6 +57,13 @@ public class TestspecificationPackageImpl extends EPackageImpl implements Testsp */ private EClass testSpecificationEClass = null; + /** + * + * + * @generated + */ + private EClass testSpecificationSkeletonEClass = null; + /** * * @@ -188,6 +196,33 @@ public EClass getTestSpecification() { return testSpecificationEClass; } + /** + * + * + * @generated + */ + public EClass getTestSpecificationSkeleton() { + return testSpecificationSkeletonEClass; + } + + /** + * + * + * @generated + */ + public EAttribute getTestSpecificationSkeleton_Language() { + return (EAttribute)testSpecificationSkeletonEClass.getEStructuralFeatures().get(0); + } + + /** + * + * + * @generated + */ + public EAttribute getTestSpecificationSkeleton_Code() { + return (EAttribute)testSpecificationSkeletonEClass.getEStructuralFeatures().get(1); + } + /** * * @@ -353,6 +388,10 @@ public void createPackageContents() { // Create classes and their features testSpecificationEClass = createEClass(TEST_SPECIFICATION); + testSpecificationSkeletonEClass = createEClass(TEST_SPECIFICATION_SKELETON); + createEAttribute(testSpecificationSkeletonEClass, TEST_SPECIFICATION_SKELETON__LANGUAGE); + createEAttribute(testSpecificationSkeletonEClass, TEST_SPECIFICATION_SKELETON__CODE); + testParameterEClass = createEClass(TEST_PARAMETER); createEAttribute(testParameterEClass, TEST_PARAMETER__TYPE); createEReference(testParameterEClass, TEST_PARAMETER__ASSIGNMENTS); @@ -408,6 +447,7 @@ public void initializePackageContents() { // Add supertypes to classes testSpecificationEClass.getESuperTypes().add(theBasePackage.getIContainer()); + testSpecificationSkeletonEClass.getESuperTypes().add(theBasePackage.getINamed()); testParameterEClass.getESuperTypes().add(theBasePackage.getIContentElement()); testCaseEClass.getESuperTypes().add(theBasePackage.getIContainer()); testCaseEClass.getESuperTypes().add(theBasePackage.getIPositionable()); @@ -420,6 +460,10 @@ public void initializePackageContents() { // Initialize classes, features, and operations; add parameters initEClass(testSpecificationEClass, TestSpecification.class, "TestSpecification", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); + initEClass(testSpecificationSkeletonEClass, TestSpecificationSkeleton.class, "TestSpecificationSkeleton", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); + initEAttribute(getTestSpecificationSkeleton_Language(), ecorePackage.getEString(), "language", "", 0, 1, TestSpecificationSkeleton.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + initEAttribute(getTestSpecificationSkeleton_Code(), ecorePackage.getEString(), "code", null, 0, 1, TestSpecificationSkeleton.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); + initEClass(testParameterEClass, TestParameter.class, "TestParameter", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); initEAttribute(getTestParameter_Type(), this.getParameterType(), "type", null, 0, 1, TestParameter.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); initEReference(getTestParameter_Assignments(), this.getParameterAssignment(), this.getParameterAssignment_Parameter(), "assignments", null, 0, -1, TestParameter.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationAdapterFactory.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationAdapterFactory.java index 406fe38e6..90def0c53 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationAdapterFactory.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationAdapterFactory.java @@ -80,6 +80,10 @@ public Adapter caseTestSpecification(TestSpecification object) { return createTestSpecificationAdapter(); } @Override + public Adapter caseTestSpecificationSkeleton(TestSpecificationSkeleton object) { + return createTestSpecificationSkeletonAdapter(); + } + @Override public Adapter caseTestParameter(TestParameter object) { return createTestParameterAdapter(); } @@ -161,6 +165,20 @@ public Adapter createTestSpecificationAdapter() { return null; } + /** + * Creates a new adapter for an object of class '{@link com.specmate.model.testspecification.TestSpecificationSkeleton Test Specification Skeleton}'. + * + * This default implementation returns null so that we can easily ignore cases; + * it's useful to ignore a case when inheritance will catch all the cases anyway. + * + * @return the new adapter. + * @see com.specmate.model.testspecification.TestSpecificationSkeleton + * @generated + */ + public Adapter createTestSpecificationSkeletonAdapter() { + return null; + } + /** * Creates a new adapter for an object of class '{@link com.specmate.model.testspecification.TestParameter Test Parameter}'. * diff --git a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationSwitch.java b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationSwitch.java index 413a993ef..a8dd38e48 100644 --- a/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationSwitch.java +++ b/bundles/specmate-model-gen/src/com/specmate/model/testspecification/util/TestspecificationSwitch.java @@ -85,6 +85,13 @@ protected T doSwitch(int classifierID, EObject theEObject) { if (result == null) result = defaultCase(theEObject); return result; } + case TestspecificationPackage.TEST_SPECIFICATION_SKELETON: { + TestSpecificationSkeleton testSpecificationSkeleton = (TestSpecificationSkeleton)theEObject; + T result = caseTestSpecificationSkeleton(testSpecificationSkeleton); + if (result == null) result = caseINamed(testSpecificationSkeleton); + if (result == null) result = defaultCase(theEObject); + return result; + } case TestspecificationPackage.TEST_PARAMETER: { TestParameter testParameter = (TestParameter)theEObject; T result = caseTestParameter(testParameter); @@ -159,6 +166,21 @@ public T caseTestSpecification(TestSpecification object) { return null; } + /** + * Returns the result of interpreting the object as an instance of 'Test Specification Skeleton'. + * + * This implementation returns null; + * returning a non-null result will terminate the switch. + * + * @param object the target of the switch. + * @return the result of interpreting the object as an instance of 'Test Specification Skeleton'. + * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject) + * @generated + */ + public T caseTestSpecificationSkeleton(TestSpecificationSkeleton object) { + return null; + } + /** * Returns the result of interpreting the object as an instance of 'Test Parameter'. * diff --git a/bundles/specmate-model-gen/src/com/specmate/usermodel/UsermodelPackage.java b/bundles/specmate-model-gen/src/com/specmate/usermodel/UsermodelPackage.java index 111d08945..1f82fed2e 100644 --- a/bundles/specmate-model-gen/src/com/specmate/usermodel/UsermodelPackage.java +++ b/bundles/specmate-model-gen/src/com/specmate/usermodel/UsermodelPackage.java @@ -38,7 +38,7 @@ public interface UsermodelPackage extends EPackage { * * @generated */ - String eNS_URI = "http://specmate.com/20180925/model/user"; + String eNS_URI = "http://specmate.com/20181108/model/user"; /** * The package namespace name. diff --git a/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/GenerateAngular.java b/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/GenerateAngular.java index 89ddd1948..189d87109 100644 --- a/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/GenerateAngular.java +++ b/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/GenerateAngular.java @@ -396,14 +396,20 @@ public void registerResourceFactories(ResourceSet resourceSet) { /* * TODO If you need additional resource factories registrations, you can register them here. the following line - * (in comment) is an example of the resource factory registration for UML. + * (in comment) is an example of the resource factory registration. * * If you want to use the generator in stand alone, the resource factory registration will be required. * * To learn more about the registration of Resource Factories, have a look at the Acceleo documentation (Help -> Help Contents). */ - // resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(UMLResource.FILE_EXTENSION, UMLResource.Factory.INSTANCE); + // resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(XyzResource.FILE_EXTENSION, XyzResource.Factory.INSTANCE); + + /* + * Some metamodels require a very complex setup for standalone usage. For example, if you want to use a generator + * targetting UML models in standalone, you NEED to use the following: + */ + // UMLResourcesUtil.init(resourceSet) } } diff --git a/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/generateAngular.mtl b/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/generateAngular.mtl index a904a50eb..60c185737 100644 --- a/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/generateAngular.mtl +++ b/bundles/specmate-model-generators-typescript/src/com/specmate/model/generators/typescript/generateAngular.mtl @@ -28,7 +28,7 @@ // Attributes [for (a: EAttribute | aClass.eAllAttributes)] - [if not (aClass.interface)]public[/if] [a.name/]: [a.eType.name/]; + [if not (aClass.interface)]public[/if] [a.name/]: [a.eType.name/][if (a.many)]['['/][']'/][/if]; [/for] // References diff --git a/bundles/specmate-model-support/bnd.bnd b/bundles/specmate-model-support/bnd.bnd index 3dfc58a0e..5222c7266 100644 --- a/bundles/specmate-model-support/bnd.bnd +++ b/bundles/specmate-model-support/bnd.bnd @@ -1,7 +1,6 @@ Bundle-Version: 0.0.0.${tstamp} Export-Package: \ com.specmate.model.support.util,\ - com.specmate.model.support.commands,\ com.specmate.urihandler -buildpath: \ org.eclipse.emf.common,\ @@ -13,7 +12,8 @@ Export-Package: \ org.eclipse.osgi.services,\ org.eclipse.emf.cdo.common,\ org.eclipse.net4j.util,\ - org.apache.commons.lang3 + org.apache.commons.lang3,\ + specmate-config-api;version=latest -dsannotations: \ * -Private-Package: com.specmate.model.support.internal \ No newline at end of file +Private-Package: com.specmate.model.support.internal \ No newline at end of file diff --git a/bundles/specmate-model-support/src/com/specmate/model/support/util/SpecmateEcoreUtil.java b/bundles/specmate-model-support/src/com/specmate/model/support/util/SpecmateEcoreUtil.java index 57fff39d7..24910d35a 100644 --- a/bundles/specmate-model-support/src/com/specmate/model/support/util/SpecmateEcoreUtil.java +++ b/bundles/specmate-model-support/src/com/specmate/model/support/util/SpecmateEcoreUtil.java @@ -7,9 +7,9 @@ import java.util.List; import org.eclipse.emf.cdo.CDOObject; +import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; -import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; @@ -20,6 +20,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil; import com.specmate.common.AssertUtil; +import com.specmate.common.SpecmateException; import com.specmate.model.base.Folder; import com.specmate.model.base.IContainer; import com.specmate.model.base.IContentElement; @@ -76,8 +77,9 @@ public static T getObjectByUriFragment(Resource resource, String id, Class List getRootObjectsByType(Resource resource, Class clazz) { @@ -184,17 +186,17 @@ public static T getFirstAncestorOfType(EObject object, Class clazz) { } return null; } - + public static String getUniqueId(EObject object) { String id; - if(object instanceof CDOObject) { - CDOObject cdoObject = (CDOObject)object; + if (object instanceof CDOObject) { + CDOObject cdoObject = (CDOObject) object; return buildStringId(cdoObject.cdoID()); } else { return null; } } - + public static String buildStringId(CDOID id) { StringBuilder builder = new StringBuilder(); CDOIDUtil.write(builder, id); @@ -221,7 +223,7 @@ public static T getLastAncestorOfType(EObject object, Class clazz) { public static String getProjectId(EObject target) { Folder projectFolder = getLastAncestorOfType(target, Folder.class); - if (projectFolder != null && projectFolder.cdoState()!=CDOState.TRANSIENT) { + if (projectFolder != null && projectFolder.cdoState() != CDOState.TRANSIENT) { return projectFolder.getId(); } else { return null; @@ -233,6 +235,16 @@ public static boolean isProject(EObject target) { return target == projectFolder; } + public static List getChildren(Object target) throws SpecmateException { + if (target instanceof Resource) { + return ((Resource) target).getContents(); + } else if (target instanceof EObject) { + return ((EObject) target).eContents(); + } else { + throw new SpecmateException("Object is no resource and no EObject"); + } + } + } @SuppressWarnings("serial") diff --git a/bundles/specmate-persistency-api/src/com/specmate/persistency/IChange.java b/bundles/specmate-persistency-api/src/com/specmate/persistency/IChange.java index 649f72d22..4b840e9ab 100644 --- a/bundles/specmate-persistency-api/src/com/specmate/persistency/IChange.java +++ b/bundles/specmate-persistency-api/src/com/specmate/persistency/IChange.java @@ -1,8 +1,7 @@ package com.specmate.persistency; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; public interface IChange { - public T doChange() throws SpecmateException, SpecmateValidationException; + public T doChange() throws SpecmateException; } diff --git a/bundles/specmate-persistency-api/src/com/specmate/persistency/IChangeListener.java b/bundles/specmate-persistency-api/src/com/specmate/persistency/IChangeListener.java index af9b72362..37f299465 100644 --- a/bundles/specmate-persistency-api/src/com/specmate/persistency/IChangeListener.java +++ b/bundles/specmate-persistency-api/src/com/specmate/persistency/IChangeListener.java @@ -5,15 +5,17 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; +import com.specmate.common.SpecmateValidationException; import com.specmate.persistency.event.EChangeKind; public interface IChangeListener { void changedObject(EObject object, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, - Object newValue, String objectClassName); + Object newValue, String objectClassName) throws SpecmateValidationException; - void removedObject(EObject object); + void removedObject(EObject object) throws SpecmateValidationException; - void newObject(String id, String className, Map featureMap); + void newObject(EObject object, String id, String className, Map featureMap) + throws SpecmateValidationException; } diff --git a/bundles/specmate-persistency-api/src/com/specmate/persistency/IPersistencyService.java b/bundles/specmate-persistency-api/src/com/specmate/persistency/IPersistencyService.java index 40ebd8ad5..f782ffc5f 100644 --- a/bundles/specmate-persistency-api/src/com/specmate/persistency/IPersistencyService.java +++ b/bundles/specmate-persistency-api/src/com/specmate/persistency/IPersistencyService.java @@ -6,7 +6,7 @@ public interface IPersistencyService { /** - * Opens a model transaction. + * Opens a model transaction with default validators. * * @throws SpecmateException */ @@ -34,5 +34,4 @@ public interface IPersistencyService { public void shutdown(); public void start() throws SpecmateException; - } diff --git a/bundles/specmate-persistency-api/src/com/specmate/persistency/ITransaction.java b/bundles/specmate-persistency-api/src/com/specmate/persistency/ITransaction.java index 208b73ddb..ec887f43b 100644 --- a/bundles/specmate-persistency-api/src/com/specmate/persistency/ITransaction.java +++ b/bundles/specmate-persistency-api/src/com/specmate/persistency/ITransaction.java @@ -17,7 +17,6 @@ public interface ITransaction extends IView { * Example with the following records (username;deleted objects;comment): * michael;Model1|CEGModel,Library Folder|Folder;deleted empty models */ - public static final String COMMENT_FIELD_SEPARATOR = ","; public static final String COMMENT_DATA_SEPARATOR = "|"; public static final String COMMENT_RECORD_SEPARATOR = ";"; @@ -35,7 +34,7 @@ public interface ITransaction extends IView { /** * Perform a change and commit * - * @throws SpecmateValidationException + * @throws SpecmateException */ T doAndCommit(IChange change) throws SpecmateException, SpecmateValidationException; @@ -43,4 +42,10 @@ public interface ITransaction extends IView { * Signals if the transaction is currently active */ public boolean isActive(); + + public void addValidator(IChangeListener v); + + public void resetValidarors(); + + public void enableValidators(boolean enable); } diff --git a/bundles/specmate-persistency-cdo/bnd.bnd b/bundles/specmate-persistency-cdo/bnd.bnd index 582c88fa1..607803570 100644 --- a/bundles/specmate-persistency-cdo/bnd.bnd +++ b/bundles/specmate-persistency-cdo/bnd.bnd @@ -37,5 +37,6 @@ Bundle-Version: 0.0.0.${tstamp} Private-Package: com.specmate.persistency.cdo.internal Export-Package: \ com.specmate.persistency.cdo,\ - com.specmate.persistency.cdo.internal + com.specmate.persistency.cdo.internal,\ + com.specmate.persistency.validation -resolve: auto \ No newline at end of file diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/CDOPersistencyService.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/CDOPersistencyService.java index 817aa9c3c..8bd84f80c 100644 --- a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/CDOPersistencyService.java +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/CDOPersistencyService.java @@ -291,7 +291,7 @@ public ITransaction openTransaction(boolean attachCommitListeners) throws Specma return openTransaction(attachCommitListeners, this.resourceName); } - public ITransaction openTransaction(boolean attachCommitListeners, String alterantiveResourceName) + private ITransaction openTransaction(boolean attachCommitListeners, String alterantiveResourceName) throws SpecmateException { if (!this.active) { throw new SpecmateException("Attempt to open transaction when persistency service is not active"); @@ -299,8 +299,10 @@ public ITransaction openTransaction(boolean attachCommitListeners, String altera CDOTransaction cdoTransaction = openCDOTransaction(); TransactionImpl transaction = new TransactionImpl(this, cdoTransaction, alterantiveResourceName, logService, statusService, attachCommitListeners ? listeners : Collections.emptyList()); + this.openTransactions.add(transaction); this.transactionGauge.inc(); + return transaction; } @@ -356,22 +358,28 @@ public void notifyEvent(IEvent event) { DeltaProcessor processor = new DeltaProcessor(invalEvent) { @Override - protected void newObject(CDOID id, String className, Map featureMap) { + protected void newObject(CDOID id, String className, Map featureMap) + throws SpecmateValidationException { postEvent(view, id, className, 0, featureMap, EChangeKind.NEW, 0); } @Override - protected void detachedObject(CDOID id, int version) { + protected void detachedObject(CDOID id, int version) throws SpecmateValidationException { postEvent(view, id, null, version, null, EChangeKind.DELETE, 0); } @Override public void changedObject(CDOID id, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, - Object newValue, int index, String objectClassName) { + Object newValue, int index, String objectClassName) throws SpecmateValidationException { postEvent(view, id, objectClassName, 0, Collections.singletonMap(feature, newValue), changeKind, index); } }; - processor.process(); + + try { + processor.process(); + } catch (SpecmateValidationException e) { + logService.log(LogService.LOG_ERROR, e.getMessage()); + } } public boolean isActive() { diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/DeltaProcessor.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/DeltaProcessor.java index cab373d94..7ee13cee1 100644 --- a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/DeltaProcessor.java +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/DeltaProcessor.java @@ -19,6 +19,7 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.ecore.EStructuralFeature; +import com.specmate.common.SpecmateValidationException; import com.specmate.persistency.event.EChangeKind; public abstract class DeltaProcessor { @@ -30,7 +31,7 @@ public DeltaProcessor(CDOChangeSetData data) { this.data = data; } - public void process() { + public void process() throws SpecmateValidationException { for (CDOIDAndVersion key : data.getNewObjects()) { if (key instanceof InternalCDORevision) { InternalCDORevision revision = (InternalCDORevision) key; @@ -55,7 +56,8 @@ public void process() { } } - private void processDelta(CDOID id, CDOFeatureDelta delta, String objectClassName) { + private void processDelta(CDOID id, CDOFeatureDelta delta, String objectClassName) + throws SpecmateValidationException { if (delta.getType().equals(Type.LIST)) { CDOListFeatureDelta listDelta = (CDOListFeatureDelta) delta; ArrayList deltas = new ArrayList<>(listDelta.getListChanges()); @@ -68,7 +70,8 @@ private void processDelta(CDOID id, CDOFeatureDelta delta, String objectClassNam processBasicDelta(id, delta, objectClassName); } - private void processBasicDelta(CDOID id, CDOFeatureDelta delta, String objectClassName) { + private void processBasicDelta(CDOID id, CDOFeatureDelta delta, String objectClassName) + throws SpecmateValidationException { switch (delta.getType()) { case SET: CDOSetFeatureDelta setDelta = (CDOSetFeatureDelta) delta; @@ -95,10 +98,11 @@ private void processBasicDelta(CDOID id, CDOFeatureDelta delta, String objectCla } protected abstract void changedObject(CDOID id, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, - Object newValue, int index, String objectClassName); + Object newValue, int index, String objectClassName) throws SpecmateValidationException; - protected abstract void newObject(CDOID id, String className, Map featureMap); + protected abstract void newObject(CDOID id, String className, Map featureMap) + throws SpecmateValidationException; - protected abstract void detachedObject(CDOID id, int version); + protected abstract void detachedObject(CDOID id, int version) throws SpecmateValidationException; } diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/HistoryProviderImpl.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/HistoryProviderImpl.java index 689e93b63..6deabcd83 100644 --- a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/HistoryProviderImpl.java +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/cdo/internal/HistoryProviderImpl.java @@ -19,6 +19,7 @@ import org.osgi.service.log.LogService; import com.specmate.common.SpecmateException; +import com.specmate.common.SpecmateValidationException; import com.specmate.model.base.BasePackage; import com.specmate.model.base.INamed; import com.specmate.model.history.Change; @@ -33,7 +34,9 @@ @Component(immediate = true) public class HistoryProviderImpl implements IHistoryProvider { + private IPersistencyService persistency; + private LogService logService; @Override @@ -112,7 +115,11 @@ private History processHistory(CDOObject cdoObject, History history) { private void fillHistoryEntry(CDOObject cdoObject, CDOCommitInfo cdoHistoryElement, HistoryEntry historyEntry) { HistoryDeltaProcessor deltaProcessor = new HistoryDeltaProcessor(cdoHistoryElement, cdoObject.cdoID()); - deltaProcessor.process(); + try { + deltaProcessor.process(); + } catch (SpecmateValidationException e) { + logService.log(LogService.LOG_ERROR, e.getMessage()); + } historyEntry.getChanges().addAll(deltaProcessor.getChanges()); historyEntry.setTimestamp(cdoHistoryElement.getTimeStamp()); extractCommentInfo(cdoHistoryElement, historyEntry); @@ -177,7 +184,8 @@ public List getChanges() { @Override protected void changedObject(CDOID id, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, - Object newValue, int index, String objectClassName) { + Object newValue, int index, String objectClassName) throws SpecmateValidationException { + if (!id.equals(this.cdoId)) { return; } @@ -206,7 +214,8 @@ protected void changedObject(CDOID id, EStructuralFeature feature, EChangeKind c } @Override - protected void newObject(CDOID id, String className, Map featureMap) { + protected void newObject(CDOID id, String className, Map featureMap) + throws SpecmateValidationException { if (!id.equals(this.cdoId)) { return; } @@ -227,7 +236,7 @@ protected void newObject(CDOID id, String className, Map changeListeners; + + private List validators; + + private boolean validatorsEnabled; + private IStatusService statusService; public TransactionImpl(CDOPersistencyService persistency, CDOTransaction transaction, String resourceName, @@ -49,6 +59,12 @@ public TransactionImpl(CDOPersistencyService persistency, CDOTransaction transac this.statusService = statusService; this.changeListeners = listeners; + this.validators = new ArrayList<>(); + this.validators.add(new IDValidator()); + this.validators.add(new NameValidator()); + this.validators.add(new TextLengthValidator()); + this.validators.add(new ConnectionValidator()); + this.validatorsEnabled = true; } @Override @@ -60,7 +76,7 @@ public void close() { logService.log(LogService.LOG_DEBUG, "Transaction closed: " + transaction.getViewID()); } - private void commit(T object) throws SpecmateException { + private void commit(T object) throws SpecmateException, SpecmateValidationException { if (!isActive()) { throw new SpecmateException("Attempt to commit but transaction is not active"); } @@ -80,7 +96,12 @@ private void commit(T object) throws SpecmateException { } } catch (SpecmateException s) { transaction.rollback(); - throw (new SpecmateException("Error while preparing commit, transaction rolled back", s)); + logService.log(LogService.LOG_ERROR, "Error during commit, transaction rolled back"); + throw s; + } catch (SpecmateValidationException s) { + transaction.rollback(); + logService.log(LogService.LOG_ERROR, "Error during commit, transaction rolled back"); + throw s; } setMetadata(object, detachedObjects); transaction.commit(); @@ -116,7 +137,7 @@ public T doAndCommit(IChange change) throws SpecmateException, SpecmateVa success = true; } if (!success) { - throw new SpecmateException("Could not commit after " + maxAttempts + " attempts."); + throw new SpecmateException("Could not commit after " + attempts + " attempts."); } return result; } @@ -174,36 +195,58 @@ private String extractDeletedObjects(List detachedObjects) { return names.toString(); } - private void notifyListeners() throws SpecmateException { + private void notifyListeners() throws SpecmateException, SpecmateValidationException { CDOChangeSetData data = transaction.getChangeSetData(); DeltaProcessor processor = new DeltaProcessor(data) { @Override - protected void newObject(CDOID id, String className, Map featureMap) { + protected void newObject(CDOID id, String className, Map featureMap) + throws SpecmateValidationException { StringBuilder builder = new StringBuilder(); CDOIDUtil.write(builder, id); String idAsString = builder.toString(); for (IChangeListener listener : changeListeners) { - listener.newObject(idAsString, className, featureMap); + listener.newObject(transaction.getObject(id), idAsString, className, featureMap); + } + + if (validatorsEnabled) { + for (IChangeListener listener : validators) { + listener.newObject(transaction.getObject(id), idAsString, className, featureMap); + } } + } @Override - protected void detachedObject(CDOID id, int version) { + protected void detachedObject(CDOID id, int version) throws SpecmateValidationException { for (IChangeListener listener : changeListeners) { listener.removedObject(transaction.getObject(id)); } + + if (validatorsEnabled) { + for (IChangeListener listener : validators) { + listener.removedObject(transaction.getObject(id)); + } + } } @Override public void changedObject(CDOID id, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, - Object newValue, int index, String objectClassName) { + Object newValue, int index, String objectClassName) throws SpecmateValidationException { + if (newValue instanceof CDOID) { + newValue = transaction.getObject((CDOID) newValue); + } + + CDOObject obj = transaction.getObject(id); + for (IChangeListener listener : changeListeners) { - if (newValue instanceof CDOID) { - newValue = transaction.getObject((CDOID) newValue); + listener.changedObject(obj, feature, changeKind, oldValue, newValue, objectClassName); + } + + if (validatorsEnabled) { + for (IChangeListener listener : validators) { + listener.changedObject(obj, feature, changeKind, oldValue, newValue, objectClassName); } - listener.changedObject(transaction.getObject(id), feature, changeKind, oldValue, newValue, - objectClassName); } } @@ -213,10 +256,6 @@ public void changedObject(CDOID id, EStructuralFeature feature, EChangeKind chan } - public void addListener(IChangeListener listener) { - changeListeners.add(listener); - } - public CDOTransaction getInternalTransaction() { return transaction; } @@ -242,4 +281,19 @@ public void update(CDOTransaction transaction) { super.update(transaction); this.transaction = transaction; } + + @Override + public void addValidator(IChangeListener v) { + this.validators.add(v); + } + + @Override + public void resetValidarors() { + this.validators.clear(); + } + + @Override + public void enableValidators(boolean enable) { + this.validatorsEnabled = enable; + } } diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/ConnectionValidator.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/ConnectionValidator.java new file mode 100644 index 000000000..9e85f8449 --- /dev/null +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/ConnectionValidator.java @@ -0,0 +1,49 @@ +package com.specmate.persistency.validation; + +import java.util.Map; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; + +import com.specmate.common.SpecmateValidationException; +import com.specmate.model.base.IModelConnection; +import com.specmate.persistency.event.EChangeKind; + +public class ConnectionValidator extends ValidatorBase { + + @Override + public void changedObject(EObject object, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, + Object newValue, String objectClassName) throws SpecmateValidationException { + + checkSourceTarget(object); + } + + @Override + public void removedObject(EObject object) throws SpecmateValidationException { + // Nothing to check + } + + @Override + public void newObject(EObject object, String id, String className, Map featureMap) + throws SpecmateValidationException { + checkSourceTarget(object); + } + + private void checkSourceTarget(EObject object) throws SpecmateValidationException { + if (object instanceof IModelConnection) { + IModelConnection connection = (IModelConnection) object; + if (connection.getSource() == null) { + throw new SpecmateValidationException( + "Connection " + connection.getName() + " is not connected to a source.", getValidatorName(), + getObjectName(object)); + } + + if (connection.getTarget() == null) { + throw new SpecmateValidationException( + "Connection " + connection.getName() + " is not connected to a target.", getValidatorName(), + getObjectName(object)); + } + } + } + +} diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/IDValidator.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/IDValidator.java new file mode 100644 index 000000000..989c1c135 --- /dev/null +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/IDValidator.java @@ -0,0 +1,81 @@ +package com.specmate.persistency.validation; + +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; + +import com.specmate.common.SpecmateValidationException; +import com.specmate.model.base.BasePackage; +import com.specmate.model.support.util.SpecmateEcoreUtil; +import com.specmate.persistency.event.EChangeKind; + +public class IDValidator extends ValidatorBase { + /** Pattern that describes valid object ids */ + private static Pattern idPattern = Pattern.compile("[a-zA-Z_0-9\\-]+"); + + @Override + public void changedObject(EObject object, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, + Object newValue, String objectClassName) throws SpecmateValidationException { + + if (feature.getName().equals(BasePackage.Literals.IID__ID.getName())) { + String objectID = validateID(object, newValue); + validateUniqueID(objectID, object); + } + } + + @Override + public void removedObject(EObject object) throws SpecmateValidationException { + // No validation required + } + + @Override + public void newObject(EObject object, String id, String className, Map featureMap) + throws SpecmateValidationException { + + String objectID = validateID(object, featureMap.get(BasePackage.Literals.IID__ID)); + validateUniqueID(objectID, object); + } + + private String validateID(EObject obj, Object objID) throws SpecmateValidationException { + if (objID == null) { + throw new SpecmateValidationException("Object does not have a valid Id.", getValidatorName(), + getObjectName(obj)); + } + + String id = (String) objID; + if (!idPattern.matcher(id).matches()) { + throw new SpecmateValidationException("Object id may only contain letters, digits, '_' and '-'.", + getValidatorName(), getObjectName(obj)); + } + + return id; + } + + private void validateUniqueID(String id, EObject object) throws SpecmateValidationException { + List contents = null; + EObject parent = object.eContainer(); + if (parent != null) { + contents = parent.eContents(); + } else { + contents = object.eResource().getContents(); + } + + int hits = 0; + + for (EObject c : contents) { + String currentId = SpecmateEcoreUtil.getID(c); + if (currentId != null && currentId.equals(id)) { + hits++; + } + if (hits > 1) { + throw new SpecmateValidationException("Duplicate id: " + id + ".", getValidatorName(), + getObjectName(object)); + } + } + + } + +} diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/NameValidator.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/NameValidator.java new file mode 100644 index 000000000..766dc9af1 --- /dev/null +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/NameValidator.java @@ -0,0 +1,67 @@ +package com.specmate.persistency.validation; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; + +import com.specmate.common.SpecmateValidationException; +import com.specmate.model.base.BasePackage; +import com.specmate.model.base.INamed; +import com.specmate.persistency.IChangeListener; +import com.specmate.persistency.event.EChangeKind; + +public class NameValidator extends ValidatorBase implements IChangeListener { + /** + * Pattern that describes invalid object names We use these characters in + * transaction commits for field and data separators + **/ + private static Pattern inValidNameChars = Pattern.compile("[,;|]"); + + @Override + public void changedObject(EObject object, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, + Object newValue, String objectClassName) throws SpecmateValidationException { + + if (object instanceof INamed && feature.equals(BasePackage.Literals.INAMED__NAME)) { + validateName(newValue, object); + } + } + + @Override + public void removedObject(EObject object) throws SpecmateValidationException { + // No validation required + } + + @Override + public void newObject(EObject object, String id, String className, Map featureMap) + throws SpecmateValidationException { + + if (object instanceof INamed) { + validateName(featureMap.get(BasePackage.Literals.INAMED__NAME), object); + } + } + + private void validateName(Object objName, EObject obj) throws SpecmateValidationException { + if (objName == null) { + throw new SpecmateValidationException("Name is undefined.", getValidatorName(), null); + } + + if (!(objName instanceof String)) { + throw new SpecmateValidationException("Name is not a string.", getValidatorName(), null); + } + + String name = (String) objName; + + if (name.trim().length() == 0) { + throw new SpecmateValidationException("Name is empty.", getValidatorName(), null); + } + + Matcher m = inValidNameChars.matcher(name); + if (m.find()) { + throw new SpecmateValidationException("Name contains an invalid character: " + name.charAt(m.start()), + getValidatorName(), getObjectName(obj)); + } + } +} diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/TextLengthValidator.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/TextLengthValidator.java new file mode 100644 index 000000000..8fe1ac4b4 --- /dev/null +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/TextLengthValidator.java @@ -0,0 +1,46 @@ +package com.specmate.persistency.validation; + +import java.util.Map; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; + +import com.specmate.common.SpecmateValidationException; +import com.specmate.persistency.event.EChangeKind; + +public class TextLengthValidator extends ValidatorBase { + public static final int MAX_LENGTH = 4000; + + @Override + public void changedObject(EObject object, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, + Object newValue, String objectClassName) throws SpecmateValidationException { + checkLength(feature.getName(), newValue, object); + } + + @Override + public void removedObject(EObject object) throws SpecmateValidationException { + // Nothing to check + } + + @Override + public void newObject(EObject object, String id, String className, Map featureMap) + throws SpecmateValidationException { + + for (Map.Entry entry : featureMap.entrySet()) { + checkLength(entry.getKey().getName(), entry.getValue(), object); + } + } + + private void checkLength(String featureName, Object o, EObject obj) throws SpecmateValidationException { + if (o instanceof String) { + String v = (String) o; + if (v.length() >= MAX_LENGTH) { + throw new SpecmateValidationException( + "The content of attribute " + featureName + " is too large (" + v.length() + + "). The maximum length is " + MAX_LENGTH + ".", + getValidatorName(), getObjectName(obj)); + } + } + } + +} diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/TopLevelValidator.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/TopLevelValidator.java new file mode 100644 index 000000000..d28554a0b --- /dev/null +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/TopLevelValidator.java @@ -0,0 +1,38 @@ +package com.specmate.persistency.validation; + +import java.util.Map; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; + +import com.specmate.common.SpecmateValidationException; +import com.specmate.model.support.util.SpecmateEcoreUtil; +import com.specmate.persistency.event.EChangeKind; + +public class TopLevelValidator extends ValidatorBase { + + @Override + public void changedObject(EObject object, EStructuralFeature feature, EChangeKind changeKind, Object oldValue, + Object newValue, String objectClassName) throws SpecmateValidationException { + validateNotTopLevel(object); + } + + @Override + public void removedObject(EObject object) throws SpecmateValidationException { + validateNotTopLevel(object); + } + + @Override + public void newObject(EObject object, String id, String className, Map featureMap) + throws SpecmateValidationException { + validateNotTopLevel(object); + } + + private void validateNotTopLevel(EObject object) throws SpecmateValidationException { + EObject parent = object.eContainer(); + if (parent == null || SpecmateEcoreUtil.isProject(parent)) { + throw new SpecmateValidationException(SpecmateEcoreUtil.getName(object) + " is at top-level.", + getValidatorName(), getObjectName(object)); + } + } +} diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/ValidatorBase.java b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/ValidatorBase.java new file mode 100644 index 000000000..72f1041c2 --- /dev/null +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/ValidatorBase.java @@ -0,0 +1,23 @@ +package com.specmate.persistency.validation; + +import org.eclipse.emf.ecore.EObject; + +import com.specmate.model.base.INamed; +import com.specmate.persistency.IChangeListener; + +public abstract class ValidatorBase implements IChangeListener { + + public String getObjectName(EObject obj) { + String name = ""; + + if (obj instanceof INamed) { + name = ((INamed) obj).getName(); + } + + return name; + } + + public String getValidatorName() { + return getClass().getName(); + } +} diff --git a/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/packageinfo b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/packageinfo new file mode 100644 index 000000000..9ad81f6fa --- /dev/null +++ b/bundles/specmate-persistency-cdo/src/com/specmate/persistency/validation/packageinfo @@ -0,0 +1 @@ +version 1.0.0 diff --git a/bundles/specmate-rest/src/com/specmate/rest/RestResult.java b/bundles/specmate-rest/src/com/specmate/rest/RestResult.java index 148e46900..d302c7fcd 100644 --- a/bundles/specmate-rest/src/com/specmate/rest/RestResult.java +++ b/bundles/specmate-rest/src/com/specmate/rest/RestResult.java @@ -17,6 +17,10 @@ public RestResult(Response response, String url, T payload) { this.payload = payload; } + public RestResult(Response response) { + this(response, null, null); + } + public RestResult(Response.Status status, T payload, String userName) { this.status = status; this.payload = payload; diff --git a/bundles/specmate-scheduler/.classpath b/bundles/specmate-scheduler/.classpath index b263de401..284fd3742 100644 --- a/bundles/specmate-scheduler/.classpath +++ b/bundles/specmate-scheduler/.classpath @@ -1,6 +1,7 @@ + diff --git a/bundles/specmate-scheduler/bnd.bnd b/bundles/specmate-scheduler/bnd.bnd index edd407986..fb1d25461 100644 --- a/bundles/specmate-scheduler/bnd.bnd +++ b/bundles/specmate-scheduler/bnd.bnd @@ -1,4 +1,6 @@ Export-Package: \ com.specmate.scheduler,\ com.specmate.scheduler.iterators --buildpath: specmate-common;version=latest \ No newline at end of file +-buildpath: \ + specmate-common;version=latest,\ + org.apache.servicemix.bundles.junit \ No newline at end of file diff --git a/bundles/specmate-scheduler/src/com/specmate/scheduler/Scheduler.java b/bundles/specmate-scheduler/src/com/specmate/scheduler/Scheduler.java index ba2e5a9f8..4886caaa8 100644 --- a/bundles/specmate-scheduler/src/com/specmate/scheduler/Scheduler.java +++ b/bundles/specmate-scheduler/src/com/specmate/scheduler/Scheduler.java @@ -6,97 +6,104 @@ import com.specmate.scheduler.iterators.ScheduleIterator; - /** - * A facility for threads to schedule recurring tasks for future execution in a background thread. + * A facility for threads to schedule recurring tasks for future execution in a + * background thread. *

- * This class is thread-safe: multiple threads can share a single Scheduler object without the need for external synchronization. + * This class is thread-safe: multiple threads can share a single + * Scheduler object without the need for external synchronization. *

- * Implementation note: internally Scheduler uses a java.util.Timer to schedule tasks. + * Implementation note: internally Scheduler uses a + * java.util.Timer to schedule tasks. */ public class Scheduler { - class SchedulerTimerTask extends TimerTask { - - private SchedulerTask schedulerTask; - private ScheduleIterator iterator; - - public SchedulerTimerTask(SchedulerTask schedulerTask, - ScheduleIterator iterator) { - this.schedulerTask = schedulerTask; - this.iterator = iterator; - } - - public void run() { - try { - schedulerTask.run(); - } finally { - reschedule(schedulerTask, iterator); - } - } - } - - private final Timer timer = new Timer(); - - public Scheduler() { - } - -/** - * Terminates this Scheduler, discarding any currently scheduled tasks. Does not interfere with a currently executing task (if it exists). Once a scheduler has been terminated, its execution thread terminates gracefully, and no more tasks may be scheduled on it. - *

- * Note that calling this method from within the run method of a scheduler task that was invoked by this scheduler absolutely guarantees that the ongoing task execution is the last task execution that will ever be performed by this scheduler. - *

- * This method may be called repeatedly; the second and subsequent calls have no effect. - */ - - public void cancel() { - timer.cancel(); - } - -/** - * Schedules the specified task for execution according to the specified schedule. If times specified by the ScheduleIterator are in the past they are scheduled for immediate execution. - *

- * @param schedulerTask task to be scheduled - * @param iterator iterator that describes the schedule - * @throws IllegalStateException if task was already scheduled or cancelled, scheduler was cancelled, or scheduler thread terminated. - */ - - public void schedule(SchedulerTask schedulerTask, - ScheduleIterator iterator) { - - Date time = iterator.next(); - if (time == null) { - schedulerTask.cancel(); - } else { - synchronized(schedulerTask.lock) { - if (schedulerTask.state != SchedulerTask.VIRGIN) { - throw new IllegalStateException("Task already scheduled " + - "or cancelled"); - } - schedulerTask.state = SchedulerTask.SCHEDULED; - schedulerTask.timerTask = - new SchedulerTimerTask(schedulerTask, iterator); - timer.schedule(schedulerTask.timerTask, time); - } - } - } - - private void reschedule(SchedulerTask schedulerTask, - ScheduleIterator iterator) { - - Date time = iterator.next(); - if (time == null) { - schedulerTask.cancel(); - } else { - synchronized(schedulerTask.lock) { - if (schedulerTask.state != SchedulerTask.CANCELLED) { - schedulerTask.timerTask = - new SchedulerTimerTask(schedulerTask, iterator); - timer.schedule(schedulerTask.timerTask, time); - } - } - } - } + class SchedulerTimerTask extends TimerTask { + + private SchedulerTask schedulerTask; + private ScheduleIterator iterator; + + public SchedulerTimerTask(SchedulerTask schedulerTask, ScheduleIterator iterator) { + this.schedulerTask = schedulerTask; + this.iterator = iterator; + } + + public void run() { + try { + schedulerTask.run(); + } finally { + reschedule(schedulerTask, iterator); + } + } + } + + private final Timer timer = new Timer(); + + public Scheduler() { + } + + /** + * Terminates this Scheduler, discarding any currently + * scheduled tasks. Does not interfere with a currently executing task (if + * it exists). Once a scheduler has been terminated, its execution thread + * terminates gracefully, and no more tasks may be scheduled on it. + *

+ * Note that calling this method from within the run method of a scheduler + * task that was invoked by this scheduler absolutely guarantees that the + * ongoing task execution is the last task execution that will ever be + * performed by this scheduler. + *

+ * This method may be called repeatedly; the second and subsequent calls + * have no effect. + */ + public void cancel() { + timer.cancel(); + } + + /** + * Schedules the specified task for execution according to the specified + * schedule. If times specified by the ScheduleIterator are in + * the past they are scheduled for immediate execution. + *

+ * + * @param schedulerTask + * task to be scheduled + * @param iterator + * iterator that describes the schedule + * @throws IllegalStateException + * if task was already scheduled or cancelled, scheduler was + * cancelled, or scheduler thread terminated. + */ + public void schedule(SchedulerTask schedulerTask, ScheduleIterator iterator) { + + Date time = iterator.next(); + if (time == null) { + schedulerTask.cancel(); + } else { + synchronized (schedulerTask.lock) { + if (schedulerTask.state != SchedulerTask.VIRGIN) { + throw new IllegalStateException("Task already scheduled " + "or cancelled"); + } + schedulerTask.state = SchedulerTask.SCHEDULED; + schedulerTask.timerTask = new SchedulerTimerTask(schedulerTask, iterator); + timer.schedule(schedulerTask.timerTask, time); + } + } + } + + private void reschedule(SchedulerTask schedulerTask, ScheduleIterator iterator) { + + Date time = iterator.next(); + if (time == null) { + schedulerTask.cancel(); + } else { + synchronized (schedulerTask.lock) { + if (schedulerTask.state != SchedulerTask.CANCELLED) { + schedulerTask.timerTask = new SchedulerTimerTask(schedulerTask, iterator); + timer.schedule(schedulerTask.timerTask, time); + } + } + } + } } - diff --git a/bundles/specmate-scheduler/src/com/specmate/scheduler/SchedulerIteratorFactory.java b/bundles/specmate-scheduler/src/com/specmate/scheduler/SchedulerIteratorFactory.java index 40b40b775..746cfd186 100644 --- a/bundles/specmate-scheduler/src/com/specmate/scheduler/SchedulerIteratorFactory.java +++ b/bundles/specmate-scheduler/src/com/specmate/scheduler/SchedulerIteratorFactory.java @@ -1,6 +1,8 @@ package com.specmate.scheduler; import java.util.Arrays; +import java.util.Date; + import com.specmate.common.SpecmateException; import com.specmate.common.SpecmateValidationException; import com.specmate.scheduler.iterators.DailyIterator; @@ -17,24 +19,29 @@ public class SchedulerIteratorFactory { private static final String DELIM = " "; public static ScheduleIterator create(String schedule) throws SpecmateException, SpecmateValidationException { + return create(schedule, new Date()); + } + + public static ScheduleIterator create(String schedule, Date date) + throws SpecmateException, SpecmateValidationException { validate(schedule); schedule = normalizeScheduleString(schedule); - return constructScheduleIterator(schedule); + return constructScheduleIterator(schedule, date); } - private static ScheduleIterator constructScheduleIterator(String schedule) throws SpecmateException { + private static ScheduleIterator constructScheduleIterator(String schedule, Date date) throws SpecmateException { String type = getType(schedule); int[] args = getArgs(schedule); if (type.equalsIgnoreCase(DAY)) { - return new DailyIterator(args); + return new DailyIterator(date, args); } if (type.equalsIgnoreCase(HOUR)) { - return new HourlyIterator(args); + return new HourlyIterator(date, args); } if (type.equalsIgnoreCase(MINUTE)) { - return new MinuteIterator(args); + return new MinuteIterator(date, args); } throw new SpecmateException("Invalid scheduler type"); } @@ -92,7 +99,7 @@ private static String[] getArgsStrs(String schedule) { String[] empty = new String[0]; return empty; } - String[] argumentsStr = Arrays.copyOfRange(parts, 1, parts.length - 1); + String[] argumentsStr = Arrays.copyOfRange(parts, 1, parts.length); return argumentsStr; } } diff --git a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/DailyIterator.java b/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/DailyIterator.java index b566fadcb..ceeb25243 100644 --- a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/DailyIterator.java +++ b/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/DailyIterator.java @@ -10,8 +10,8 @@ public class DailyIterator implements ScheduleIterator { private final Calendar calendar = Calendar.getInstance(); - public DailyIterator(int... time) { - this(getHourOfDay(time), getMinute(time), getSecond(time), new Date()); + public DailyIterator(Date date, int... time) { + this(getHourOfDay(time), getMinute(time), getSecond(time), date); } public DailyIterator(int hourOfDay, int minute, int second, Date date) { @@ -25,6 +25,7 @@ public DailyIterator(int hourOfDay, int minute, int second, Date date) { } } + @Override public Date next() { calendar.add(Calendar.DATE, 1); return calendar.getTime(); @@ -33,11 +34,11 @@ public Date next() { private static int getHourOfDay(int... time) { return SchedulerUtils.getNumberIfExistsOrZero(0, time); } - + private static int getMinute(int... time) { return SchedulerUtils.getNumberIfExistsOrZero(1, time); } - + private static int getSecond(int... time) { return SchedulerUtils.getNumberIfExistsOrZero(2, time); } diff --git a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/HourlyIterator.java b/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/HourlyIterator.java index d341aaad8..c5dc3415b 100644 --- a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/HourlyIterator.java +++ b/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/HourlyIterator.java @@ -10,8 +10,8 @@ public class HourlyIterator implements ScheduleIterator { private final Calendar calendar = Calendar.getInstance(); - public HourlyIterator(int... time) { - this(getMinute(time), getSecond(time), new Date()); + public HourlyIterator(Date date, int... time) { + this(getMinute(time), getSecond(time), date); } public HourlyIterator(int minute, int second, Date date) { @@ -20,10 +20,11 @@ public HourlyIterator(int minute, int second, Date date) { calendar.set(Calendar.SECOND, second); calendar.set(Calendar.MILLISECOND, 0); if (!calendar.getTime().before(date)) { - calendar.add(Calendar.DATE, -1); + calendar.add(Calendar.HOUR_OF_DAY, -1); } } + @Override public Date next() { calendar.add(Calendar.HOUR_OF_DAY, 1); return calendar.getTime(); @@ -32,7 +33,7 @@ public Date next() { private static int getMinute(int... time) { return SchedulerUtils.getNumberIfExistsOrZero(0, time); } - + private static int getSecond(int... time) { return SchedulerUtils.getNumberIfExistsOrZero(1, time); } diff --git a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/MinuteIterator.java b/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/MinuteIterator.java index 956ed7b42..d1145e46f 100644 --- a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/MinuteIterator.java +++ b/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/MinuteIterator.java @@ -10,8 +10,8 @@ public class MinuteIterator implements ScheduleIterator { private final Calendar calendar = Calendar.getInstance(); - public MinuteIterator(int... time) { - this(getSecond(time), new Date()); + public MinuteIterator(Date date, int... time) { + this(getSecond(time), date); } public MinuteIterator(int second, Date date) { @@ -19,10 +19,11 @@ public MinuteIterator(int second, Date date) { calendar.set(Calendar.SECOND, second); calendar.set(Calendar.MILLISECOND, 0); if (!calendar.getTime().before(date)) { - calendar.add(Calendar.DATE, -1); + calendar.add(Calendar.MINUTE, -1); } } + @Override public Date next() { calendar.add(Calendar.MINUTE, 1); return calendar.getTime(); diff --git a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/RestrictedDailyIterator.java b/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/RestrictedDailyIterator.java deleted file mode 100644 index d8c3aabc3..000000000 --- a/bundles/specmate-scheduler/src/com/specmate/scheduler/iterators/RestrictedDailyIterator.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.specmate.scheduler.iterators; - -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; - -/** - * A RestrictedDailyIterator returns a sequence of dates on - * subsequent days (restricted to a set of days, e.g. weekdays only) - * representing the same time each day. - */ -public class RestrictedDailyIterator implements ScheduleIterator { - private final int[] days; - private final Calendar calendar = Calendar.getInstance(); - - public RestrictedDailyIterator(int hourOfDay, int minute, int second, int[] days) { - this(hourOfDay, minute, second, days, new Date()); - } - - public RestrictedDailyIterator(int hourOfDay, int minute, int second, int[] days, Date date) { - this.days = (int[]) days.clone(); - Arrays.sort(this.days); - - calendar.setTime(date); - calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); - calendar.set(Calendar.MINUTE, minute); - calendar.set(Calendar.SECOND, second); - calendar.set(Calendar.MILLISECOND, 0); - if (!calendar.getTime().before(date)) { - calendar.add(Calendar.DATE, -1); - } - } - - public Date next() { - do { - calendar.add(Calendar.DATE, 1); - } while (Arrays.binarySearch(days, calendar.get(Calendar.DAY_OF_WEEK)) < 0); - return calendar.getTime(); - } - -} diff --git a/bundles/specmate-scheduler/test/com/specmate/schedule/test/IteratorsTest.java b/bundles/specmate-scheduler/test/com/specmate/schedule/test/IteratorsTest.java new file mode 100644 index 000000000..d74bd4c33 --- /dev/null +++ b/bundles/specmate-scheduler/test/com/specmate/schedule/test/IteratorsTest.java @@ -0,0 +1,78 @@ +package com.specmate.schedule.test; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.junit.Assert; +import org.junit.Test; + +import com.specmate.scheduler.SchedulerIteratorFactory; +import com.specmate.scheduler.iterators.ScheduleIterator; + +public class IteratorsTest { + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + @Test + public void testHourlyIterator() throws Exception { + Date date = dateFormat.parse("2018-11-01 09:30:10"); + + // scheduled time before current time + ScheduleIterator hourlyIterator = SchedulerIteratorFactory.create("hour 20 15", date); + Date next = hourlyIterator.next(); + Assert.assertEquals("2018-11-01 10:20:15", dateFormat.format(next)); + + // scheduled time after current time + hourlyIterator = SchedulerIteratorFactory.create("hour 40 15", date); + next = hourlyIterator.next(); + Assert.assertEquals("2018-11-01 09:40:15", dateFormat.format(next)); + + Date endOfDay = dateFormat.parse("2018-12-31 23:30:10"); + // scheduled time need day jump + hourlyIterator = SchedulerIteratorFactory.create("hour 20 15", endOfDay); + next = hourlyIterator.next(); + Assert.assertEquals("2019-01-01 00:20:15", dateFormat.format(next)); + } + + @Test + public void testMinuteIterator() throws Exception { + Date date = dateFormat.parse("2018-11-01 09:30:10"); + + // scheduled time before current time + ScheduleIterator minuteIterator = SchedulerIteratorFactory.create("minute 15", date); + Date next = minuteIterator.next(); + Assert.assertEquals("2018-11-01 09:30:15", dateFormat.format(next)); + + // scheduled time after current time + minuteIterator = SchedulerIteratorFactory.create("minute 5", date); + next = minuteIterator.next(); + Assert.assertEquals("2018-11-01 09:31:05", dateFormat.format(next)); + + Date endOfDay = dateFormat.parse("2018-12-31 23:59:10"); + // scheduled time need day jump + minuteIterator = SchedulerIteratorFactory.create("minute 5", endOfDay); + next = minuteIterator.next(); + Assert.assertEquals("2019-01-01 00:00:05", dateFormat.format(next)); + } + + @Test + public void testDaily() throws Exception { + Date date = dateFormat.parse("2018-11-01 09:30:10"); + + // scheduled time before current time + ScheduleIterator dayIterator = SchedulerIteratorFactory.create("day 8 20 5", date); + Date next = dayIterator.next(); + Assert.assertEquals("2018-11-02 08:20:05", dateFormat.format(next)); + + // scheduled time after current time + dayIterator = SchedulerIteratorFactory.create("day 10 20 5", date); + next = dayIterator.next(); + Assert.assertEquals("2018-11-01 10:20:05", dateFormat.format(next)); + + Date endOfDay = dateFormat.parse("2018-12-31 23:59:10"); + // scheduled minutes need year jump + dayIterator = SchedulerIteratorFactory.create("day 10 20 5", endOfDay); + next = dayIterator.next(); + Assert.assertEquals("2019-01-01 10:20:05", dateFormat.format(next)); + } +} diff --git a/bundles/specmate-std-env/dev-specmate-all.bndrun b/bundles/specmate-std-env/dev-specmate-all.bndrun index ddc1f26d9..bdf6e6e40 100644 --- a/bundles/specmate-std-env/dev-specmate-all.bndrun +++ b/bundles/specmate-std-env/dev-specmate-all.bndrun @@ -187,6 +187,7 @@ com.sun.jersey.jersey-server;version='[1.19.0,1.19.1)',\ javax.ws.rs.jsr311-api;version='[1.1.1,1.1.2)',\ specmate-rest;version=snapshot,\ + org.apache.commons.collections4;version='[4.0.0,4.0.1)',\ specmate-scheduler;version=snapshot -runproperties: \ @@ -198,4 +199,5 @@ -runrepos: \ Workspace,\ Local --runvm: -Xmx6000m, -Djdk.crypto.KeyAgreement.legacyKDF=true \ No newline at end of file +-runvm: -Xmx6000m\n\ + -Djdk.crypto.KeyAgreement.legacyKDF=true \ No newline at end of file diff --git a/bundles/specmate-std-env/prod-specmate-all.bndrun b/bundles/specmate-std-env/prod-specmate-all.bndrun index 06154ee49..c8b7082e3 100644 --- a/bundles/specmate-std-env/prod-specmate-all.bndrun +++ b/bundles/specmate-std-env/prod-specmate-all.bndrun @@ -172,6 +172,7 @@ org.apache.commons.lang3;version='[3.3.2,3.3.3)',\ org.eclipse.emf.cdo.server.db;version='[4.4.0,4.4.1)',\ specmate-rest;version=snapshot,\ + org.apache.commons.collections4;version='[4.0.0,4.0.1)',\ specmate-scheduler;version=snapshot -runproperties: \ diff --git a/bundles/specmate-testspecification/bnd.bnd b/bundles/specmate-testspecification/bnd.bnd index b897e0901..fc5b2f92e 100644 --- a/bundles/specmate-testspecification/bnd.bnd +++ b/bundles/specmate-testspecification/bnd.bnd @@ -17,4 +17,6 @@ org.sat4j.pb,\ specmate-emfrest-api;version=latest,\ specmate-rest;version=latest -Private-Package: com.specmate.testspecification.internal.services \ No newline at end of file +Private-Package: \ + com.specmate.testspecification.internal.services,\ + com.specmate.testspecification.internal.testskeleton \ No newline at end of file diff --git a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/CEGTestCaseGenerator.java b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/CEGTestCaseGenerator.java index 434fcb85b..537087667 100644 --- a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/CEGTestCaseGenerator.java +++ b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/CEGTestCaseGenerator.java @@ -1,6 +1,7 @@ package com.specmate.testspecification.internal.services; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -8,6 +9,7 @@ import java.util.Map.Entry; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; @@ -65,7 +67,7 @@ protected void generateParameters() { /** * Determines if a node is an input, output or intermediate node. - * + * * @param node * @return ParameterType.INPUT, if the nodes is an input node, * ParameterType.OUTPUT, if the node is an output node, @@ -143,6 +145,7 @@ private TestCase createTestCase(NodeEvaluation evaluation, TestSpecification spe String parameterValue = StringUtils.join(constraints, ","); ParameterAssignment assignment = TestspecificationFactory.eINSTANCE.createParameterAssignment(); assignment.setId(SpecmateEcoreUtil.getIdForChild(testCase, assignment.eClass())); + assignment.setName(assignment.getId()); assignment.setParameter(parameter); assignment.setValue(parameterValue); assignment.setCondition(parameterValue); @@ -168,10 +171,10 @@ private String negateCondition(String condition) { } /** - * Node evaluations are a precursor to test cases. This method computes the - * node evaluations according to the rules in the Specmate systems - * requirements documentation. - * + * Node evaluations are a precursor to test cases. This method computes the node + * evaluations according to the rules in the Specmate systems requirements + * documentation. + * * @param nodes * @return * @throws SpecmateException @@ -211,8 +214,8 @@ private Pair, Set> refineEvaluations(Set getInitialEvaluations() { Set evaluations = new HashSet<>(); @@ -247,8 +250,8 @@ private Optional getAnyIntermediateNode(NodeEvaluation evaluation) { } /** - * Returns evaluations that have intermediate nodes (i.e. nodes that have to - * be evaluated) + * Returns evaluations that have intermediate nodes (i.e. nodes that have to be + * evaluated) */ private Set getIntermediateEvaluations(Set evaluations) { HashSet intermediate = new HashSet<>(); @@ -322,9 +325,9 @@ private void handleAllCase(boolean isAnd, NodeEvaluation evaluation, IModelNode } /** - * Sets the value of a node in an evaluation but checks first if it is - * already set with a different value - * + * Sets the value of a node in an evaluation but checks first if it is already + * set with a different value + * * @return false if an inconsistent value would be set in the node */ private boolean checkAndSet(NodeEvaluation evaluation, CEGNode node, TaggedBoolean effectiveValue) @@ -338,9 +341,9 @@ private boolean checkAndSet(NodeEvaluation evaluation, CEGNode node, TaggedBoole } /** - * Runs through the list of evaluations and merges the ones that can be - * merged. Identifiey inconsistent evaluations - * + * Runs through the list of evaluations and merges the ones that can be merged. + * Identify inconsistent evaluations + * * @throws SpecmateException */ private Pair, Set> mergeCompatibleEvaluations(Set evaluations) @@ -441,10 +444,11 @@ private int getAdditionalVar(int i) { return nodes.size() + i; } - private IVecInt getVectorForVariables(int... vars) { + private IVecInt getVectorForVariables(Integer... vars) { IVecInt vector = new VecInt(vars.length + 1); - for (int i = 0; i < vars.length; i++) + for (int i = 0; i < vars.length; i++) { vector.push(vars[i]); + } return vector; } @@ -475,8 +479,8 @@ private NodeEvaluation fill(NodeEvaluation evaluation) throws SpecmateException } /** - * Sets the value in an evaluation based on an original evaluation and a - * model value. + * Sets the value in an evaluation based on an original evaluation and a model + * value. */ private void setModelValue(NodeEvaluation originalEvaluation, NodeEvaluation targetEvaluation, int varNameValue) { boolean value = varNameValue > 0; @@ -516,6 +520,7 @@ private void pushEvaluation(NodeEvaluation evaluation, GateTranslator translator } } + /** Feeds constraints representing the CEG structure to the solver */ private void pushCEGStructure(GateTranslator translator) throws ContradictionException { for (IModelNode node : nodes) { int varForNode = getVarForNode(node); @@ -528,6 +533,35 @@ private void pushCEGStructure(GateTranslator translator) throws ContradictionExc } } } + pushMutualExclusiveConstraints(translator); + } + + private void pushMutualExclusiveConstraints(GateTranslator translator) throws ContradictionException { + Collection> mutualExclusiveNodeSets = getMutualExclusiveNodeSets(); + for (Collection mutexSet : mutualExclusiveNodeSets) { + Integer[] variables = mutexSet.stream().map(node -> getVarForNode(node)).collect(Collectors.toList()) + .toArray(new Integer[0]); + translator.addAtMost(getVectorForVariables(variables), 1); + } + } + + private Collection> getMutualExclusiveNodeSets() { + Collection> result = new ArrayList<>(); + Map> multiMap = new HashMap>(); + for (IModelNode node : nodes) { + CEGNode cegNode = (CEGNode) node; + if (cegNode.getCondition().trim().startsWith("=")) { + String variable = cegNode.getVariable(); + if(!multiMap.containsKey(variable)) { + multiMap.put(variable, new HashSet()); + } + multiMap.get(variable).add(cegNode); + } + } + for (String key : multiMap.keySet()) { + result.add(multiMap.get(key)); + } + return result; } /** Returns the CEG node for a given variable (given as int) */ @@ -545,7 +579,7 @@ private IVecInt getPredecessorVector(IModelNode node) { IVecInt vector = new VecInt(); for (IModelConnection conn : node.getIncomingConnections()) { IModelNode pre = conn.getSource(); - int var = getVarForNode((CEGNode) pre); + int var = getVarForNode(pre); if (((CEGConnection) conn).isNegate()) { var *= -1; } @@ -555,9 +589,9 @@ private IVecInt getPredecessorVector(IModelNode node) { } /** - * Equality checker that ignores differences in the fields id, name and - * position + * Equality checker that ignores differences in the fields id, name and position */ + @SuppressWarnings("serial") private class IdNamePositionIgnoreEqualityHelper extends EqualityHelper { @Override protected boolean haveEqualFeature(EObject eObject1, EObject eObject2, EStructuralFeature feature) { diff --git a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/TestGeneratorService.java b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/TestGeneratorService.java index 1aa3305d5..cff0392b2 100644 --- a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/TestGeneratorService.java +++ b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/TestGeneratorService.java @@ -6,7 +6,6 @@ import org.osgi.service.component.annotations.Component; import com.specmate.common.SpecmateException; -import com.specmate.common.SpecmateValidationException; import com.specmate.emfrest.api.IRestService; import com.specmate.emfrest.api.RestServiceBase; import com.specmate.model.processes.Process; @@ -38,8 +37,7 @@ public boolean canPost(Object target, Object object) { /** {@inheritDoc} */ @Override - public RestResult post(Object target, Object object, String token) - throws SpecmateValidationException, SpecmateException { + public RestResult post(Object target, Object object, String token) throws SpecmateException { TestSpecification specification = (TestSpecification) target; EObject container = specification.eContainer(); if (container instanceof CEGModel) { @@ -47,7 +45,7 @@ public RestResult post(Object target, Object object, String token) } else if (container instanceof Process) { new ProcessTestCaseGenerator(specification).generate(); } else { - throw new SpecmateValidationException( + throw new SpecmateException( "You can only generate test cases from ceg models or processes. The supplied element is of class " + container.getClass().getSimpleName()); } diff --git a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/TestSkeletonGeneratorService.java b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/TestSkeletonGeneratorService.java new file mode 100644 index 000000000..40588f121 --- /dev/null +++ b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/services/TestSkeletonGeneratorService.java @@ -0,0 +1,69 @@ +package com.specmate.testspecification.internal.services; + +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; + +import com.specmate.common.SpecmateException; +import com.specmate.emfrest.api.IRestService; +import com.specmate.emfrest.api.RestServiceBase; +import com.specmate.model.testspecification.TestSpecification; +import com.specmate.model.testspecification.TestSpecificationSkeleton; +import com.specmate.rest.RestResult; +import com.specmate.testspecification.internal.testskeleton.BaseSkeleton; +import com.specmate.testspecification.internal.testskeleton.JavaTestSpecificationSkeleton; +import com.specmate.testspecification.internal.testskeleton.JavascriptTestSpecificationSkeleton; + +@Component(immediate = true, service = IRestService.class) +public class TestSkeletonGeneratorService extends RestServiceBase { + private final String LPARAM = "language"; + private final String JAVA = "java"; + private final String JAVASCRIPT = "javascript"; + private Map skeletonGenerators; + + @Activate + public void activate() { + skeletonGenerators = new HashMap<>(); + skeletonGenerators.put(JAVA, new JavaTestSpecificationSkeleton(JAVA)); + skeletonGenerators.put(JAVASCRIPT, new JavascriptTestSpecificationSkeleton(JAVASCRIPT)); + } + + @Override + public String getServiceName() { + return "generateTestSkeleton"; + } + + @Override + public boolean canGet(Object object) { + return object instanceof TestSpecification; + } + + @Override + public RestResult get(Object object, MultivaluedMap queryParams, String token) + throws SpecmateException { + + String language = queryParams.getFirst(LPARAM); + if (language == null) { + return new RestResult<>(Response.Status.BAD_REQUEST); + } + + BaseSkeleton generator = skeletonGenerators.get(language); + if (generator == null) { + return new RestResult<>(Response.Status.BAD_REQUEST); + } + + if (!(object instanceof TestSpecification)) { + return new RestResult<>(Response.Status.BAD_REQUEST); + } + + TestSpecification ts = (TestSpecification) object; + + return new RestResult(Response.Status.OK, generator.generate(ts)); + } + +} diff --git a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/BaseSkeleton.java b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/BaseSkeleton.java new file mode 100644 index 000000000..84fb31509 --- /dev/null +++ b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/BaseSkeleton.java @@ -0,0 +1,82 @@ +package com.specmate.testspecification.internal.testskeleton; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.regex.Pattern; + +import com.specmate.model.support.util.SpecmateEcoreUtil; +import com.specmate.model.testspecification.ParameterAssignment; +import com.specmate.model.testspecification.ParameterType; +import com.specmate.model.testspecification.TestCase; +import com.specmate.model.testspecification.TestSpecification; +import com.specmate.model.testspecification.TestSpecificationSkeleton; +import com.specmate.model.testspecification.TestspecificationFactory; + +public abstract class BaseSkeleton { + private static Pattern startsNumerical = Pattern.compile("^[0-9]"); + private static Pattern invalidChars = Pattern.compile("[^a-zA-Z_0-9\\_]"); + protected String language; + protected String testArea; + protected Date generationDate; + protected TestSpecification testSpecification; + + public BaseSkeleton(String language) { + this.language = language; + this.generationDate = new Date(); + } + + public TestSpecificationSkeleton generate(TestSpecification testSpecification) { + StringBuilder sb = new StringBuilder(); + this.testSpecification = testSpecification; + this.testArea = testSpecification.getName(); + TestSpecificationSkeleton tss = TestspecificationFactory.eINSTANCE.createTestSpecificationSkeleton(); + tss.setLanguage(language); + tss.setName(generateFileName()); + tss.setCode(generateCode(sb)); + + return tss; + } + + protected void appendTestCaseMethodName(StringBuilder sb, TestCase tc) { + List pAssignments = SpecmateEcoreUtil.pickInstancesOf(tc.getContents(), + ParameterAssignment.class); + + ParameterAssignment output = null; + for (ParameterAssignment pAssignment : pAssignments) { + if (pAssignment.getParameter().getType().equals(ParameterType.OUTPUT)) { + output = pAssignment; + } else { + appendParameterValue(sb, pAssignment); + } + } + + if (output != null) { + appendParameterValue(sb, output); + } + } + + protected void appendDateComment(StringBuilder sb) { + sb.append("/*\n"); + sb.append(" * Datum: "); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + sb.append(sdf.format(generationDate)); + sb.append("\n */\n\n"); + } + + protected String replaceInvalidChars(String r) { + r = startsNumerical.matcher(r).replaceAll(""); + return invalidChars.matcher(r).replaceAll("_"); + } + + private void appendParameterValue(StringBuilder sb, ParameterAssignment pa) { + sb.append("___"); + sb.append(replaceInvalidChars(pa.getParameter().getName())); + sb.append("__"); + sb.append(replaceInvalidChars(pa.getValue())); + } + + protected abstract String generateCode(StringBuilder sb); + + protected abstract String generateFileName(); +} diff --git a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/JavaTestSpecificationSkeleton.java b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/JavaTestSpecificationSkeleton.java new file mode 100644 index 000000000..4aeb5d440 --- /dev/null +++ b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/JavaTestSpecificationSkeleton.java @@ -0,0 +1,50 @@ +package com.specmate.testspecification.internal.testskeleton; + +import java.util.List; + +import com.specmate.model.support.util.SpecmateEcoreUtil; +import com.specmate.model.testspecification.TestCase; + +public class JavaTestSpecificationSkeleton extends BaseSkeleton { + + public JavaTestSpecificationSkeleton(String language) { + super(language); + } + + @Override + protected String generateCode(StringBuilder sb) { + sb.append("import org.junit.Test;\n"); + sb.append("import org.junit.Assert;\n\n"); + appendDateComment(sb); + sb.append("public class "); + sb.append(generateClassname()); + sb.append(" {\n\n"); + List testCases = SpecmateEcoreUtil.pickInstancesOf(testSpecification.getContents(), TestCase.class); + for (TestCase tc : testCases) { + sb.append("\t/*\n"); + sb.append("\t * Testfall: "); + sb.append(tc.getName()); + sb.append("\n\t */\n"); + sb.append("\t@Test\n"); + sb.append("\tpublic void "); + sb.append(generateClassname()); + appendTestCaseMethodName(sb, tc); + sb.append("() {\n"); + sb.append("\t\tAssert.throw();\n"); + sb.append("\t}\n\n"); + } + + sb.append("}"); + + return sb.toString(); + } + + @Override + protected String generateFileName() { + return generateClassname() + ".java"; + } + + private String generateClassname() { + return replaceInvalidChars(testArea) + "Test"; + } +} diff --git a/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/JavascriptTestSpecificationSkeleton.java b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/JavascriptTestSpecificationSkeleton.java new file mode 100644 index 000000000..660256d6e --- /dev/null +++ b/bundles/specmate-testspecification/src/com/specmate/testspecification/internal/testskeleton/JavascriptTestSpecificationSkeleton.java @@ -0,0 +1,43 @@ +package com.specmate.testspecification.internal.testskeleton; + +import java.util.List; + +import com.specmate.model.support.util.SpecmateEcoreUtil; +import com.specmate.model.testspecification.TestCase; + +public class JavascriptTestSpecificationSkeleton extends BaseSkeleton { + + public JavascriptTestSpecificationSkeleton(String language) { + super(language); + } + + @Override + protected String generateCode(StringBuilder sb) { + appendDateComment(sb); + sb.append("describe('"); + sb.append(replaceInvalidChars(testArea)); + sb.append("', () => {\n\n"); + List testCases = SpecmateEcoreUtil.pickInstancesOf(testSpecification.getContents(), TestCase.class); + for (TestCase tc : testCases) { + sb.append("\t/*\n"); + sb.append("\t * Testfall: "); + sb.append(tc.getName()); + sb.append("\n\t */\n"); + sb.append("\tit('"); + sb.append(replaceInvalidChars(testArea)); + appendTestCaseMethodName(sb, tc); + sb.append("', () => {\n"); + sb.append("\t\tthrow new Error('not implemented yet');\n"); + sb.append("\t});\n\n"); + } + + sb.append("});"); + + return sb.toString(); + } + + @Override + protected String generateFileName() { + return replaceInvalidChars(testArea) + ".js"; + } +} diff --git a/bundles/specmate-trello-connector/src/com/specmate/connectors/trello/internal/services/TrelloConnector.java b/bundles/specmate-trello-connector/src/com/specmate/connectors/trello/internal/services/TrelloConnector.java index 960748f56..5dbb51842 100644 --- a/bundles/specmate-trello-connector/src/com/specmate/connectors/trello/internal/services/TrelloConnector.java +++ b/bundles/specmate-trello-connector/src/com/specmate/connectors/trello/internal/services/TrelloConnector.java @@ -17,7 +17,6 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.log.LogService; -import com.specmate.rest.RestClient; import com.specmate.common.SpecmateException; import com.specmate.common.SpecmateValidationException; import com.specmate.connectors.api.IRequirementsSource; @@ -28,6 +27,7 @@ import com.specmate.model.base.IContainer; import com.specmate.model.requirements.Requirement; import com.specmate.model.requirements.RequirementsFactory; +import com.specmate.rest.RestClient; import com.specmate.rest.RestResult; @Component(immediate = true, service = IRequirementsSource.class, configurationPid = TrelloConnectorConfig.PID, configurationPolicy = ConfigurationPolicy.REQUIRE) @@ -78,6 +78,7 @@ public Collection getRequirements() throws SpecmateException { RestResult restResult = restClient.getList("/1/boards/" + boardId + "/cards", "key", this.key, "token", this.token); if (restResult.getResponse().getStatus() == Status.OK.getStatusCode()) { + restResult.getResponse().close(); List requirements = new ArrayList<>(); JSONArray cardsArray = restResult.getPayload(); for (int i = 0; i < cardsArray.length(); i++) { @@ -86,6 +87,7 @@ public Collection getRequirements() throws SpecmateException { } return requirements; } else { + restResult.getResponse().close(); throw new SpecmateException("Could not retrieve list of trello cards."); } } @@ -106,6 +108,7 @@ public List getLists() throws SpecmateException { RestResult restResult = restClient.getList("/1/boards/" + boardId + "/lists", "cards", "open", "key", this.key, "token", this.token); if (restResult.getResponse().getStatus() == Status.OK.getStatusCode()) { + restResult.getResponse().close(); List folders = new ArrayList<>(); JSONArray listsArray = restResult.getPayload(); for (int i = 0; i < listsArray.length(); i++) { @@ -115,6 +118,7 @@ public List getLists() throws SpecmateException { } return folders; } + restResult.getResponse().close(); throw new SpecmateException("Could not load Trello Lists."); } diff --git a/web/package.json b/web/package.json index 9b29cdb82..c00d7734f 100644 --- a/web/package.json +++ b/web/package.json @@ -38,6 +38,7 @@ "bootstrap": "4.0.0", "classlist.js": "1.1.20150312", "core-js": "2.5.3", + "file-saver": "^2.0.0-rc.4", "flag-icon-css": "2.9.0", "font-awesome": "4.7.0", "jquery": "3.3.1", @@ -53,6 +54,7 @@ }, "devDependencies": { "@biesbjerg/ngx-translate-extract": "2.3.4", + "@types/file-saver": "^2.0.0", "@types/yargs": "^11.0.0", "angular2-dependencies-graph": "1.0.0-alpha.12", "angular2-template-loader": "0.6.2", diff --git a/web/src/app/factory/util/graph-element-factory-selector.ts b/web/src/app/factory/util/graph-element-factory-selector.ts index 99490d750..b0df1ffb0 100644 --- a/web/src/app/factory/util/graph-element-factory-selector.ts +++ b/web/src/app/factory/util/graph-element-factory-selector.ts @@ -20,7 +20,7 @@ import { ProcessConnection } from '../../model/ProcessConnection'; import { ProcessConnectionFactory } from '../process-connection-factory'; import { IModelNode } from '../../model/IModelNode'; -type Coords = {x: number, y: number}; +export type Coords = {x: number, y: number}; export class GraphElementFactorySelector { public static getNodeFactory(template: IContainer, coords: Coords, dataService: SpecmateDataService): PositionableElementFactoryBase { diff --git a/web/src/app/model/BatchOperation.ts b/web/src/app/model/BatchOperation.ts index 1320748bd..da93a9c01 100644 --- a/web/src/app/model/BatchOperation.ts +++ b/web/src/app/model/BatchOperation.ts @@ -5,7 +5,7 @@ export class BatchOperation { - ___nsuri: string = "http://specmate.com/20180925/model/batch"; + ___nsuri: string = "http://specmate.com/20181108/model/batch"; public url: string; public className: string = "BatchOperation"; public static className: string = "BatchOperation"; diff --git a/web/src/app/model/CEGConnection.ts b/web/src/app/model/CEGConnection.ts index 4d3a88f5b..9856243dc 100644 --- a/web/src/app/model/CEGConnection.ts +++ b/web/src/app/model/CEGConnection.ts @@ -4,7 +4,7 @@ export class CEGConnection { - ___nsuri: string = "http://specmate.com/20180925/model/requirements"; + ___nsuri: string = "http://specmate.com/20181108/model/requirements"; public url: string; public className: string = "CEGConnection"; public static className: string = "CEGConnection"; diff --git a/web/src/app/model/CEGModel.ts b/web/src/app/model/CEGModel.ts index d8155ca3e..83b1b51d7 100644 --- a/web/src/app/model/CEGModel.ts +++ b/web/src/app/model/CEGModel.ts @@ -4,7 +4,7 @@ export class CEGModel { - ___nsuri: string = "http://specmate.com/20180925/model/requirements"; + ___nsuri: string = "http://specmate.com/20181108/model/requirements"; public url: string; public className: string = "CEGModel"; public static className: string = "CEGModel"; diff --git a/web/src/app/model/CEGNode.ts b/web/src/app/model/CEGNode.ts index 09ba8be39..f87623257 100644 --- a/web/src/app/model/CEGNode.ts +++ b/web/src/app/model/CEGNode.ts @@ -4,7 +4,7 @@ export class CEGNode { - ___nsuri: string = "http://specmate.com/20180925/model/requirements"; + ___nsuri: string = "http://specmate.com/20181108/model/requirements"; public url: string; public className: string = "CEGNode"; public static className: string = "CEGNode"; diff --git a/web/src/app/model/Change.ts b/web/src/app/model/Change.ts index b5d211533..271ed0342 100644 --- a/web/src/app/model/Change.ts +++ b/web/src/app/model/Change.ts @@ -4,7 +4,7 @@ export class Change { - ___nsuri: string = "http://specmate.com/20180925/model/history"; + ___nsuri: string = "http://specmate.com/20181108/model/history"; public url: string; public className: string = "Change"; public static className: string = "Change"; diff --git a/web/src/app/model/Folder.ts b/web/src/app/model/Folder.ts index 8a4c1f3e5..6e8431d47 100644 --- a/web/src/app/model/Folder.ts +++ b/web/src/app/model/Folder.ts @@ -4,7 +4,7 @@ export class Folder { - ___nsuri: string = "http://specmate.com/20180925/model/base"; + ___nsuri: string = "http://specmate.com/20181108/model/base"; public url: string; public className: string = "Folder"; public static className: string = "Folder"; diff --git a/web/src/app/model/History.ts b/web/src/app/model/History.ts index 3966decd2..f399c65a4 100644 --- a/web/src/app/model/History.ts +++ b/web/src/app/model/History.ts @@ -5,7 +5,7 @@ export class History { - ___nsuri: string = "http://specmate.com/20180925/model/history"; + ___nsuri: string = "http://specmate.com/20181108/model/history"; public url: string; public className: string = "History"; public static className: string = "History"; diff --git a/web/src/app/model/HistoryEntry.ts b/web/src/app/model/HistoryEntry.ts index 5a2850add..cbe17494c 100644 --- a/web/src/app/model/HistoryEntry.ts +++ b/web/src/app/model/HistoryEntry.ts @@ -5,7 +5,7 @@ export class HistoryEntry { - ___nsuri: string = "http://specmate.com/20180925/model/history"; + ___nsuri: string = "http://specmate.com/20181108/model/history"; public url: string; public className: string = "HistoryEntry"; public static className: string = "HistoryEntry"; @@ -17,7 +17,7 @@ public comment: EString; // References - + // Containment public changes: Change[]; diff --git a/web/src/app/model/IExternal.ts b/web/src/app/model/IExternal.ts index 7a37f455e..91862ce9d 100644 --- a/web/src/app/model/IExternal.ts +++ b/web/src/app/model/IExternal.ts @@ -4,7 +4,7 @@ export class IExternal { - ___nsuri: string = "http://specmate.com/20180925/model/base"; + ___nsuri: string = "http://specmate.com/20181108/model/base"; public url: string; public className: string = "IExternal"; public static className: string = "IExternal"; diff --git a/web/src/app/model/IModelConnection.ts b/web/src/app/model/IModelConnection.ts index 1bf42ca42..2846eff66 100644 --- a/web/src/app/model/IModelConnection.ts +++ b/web/src/app/model/IModelConnection.ts @@ -4,7 +4,7 @@ export class IModelConnection { - ___nsuri: string = "http://specmate.com/20180925/model/base"; + ___nsuri: string = "http://specmate.com/20181108/model/base"; public url: string; public className: string = "IModelConnection"; public static className: string = "IModelConnection"; diff --git a/web/src/app/model/IModelNode.ts b/web/src/app/model/IModelNode.ts index 19dafab59..84cbc2f54 100644 --- a/web/src/app/model/IModelNode.ts +++ b/web/src/app/model/IModelNode.ts @@ -4,7 +4,7 @@ export class IModelNode { - ___nsuri: string = "http://specmate.com/20180925/model/base"; + ___nsuri: string = "http://specmate.com/20181108/model/base"; public url: string; public className: string = "IModelNode"; public static className: string = "IModelNode"; diff --git a/web/src/app/model/ITracingElement.ts b/web/src/app/model/ITracingElement.ts index 2bc407f5b..337329d01 100644 --- a/web/src/app/model/ITracingElement.ts +++ b/web/src/app/model/ITracingElement.ts @@ -4,7 +4,7 @@ export class ITracingElement { - ___nsuri: string = "http://specmate.com/20180925/model/base"; + ___nsuri: string = "http://specmate.com/20181108/model/base"; public url: string; public className: string = "ITracingElement"; public static className: string = "ITracingElement"; diff --git a/web/src/app/model/Operation.ts b/web/src/app/model/Operation.ts index 6d62826c8..12cd9712b 100644 --- a/web/src/app/model/Operation.ts +++ b/web/src/app/model/Operation.ts @@ -5,7 +5,7 @@ export class Operation { - ___nsuri: string = "http://specmate.com/20180925/model/batch"; + ___nsuri: string = "http://specmate.com/20181108/model/batch"; public url: string; public className: string = "Operation"; public static className: string = "Operation"; diff --git a/web/src/app/model/ParameterAssignment.ts b/web/src/app/model/ParameterAssignment.ts index f26df2d42..638cbcc70 100644 --- a/web/src/app/model/ParameterAssignment.ts +++ b/web/src/app/model/ParameterAssignment.ts @@ -4,7 +4,7 @@ export class ParameterAssignment { - ___nsuri: string = "http://specmate.com/20180925/model/testspecification"; + ___nsuri: string = "http://specmate.com/20181108/model/testspecification"; public url: string; public className: string = "ParameterAssignment"; public static className: string = "ParameterAssignment"; diff --git a/web/src/app/model/Process.ts b/web/src/app/model/Process.ts index 6f168160f..eb5bf4b09 100644 --- a/web/src/app/model/Process.ts +++ b/web/src/app/model/Process.ts @@ -4,7 +4,7 @@ export class Process { - ___nsuri: string = "http://specmate.com/20180925/model/processes"; + ___nsuri: string = "http://specmate.com/20181108/model/processes"; public url: string; public className: string = "Process"; public static className: string = "Process"; diff --git a/web/src/app/model/ProcessConnection.ts b/web/src/app/model/ProcessConnection.ts index 9761711f5..e5a968c50 100644 --- a/web/src/app/model/ProcessConnection.ts +++ b/web/src/app/model/ProcessConnection.ts @@ -4,7 +4,7 @@ export class ProcessConnection { - ___nsuri: string = "http://specmate.com/20180925/model/processes"; + ___nsuri: string = "http://specmate.com/20181108/model/processes"; public url: string; public className: string = "ProcessConnection"; public static className: string = "ProcessConnection"; diff --git a/web/src/app/model/ProcessDecision.ts b/web/src/app/model/ProcessDecision.ts index 4fe298ca8..03ab16a14 100644 --- a/web/src/app/model/ProcessDecision.ts +++ b/web/src/app/model/ProcessDecision.ts @@ -4,7 +4,7 @@ export class ProcessDecision { - ___nsuri: string = "http://specmate.com/20180925/model/processes"; + ___nsuri: string = "http://specmate.com/20181108/model/processes"; public url: string; public className: string = "ProcessDecision"; public static className: string = "ProcessDecision"; diff --git a/web/src/app/model/ProcessEnd.ts b/web/src/app/model/ProcessEnd.ts index fc78a3aa6..75ef43941 100644 --- a/web/src/app/model/ProcessEnd.ts +++ b/web/src/app/model/ProcessEnd.ts @@ -4,7 +4,7 @@ export class ProcessEnd { - ___nsuri: string = "http://specmate.com/20180925/model/processes"; + ___nsuri: string = "http://specmate.com/20181108/model/processes"; public url: string; public className: string = "ProcessEnd"; public static className: string = "ProcessEnd"; diff --git a/web/src/app/model/ProcessNode.ts b/web/src/app/model/ProcessNode.ts index 6c3b4135e..c7895d551 100644 --- a/web/src/app/model/ProcessNode.ts +++ b/web/src/app/model/ProcessNode.ts @@ -4,7 +4,7 @@ export class ProcessNode { - ___nsuri: string = "http://specmate.com/20180925/model/processes"; + ___nsuri: string = "http://specmate.com/20181108/model/processes"; public url: string; public className: string = "ProcessNode"; public static className: string = "ProcessNode"; diff --git a/web/src/app/model/ProcessStart.ts b/web/src/app/model/ProcessStart.ts index 247071fc3..e3b355a57 100644 --- a/web/src/app/model/ProcessStart.ts +++ b/web/src/app/model/ProcessStart.ts @@ -4,7 +4,7 @@ export class ProcessStart { - ___nsuri: string = "http://specmate.com/20180925/model/processes"; + ___nsuri: string = "http://specmate.com/20181108/model/processes"; public url: string; public className: string = "ProcessStart"; public static className: string = "ProcessStart"; diff --git a/web/src/app/model/ProcessStep.ts b/web/src/app/model/ProcessStep.ts index 1ce2d8e14..608043e06 100644 --- a/web/src/app/model/ProcessStep.ts +++ b/web/src/app/model/ProcessStep.ts @@ -4,7 +4,7 @@ export class ProcessStep { - ___nsuri: string = "http://specmate.com/20180925/model/processes"; + ___nsuri: string = "http://specmate.com/20181108/model/processes"; public url: string; public className: string = "ProcessStep"; public static className: string = "ProcessStep"; diff --git a/web/src/app/model/Requirement.ts b/web/src/app/model/Requirement.ts index 30dec9053..099573a34 100644 --- a/web/src/app/model/Requirement.ts +++ b/web/src/app/model/Requirement.ts @@ -4,7 +4,7 @@ export class Requirement { - ___nsuri: string = "http://specmate.com/20180925/model/requirements"; + ___nsuri: string = "http://specmate.com/20181108/model/requirements"; public url: string; public className: string = "Requirement"; public static className: string = "Requirement"; diff --git a/web/src/app/model/Status.ts b/web/src/app/model/Status.ts index 476a4db31..3cf4cf847 100644 --- a/web/src/app/model/Status.ts +++ b/web/src/app/model/Status.ts @@ -4,7 +4,7 @@ export class Status { - ___nsuri: string = "http://specmate.com/20180925/model/administration"; + ___nsuri: string = "http://specmate.com/20181108/model/administration"; public url: string; public className: string = "Status"; public static className: string = "Status"; diff --git a/web/src/app/model/TestCase.ts b/web/src/app/model/TestCase.ts index 315ae6fa0..d1bbace93 100644 --- a/web/src/app/model/TestCase.ts +++ b/web/src/app/model/TestCase.ts @@ -4,7 +4,7 @@ export class TestCase { - ___nsuri: string = "http://specmate.com/20180925/model/testspecification"; + ___nsuri: string = "http://specmate.com/20181108/model/testspecification"; public url: string; public className: string = "TestCase"; public static className: string = "TestCase"; diff --git a/web/src/app/model/TestParameter.ts b/web/src/app/model/TestParameter.ts index 4e1c0bad2..591b89442 100644 --- a/web/src/app/model/TestParameter.ts +++ b/web/src/app/model/TestParameter.ts @@ -4,7 +4,7 @@ export class TestParameter { - ___nsuri: string = "http://specmate.com/20180925/model/testspecification"; + ___nsuri: string = "http://specmate.com/20181108/model/testspecification"; public url: string; public className: string = "TestParameter"; public static className: string = "TestParameter"; diff --git a/web/src/app/model/TestProcedure.ts b/web/src/app/model/TestProcedure.ts index 475069258..eb6b945d7 100644 --- a/web/src/app/model/TestProcedure.ts +++ b/web/src/app/model/TestProcedure.ts @@ -4,7 +4,7 @@ export class TestProcedure { - ___nsuri: string = "http://specmate.com/20180925/model/testspecification"; + ___nsuri: string = "http://specmate.com/20181108/model/testspecification"; public url: string; public className: string = "TestProcedure"; public static className: string = "TestProcedure"; diff --git a/web/src/app/model/TestSpecification.ts b/web/src/app/model/TestSpecification.ts index 5f8a78003..eae83491d 100644 --- a/web/src/app/model/TestSpecification.ts +++ b/web/src/app/model/TestSpecification.ts @@ -4,7 +4,7 @@ export class TestSpecification { - ___nsuri: string = "http://specmate.com/20180925/model/testspecification"; + ___nsuri: string = "http://specmate.com/20181108/model/testspecification"; public url: string; public className: string = "TestSpecification"; public static className: string = "TestSpecification"; diff --git a/web/src/app/model/TestSpecificationSkeleton.ts b/web/src/app/model/TestSpecificationSkeleton.ts new file mode 100644 index 000000000..2a4f493e1 --- /dev/null +++ b/web/src/app/model/TestSpecificationSkeleton.ts @@ -0,0 +1,23 @@ + import './support/gentypes'; + import { Proxy } from './support/proxy'; + + + export class TestSpecificationSkeleton { + + ___nsuri: string = "http://specmate.com/20181108/model/testspecification"; + public url: string; + public className: string = "TestSpecificationSkeleton"; + public static className: string = "TestSpecificationSkeleton"; + + // Attributes + public name: EString; + public language: EString; + public code: EString; + + // References + + // Containment + + + } + diff --git a/web/src/app/model/TestStep.ts b/web/src/app/model/TestStep.ts index 2e7bcfb0c..3045cf902 100644 --- a/web/src/app/model/TestStep.ts +++ b/web/src/app/model/TestStep.ts @@ -4,7 +4,7 @@ export class TestStep { - ___nsuri: string = "http://specmate.com/20180925/model/testspecification"; + ___nsuri: string = "http://specmate.com/20181108/model/testspecification"; public url: string; public className: string = "TestStep"; public static className: string = "TestStep"; diff --git a/web/src/app/model/User.ts b/web/src/app/model/User.ts index a860cedaa..0dd561fe9 100644 --- a/web/src/app/model/User.ts +++ b/web/src/app/model/User.ts @@ -4,13 +4,13 @@ export class User { - ___nsuri: string = "http://specmate.com/20180925/model/user"; + ___nsuri: string = "http://specmate.com/20181108/model/user"; public url: string; public className: string = "User"; public static className: string = "User"; // Attributes - public allowedUrls: EString; + public allowedUrls: EString[]; public userName: EString; public passWord: EString; public projectName: EString; diff --git a/web/src/app/model/UserSession.ts b/web/src/app/model/UserSession.ts index c36aa51dc..99b20fb42 100644 --- a/web/src/app/model/UserSession.ts +++ b/web/src/app/model/UserSession.ts @@ -4,7 +4,7 @@ export class UserSession { - ___nsuri: string = "http://specmate.com/20180925/model/user"; + ___nsuri: string = "http://specmate.com/20181108/model/user"; public url: string; public className: string = "UserSession"; public static className: string = "UserSession"; @@ -18,7 +18,6 @@ public TargetSystem: AccessRights; public libraryFolders: EString[]; - // References // Containment diff --git a/web/src/app/model/meta/field-meta.ts b/web/src/app/model/meta/field-meta.ts index e378686dd..04f135fa7 100644 --- a/web/src/app/model/meta/field-meta.ts +++ b/web/src/app/model/meta/field-meta.ts @@ -255,6 +255,15 @@ export class MetaInfo { rows: '8', position: '100' } ]; + public static TestSpecificationSkeleton: FieldMetaItem[] = [ + { + name: "name", + shortDesc: 'Name', + longDesc: '', + required: true, + type: 'text', + position: '0' + } ]; public static TestParameter: FieldMetaItem[] = [ { name: "name", diff --git a/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.html b/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.html index 7cccacffa..1a674dbae 100644 --- a/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.html +++ b/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.html @@ -1,7 +1,7 @@

-   -   -   -   +   +   +   +  
 {{'connection.lost' | translate}}
\ No newline at end of file diff --git a/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.ts b/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.ts index a6348f17e..09f3c58df 100644 --- a/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.ts +++ b/web/src/app/modules/actions/modules/common-controls/components/common-controls.component.ts @@ -1,9 +1,10 @@ import { Component } from '@angular/core'; -import { SpecmateDataService } from '../../../../data/modules/data-service/services/specmate-data.service'; -import { NavigatorService } from '../../../../navigation/modules/navigator/services/navigator.service'; -import { ValidationService } from '../../../../forms/modules/validation/services/validation.service'; import { TranslateService } from '@ngx-translate/core'; import { ServerConnectionService } from '../../../../common/modules/connection/services/server-connection-service'; +import { UISafe } from '../../../../common/modules/ui/ui-safe-decorator'; +import { SpecmateDataService } from '../../../../data/modules/data-service/services/specmate-data.service'; +import { ValidationService } from '../../../../forms/modules/validation/services/validation.service'; +import { NavigatorService } from '../../../../navigation/modules/navigator/services/navigator.service'; @Component({ moduleId: module.id.toString(), @@ -59,11 +60,16 @@ export class CommonControls { } public get isSaveEnabled(): boolean { - return this.isEnabled && this.dataService.hasCommits && this.validator.currentValid; + return this.isEnabled && this.hasCommits && this.validator.currentValid; } public get isUndoEnabled(): boolean { - return this.isEnabled && this.dataService.hasCommits; + return this.isEnabled && this.hasCommits; + } + + @UISafe() + private get hasCommits(): boolean { + return this.dataService.hasCommits; } public get isBackEnabled(): boolean { diff --git a/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.css b/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.css new file mode 100644 index 000000000..4311c5e7a --- /dev/null +++ b/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.css @@ -0,0 +1,4 @@ +.btn.btn-link { + padding: 0px; + margin: 0px; +} diff --git a/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.html b/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.html new file mode 100644 index 000000000..9d0500917 --- /dev/null +++ b/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.html @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.ts b/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.ts new file mode 100644 index 000000000..793da542f --- /dev/null +++ b/web/src/app/modules/actions/modules/export-testspecification-button/components/export-testspecification-button.component.ts @@ -0,0 +1,156 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { TestSpecification } from '../../../../../model/TestSpecification'; +import { TestCase } from '../../../../../model/TestCase'; +import { TestParameter } from '../../../../../model/TestParameter'; +import { ParameterAssignment } from '../../../../../model/ParameterAssignment'; +import { Url } from '../../../../../util/url'; +import { Type } from '../../../../../util/type'; +import { IContainer } from '../../../../../model/IContainer'; +import { SpecmateDataService } from '../../../../data/modules/data-service/services/specmate-data.service'; +import { ValidationService } from '../../../../forms/modules/validation/services/validation.service'; +import { TranslateService } from '@ngx-translate/core'; +import { AuthenticationService } from '../../../../views/main/authentication/modules/auth/services/authentication.service'; +import { saveAs } from 'file-saver'; + +@Component({ + moduleId: module.id.toString(), + selector: 'export-testspecification-button', + templateUrl: 'export-testspecification-button.component.html', + styleUrls: ['export-testspecification-button.component.css'] +}) + +export class ExportTestspecificationButton { + + @Input() + public testSpecification: TestSpecification; + + private contents: IContainer[]; + private testCases: TestCase[]; + private testParameters: TestParameter[]; + private parameterAssignments: ParameterAssignment[]; + private finalCsvString: string; + + constructor( + private dataService: SpecmateDataService, + private validation: ValidationService) { } + + // Export Function + public async exportTestSpecification(): Promise { + if (!this.enabled) { + return; + } + const contents = await this.dataService.readContents(this.testSpecification.url); + this.contents = contents; + await this.loadTestParameters(); + await this.loadTestCases(); + await Promise.all(this.loadParameterAssignments()); + this.prepareExportString(); + this.createDownloadFile(); + } + + private prepareExportString(): void { + this.pushHeaders(); + this.pushRows(); + } + + private pushHeaders(): void { + let header = 'Test Cases,'; + if (this.testParameters) { + for (let i = 0 ; i < this.testParameters.length ; i++) { + if (this.testParameters[i].type == 'INPUT') { + header += this.testParameters[i].type + ' - ' + this.testParameters[i].name + ', '; + } + } + for (let i = 0 ; i < this.testParameters.length ; i++) { + if (this.testParameters[i].type == 'OUTPUT') { + header += this.testParameters[i].type + ' - ' + this.testParameters[i].name + ', '; + } + } + } + header += '\n'; + this.finalCsvString = header; + } + + private pushRows(): void { + let testCasesString = ''; + if (this.testCases) { + for (let i = 0 ; i < this.testCases.length ; i++) { + testCasesString += this.testCases[i].name + ', '; + for (let j = 0 ; j < this.testParameters.length; j++) { + let assignmentsList = this.getAssignments(this.testParameters[j]); + for (let k = 0 ; k < assignmentsList.length; k++) { + if (Url.parent(assignmentsList[k].url) == this.testCases[i].url) { + testCasesString += assignmentsList[k].condition + ', '; + break; + } + } + } + testCasesString += '\n'; + } + } + this.finalCsvString += testCasesString; + } + private getAssignments(testParameter: TestParameter): ParameterAssignment[] { + let assignmentsList: ParameterAssignment[]; + assignmentsList = []; + for (let i = 0 ; i < this.parameterAssignments.length; i++) { + if (this.parameterAssignments[i].parameter.url == testParameter.url) { + assignmentsList.push(this.parameterAssignments[i]); + } + } + return assignmentsList; + } + + private loadTestCases(): void { + this.testCases = this.contents.filter((element: IContainer) => Type.is(element, TestCase)) + .map((element: IContainer) => element as TestCase); + } + + private loadTestParameters(): Promise { + let loadTestParametersTask: Promise = Promise.resolve(); + loadTestParametersTask = loadTestParametersTask.then(() => { + this.testParameters = this.contents.filter((element: IContainer) => Type.is(element, TestParameter)) + .map((element: IContainer) => element as TestParameter); + }); + return loadTestParametersTask; + } + + private loadParameterAssignments(): Promise[] { + let testCases: TestCase[] = this.testCases; + this.parameterAssignments = []; + let promiseArray: Promise[]; + promiseArray = []; + + let loadParameterAssignmentsTask: Promise = Promise.resolve(); + for (let i = 0; i < testCases.length; i++) { + let currentTestCase: TestCase = testCases[i]; + loadParameterAssignmentsTask = loadParameterAssignmentsTask.then(() => { + return this.dataService.readContents(currentTestCase.url) + .then((contents: IContainer[]) => + contents.forEach((element: IContainer) => { + if (element.className == 'ParameterAssignment') { + this.parameterAssignments.push(element as ParameterAssignment); + } + })); + }); + promiseArray.push(loadParameterAssignmentsTask); + } + return promiseArray; + } + + private createDownloadFile(): void { + const blob = new Blob(['\ufeff', this.finalCsvString], { type: 'text/csv;charset=utf-8;' }); + saveAs(blob, this.testSpecification.name + '.csv'); + } + + public get enabled(): boolean { + return this.isValid(); + } + + private isValid(): boolean { + if (this.testSpecification === undefined) { + return false; + } + return this.validation.isValid(this.testSpecification, this.contents); + } +} diff --git a/web/src/app/modules/actions/modules/export-testspecification-button/export-testspecification-button.module.ts b/web/src/app/modules/actions/modules/export-testspecification-button/export-testspecification-button.module.ts new file mode 100644 index 000000000..75f2789ae --- /dev/null +++ b/web/src/app/modules/actions/modules/export-testspecification-button/export-testspecification-button.module.ts @@ -0,0 +1,28 @@ +import { NgModule } from '@angular/core'; +import { ExportTestspecificationButton } from './components/export-testspecification-button.component'; +import { BrowserModule } from '@angular/platform-browser'; +import { TranslateModule } from '@ngx-translate/core'; + +@NgModule({ + imports: [ + // MODULE IMPORTS + BrowserModule, + TranslateModule + ], + declarations: [ + // COMPONENTS IN THIS MODULE + ExportTestspecificationButton + ], + exports: [ + // THE COMPONENTS VISIBLE TO THE OUTSIDE + ExportTestspecificationButton + ], + providers: [ + // SERVICES + ], + bootstrap: [ + // COMPONENTS THAT ARE BOOTSTRAPPED HERE + ] +}) + +export class ExportTestspecificationButtonModule { } diff --git a/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.css b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.css new file mode 100644 index 000000000..4311c5e7a --- /dev/null +++ b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.css @@ -0,0 +1,4 @@ +.btn.btn-link { + padding: 0px; + margin: 0px; +} diff --git a/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.html b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.html new file mode 100644 index 000000000..d36315e8f --- /dev/null +++ b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.html @@ -0,0 +1 @@ + diff --git a/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.ts b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.ts new file mode 100644 index 000000000..1c6ac5838 --- /dev/null +++ b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/components/get-test-specification-skeleton-button.component.ts @@ -0,0 +1,64 @@ +import { Component, Input } from '@angular/core'; +import { SpecmateDataService } from '../../../../data/modules/data-service/services/specmate-data.service'; +import { TestSpecification } from '../../../../../model/TestSpecification'; +import { TranslateService } from '@ngx-translate/core'; +import { saveAs } from 'file-saver'; +import { LowerCasePipe } from '@angular/common'; +import { TestSpecificationSkeleton } from '../../../../../model/TestSpecificationSkeleton'; + +@Component({ + moduleId: module.id.toString(), + selector: 'get-test-specification-skeleton-button', + templateUrl: 'get-test-specification-skeleton-button.component.html', + styleUrls: ['get-test-specification-skeleton-button.component.css'] +}) + +export class GetTestSpecificationSkeletonButton { + + private _testspecification: TestSpecification; + + private _lang: string; + + @Input() + public set testspecification(testspecification: TestSpecification) { + if (!testspecification) { + return; + } + this._testspecification = testspecification; + } + + @Input() + public set language(lang: string) { + this._lang = lang; + } + + constructor(private dataService: SpecmateDataService, + private translate: TranslateService) { } + + public async getskeleton(): Promise { + if (!this.enabled) { + return; + } + + const data: TestSpecificationSkeleton = await this.dataService.performQuery(this._testspecification.url, 'generateTestSkeleton', + { language: new LowerCasePipe().transform(this._lang)}); + + if (data === undefined) { + throw new Error('Could not load test specification skeleton for ' + this._lang); + } + + saveAs(new Blob([data.code], {type: 'text/plain;charset=utf-8'}), data.name); + } + + public get language(): string { + return this._lang; + } + + public get enabled(): boolean { + if (this._testspecification === undefined) { + return false; + } + + return true; + } +} diff --git a/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/get-test-specification-skeleton-button.module.ts b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/get-test-specification-skeleton-button.module.ts new file mode 100644 index 000000000..00bdb6cc0 --- /dev/null +++ b/web/src/app/modules/actions/modules/get-test-specification-skeleton-button/get-test-specification-skeleton-button.module.ts @@ -0,0 +1,28 @@ +import { NgModule } from '@angular/core'; +import { GetTestSpecificationSkeletonButton } from './components/get-test-specification-skeleton-button.component'; +import { BrowserModule } from '@angular/platform-browser'; +import { TranslateModule } from '@ngx-translate/core'; + +@NgModule({ + imports: [ + // MODULE IMPORTS + BrowserModule, + TranslateModule + ], + declarations: [ + // COMPONENTS IN THIS MODULE + GetTestSpecificationSkeletonButton + ], + exports: [ + // THE COMPONENTS VISIBLE TO THE OUTSIDE + GetTestSpecificationSkeletonButton + ], + providers: [ + // SERVICES + ], + bootstrap: [ + // COMPONENTS THAT ARE BOOTSTRAPPED HERE + ] +}) + +export class GetTestSpecificationSkeletonButtonModule { } diff --git a/web/src/app/modules/actions/modules/test-specification-generator-button/components/test-specification-generator-button.component.ts b/web/src/app/modules/actions/modules/test-specification-generator-button/components/test-specification-generator-button.component.ts index 20343d87c..1c5f472c5 100644 --- a/web/src/app/modules/actions/modules/test-specification-generator-button/components/test-specification-generator-button.component.ts +++ b/web/src/app/modules/actions/modules/test-specification-generator-button/components/test-specification-generator-button.component.ts @@ -9,14 +9,6 @@ import { TestSpecification } from '../../../../../model/TestSpecification'; import { Id } from '../../../../../util/id'; import { Url } from '../../../../../util/url'; import { Config } from '../../../../../config/config'; -import { Type } from '../../../../../util/type'; -import { CEGNode } from '../../../../../model/CEGNode'; -import { ProcessStart } from '../../../../../model/ProcessStart'; -import { ProcessEnd } from '../../../../../model/ProcessEnd'; -import { IModelNode } from '../../../../../model/IModelNode'; -import { ProcessStep } from '../../../../../model/ProcessStep'; -import { ProcessConnection } from '../../../../../model/ProcessConnection'; -import { ProcessDecision } from '../../../../../model/ProcessDecision'; import { ValidationService } from '../../../../forms/modules/validation/services/validation.service'; import { ValidationResult } from '../../../../../validation/validation-result'; import { TranslateService } from '@ngx-translate/core'; diff --git a/web/src/app/modules/common/modules/ui/ui-safe-decorator.ts b/web/src/app/modules/common/modules/ui/ui-safe-decorator.ts new file mode 100644 index 000000000..1f1a9738d --- /dev/null +++ b/web/src/app/modules/common/modules/ui/ui-safe-decorator.ts @@ -0,0 +1,33 @@ +/** + * Adding @UISafe() to a getter delays changes to the underlying value until the next update cycle. + * This prevents ExpressionChangedAfterItHasBeenCheckedErrors + */ +export function UISafe(): MethodDecorator { + return function(target: any, propertyKey: string| symbol, descriptor: PropertyDescriptor) { + let originalMethod = descriptor.get; + if (!originalMethod) { + throw new Error('@UISafe can only decorate getters.'); + } + if (!descriptor.configurable) { + throw new Error('@UISafe target must be configurable.'); + } + let oldValue: any = undefined; + let firstCall = true; + descriptor.get = function() { + let context = this; + let args = arguments; + let newValue = originalMethod.apply(context, args); + if (firstCall) { + oldValue = newValue; + firstCall = false; + } + if (oldValue !== newValue) { + setTimeout(() => { + oldValue = newValue; + }); + } + return oldValue; + }; + return descriptor; + }; +} diff --git a/web/src/app/modules/data/modules/data-service/services/specmate-data.service.ts b/web/src/app/modules/data/modules/data-service/services/specmate-data.service.ts index ad679f9c5..96558ee36 100644 --- a/web/src/app/modules/data/modules/data-service/services/specmate-data.service.ts +++ b/web/src/app/modules/data/modules/data-service/services/specmate-data.service.ts @@ -43,6 +43,7 @@ export class SpecmateDataService { } public stateChanged: EventEmitter; + public committed: EventEmitter; private cache: DataCache = new DataCache(); private serviceInterface: ServiceInterface; @@ -57,6 +58,7 @@ export class SpecmateDataService { this.serviceInterface = new ServiceInterface(http); this.scheduler = new Scheduler(this, this.logger, this.translate); this.stateChanged = new EventEmitter(); + this.committed = new EventEmitter(); this.auth.authChanged.subscribe(() => { if (!this.auth.isAuthenticated) { @@ -190,6 +192,7 @@ export class SpecmateDataService { this.scheduler.resolveBatchOperation(batchOperation); this.scheduler.clearCommits(); this.busy = false; + this.committed.emit(); } public undo(): void { diff --git a/web/src/app/modules/forms/modules/generic-form/components/generic-form.component.ts b/web/src/app/modules/forms/modules/generic-form/components/generic-form.component.ts index 9a0a1dae1..f7515827b 100644 --- a/web/src/app/modules/forms/modules/generic-form/components/generic-form.component.ts +++ b/web/src/app/modules/forms/modules/generic-form/components/generic-form.component.ts @@ -142,7 +142,8 @@ export class GenericForm { updateValue = converter.convertFromControlToModel(updateValue); } // We do not need to clone here (hopefully), because only simple values can be passed via forms. - if (this.element[fieldName] + '' !== updateValue + '') { + const originalValue = this.element[fieldName] || ''; + if (originalValue !== updateValue + '') { this.element[fieldName] = updateValue; changed = true; } diff --git a/web/src/app/modules/specmate/components/specmate.component.html b/web/src/app/modules/specmate/components/specmate.component.html index d38a35479..4a9447cc6 100644 --- a/web/src/app/modules/specmate/components/specmate.component.html +++ b/web/src/app/modules/specmate/components/specmate.component.html @@ -1,5 +1,8 @@ -
+ +
@@ -16,7 +19,7 @@ - + diff --git a/web/src/app/modules/views/main/authentication/modules/login/components/login.component.html b/web/src/app/modules/views/main/authentication/modules/login/components/login.component.html index 44e9fec42..b6296fa15 100644 --- a/web/src/app/modules/views/main/authentication/modules/login/components/login.component.html +++ b/web/src/app/modules/views/main/authentication/modules/login/components/login.component.html @@ -62,4 +62,4 @@

{{'login' | translate}}

- \ No newline at end of file + diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/base/contents-container-base.ts b/web/src/app/modules/views/main/editors/modules/contents-container/base/contents-container-base.ts index e88f249b9..6817d572a 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/base/contents-container-base.ts +++ b/web/src/app/modules/views/main/editors/modules/contents-container/base/contents-container-base.ts @@ -4,7 +4,10 @@ import { TranslateService } from '@ngx-translate/core'; import { IContainer } from '../../../../../../../model/IContainer'; import { ConfirmationModal } from '../../../../../../notification/modules/modals/services/confirmation-modal.service'; import { Id } from '../../../../../../../util/id'; -import { OnInit, Input } from '@angular/core'; +import { OnInit, Input, Type } from '@angular/core'; +import { Objects } from '../../../../../../../util/objects'; +import { ClipboardService } from '../../tool-pallette/services/clipboard-service'; +import { GraphTransformer } from '../../tool-pallette/util/graphTransformer'; export abstract class ContentContainerBase implements OnInit { @@ -27,7 +30,8 @@ export abstract class ContentContainerBase implements OnIn protected dataService: SpecmateDataService, protected navigator: NavigatorService, protected translate: TranslateService, - protected modal: ConfirmationModal) { + protected modal: ConfirmationModal, + private clipboardService: ClipboardService) { } public async ngOnInit(): Promise { @@ -64,4 +68,50 @@ export abstract class ContentContainerBase implements OnIn const contents = await this.dataService.readContents(this.parent.url, false); this.contents = contents.filter(this.condition); } + + private get clipboardModel(): IContainer { + if (this.canPaste) { + return this.clipboardService.clipboard[0] as IContainer; + } + return undefined; + } + + public get clipboardModelName(): string { + if (this.canPaste) { + return this.clipboardModel.name; + } + return this.translate.instant('pasteAsName'); + } + + public async copy(model: IContainer): Promise { + const copy = Objects.clone(model) as IContainer; + copy.description = model.description; + copy.id = Id.uuid; + copy.name = this.translate.instant('copyOf') + ' ' + model.name; + this.clipboardService.clipboard = [copy]; + } + + public async paste(name: string): Promise { + if (!this.canPaste) { + return; + } + const model = this.clipboardModel; + const pasteName = name || this.clipboardModelName; + const copy = await this.createElement(pasteName); + copy.description = model.description; + + const contents = await this.dataService.readContents(model.url, true); + const transformer = new GraphTransformer(this.dataService, undefined, copy); + + const compoundId = Id.uuid; + await this.dataService.updateElement(copy, true, compoundId); + await transformer.cloneSubgraph(contents, compoundId, true); + await this.dataService.commit(this.translate.instant('paste')); + await this.readContents(); + this.clipboardService.clear(); + } + + public get canPaste(): boolean { + return this.clipboardService.clipboard.length === 1 && this.condition(this.clipboardService.clipboard[0]); + } } diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/base/testspecification-generatable-content-container-base.ts b/web/src/app/modules/views/main/editors/modules/contents-container/base/testspecification-generatable-content-container-base.ts new file mode 100644 index 000000000..beb63dcbf --- /dev/null +++ b/web/src/app/modules/views/main/editors/modules/contents-container/base/testspecification-generatable-content-container-base.ts @@ -0,0 +1,26 @@ +import { ContentContainerBase } from './contents-container-base'; +import { IContainer } from '../../../../../../../model/IContainer'; +import { SpecmateDataService } from '../../../../../../data/modules/data-service/services/specmate-data.service'; +import { NavigatorService } from '../../../../../../navigation/modules/navigator/services/navigator.service'; +import { TranslateService } from '@ngx-translate/core'; +import { ConfirmationModal } from '../../../../../../notification/modules/modals/services/confirmation-modal.service'; +import { ClipboardService } from '../../tool-pallette/services/clipboard-service'; +import { AdditionalInformationService } from '../../../../../side/modules/links-actions/services/additional-information.service'; + +export abstract class TestSpecificationContentContainerBase extends ContentContainerBase { + + constructor( + dataService: SpecmateDataService, + navigator: NavigatorService, + translate: TranslateService, + modal: ConfirmationModal, + clipboardService: ClipboardService, + protected additionalInformationService: AdditionalInformationService) { + super(dataService, navigator, translate, modal, clipboardService); + } + + public get canGenerateTestSpecification(): boolean { + return this.additionalInformationService.canGenerateTestSpecifications; + } + +} diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.html b/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.html index f14fc7325..0fad520b6 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.html +++ b/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.html @@ -20,13 +20,18 @@
{{'Cause-EffectModels' | translate}}
{{element.description | truncate: 60}} - - - + @@ -41,13 +46,24 @@
{{'Cause-EffectModels' | translate}}
-
+
+
+ +
+ +
+
+
\ No newline at end of file diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.ts b/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.ts index f6db7cb04..be2051d06 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.ts +++ b/web/src/app/modules/views/main/editors/modules/contents-container/components/ceg-model-container.component.ts @@ -10,6 +10,9 @@ import { NavigatorService } from '../../../../../../navigation/modules/navigator import { TranslateService } from '@ngx-translate/core'; import { ConfirmationModal } from '../../../../../../notification/modules/modals/services/confirmation-modal.service'; import { Id } from '../../../../../../../util/id'; +import { ClipboardService } from '../../tool-pallette/services/clipboard-service'; +import { TestSpecificationContentContainerBase } from '../base/testspecification-generatable-content-container-base'; +import { AdditionalInformationService } from '../../../../../side/modules/links-actions/services/additional-information.service'; @Component({ moduleId: module.id.toString(), @@ -18,10 +21,15 @@ import { Id } from '../../../../../../../util/id'; styleUrls: ['ceg-model-container.component.css'] }) -export class CEGModelContainer extends ContentContainerBase { +export class CEGModelContainer extends TestSpecificationContentContainerBase { - constructor(dataService: SpecmateDataService, navigator: NavigatorService, translate: TranslateService, modal: ConfirmationModal) { - super(dataService, navigator, translate, modal); + constructor(dataService: SpecmateDataService, + navigator: NavigatorService, + translate: TranslateService, + modal: ConfirmationModal, + clipboardService: ClipboardService, + additionalInformationService: AdditionalInformationService) { + super(dataService, navigator, translate, modal, clipboardService, additionalInformationService); } protected condition = (element: IContainer) => Type.is(element, CEGModel); diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/components/folder-container.component.ts b/web/src/app/modules/views/main/editors/modules/contents-container/components/folder-container.component.ts index 29935adf4..3ae2bba06 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/components/folder-container.component.ts +++ b/web/src/app/modules/views/main/editors/modules/contents-container/components/folder-container.component.ts @@ -9,6 +9,7 @@ import { ConfirmationModal } from '../../../../../../notification/modules/modals import { Id } from '../../../../../../../util/id'; import { Folder } from '../../../../../../../model/Folder'; import { FolderFactory } from '../../../../../../../factory/folder-factory'; +import { ClipboardService } from '../../tool-pallette/services/clipboard-service'; @Component({ moduleId: module.id.toString(), @@ -19,8 +20,12 @@ import { FolderFactory } from '../../../../../../../factory/folder-factory'; export class FolderContainer extends ContentContainerBase { - constructor(dataService: SpecmateDataService, navigator: NavigatorService, translate: TranslateService, modal: ConfirmationModal) { - super(dataService, navigator, translate, modal); + constructor(dataService: SpecmateDataService, + navigator: NavigatorService, + translate: TranslateService, + modal: ConfirmationModal, + clipboardService: ClipboardService) { + super(dataService, navigator, translate, modal, clipboardService); } protected condition = (element: IContainer) => Type.is(element, Folder); diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.html b/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.html index b29d693a9..337c7b63f 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.html +++ b/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.html @@ -20,13 +20,18 @@
{{'ProcessModels' | translate}}
{{element.description | truncate: 60}} - - - + @@ -41,13 +46,25 @@
{{'ProcessModels' | translate}}
-
+
+
+ +
+ +
+
+
\ No newline at end of file diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.ts b/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.ts index abd631553..be4f3606e 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.ts +++ b/web/src/app/modules/views/main/editors/modules/contents-container/components/process-model-container.component.ts @@ -10,6 +10,9 @@ import { NavigatorService } from '../../../../../../navigation/modules/navigator import { TranslateService } from '@ngx-translate/core'; import { ConfirmationModal } from '../../../../../../notification/modules/modals/services/confirmation-modal.service'; import { Id } from '../../../../../../../util/id'; +import { ClipboardService } from '../../tool-pallette/services/clipboard-service'; +import { TestSpecificationContentContainerBase } from '../base/testspecification-generatable-content-container-base'; +import { AdditionalInformationService } from '../../../../../side/modules/links-actions/services/additional-information.service'; @Component({ moduleId: module.id.toString(), @@ -18,10 +21,15 @@ import { Id } from '../../../../../../../util/id'; styleUrls: ['process-model-container.component.css'] }) -export class ProcessModelContainer extends ContentContainerBase { +export class ProcessModelContainer extends TestSpecificationContentContainerBase { - constructor(dataService: SpecmateDataService, navigator: NavigatorService, translate: TranslateService, modal: ConfirmationModal) { - super(dataService, navigator, translate, modal); + constructor(dataService: SpecmateDataService, + navigator: NavigatorService, + translate: TranslateService, + modal: ConfirmationModal, + additionalInformationService: AdditionalInformationService, + clipboardService: ClipboardService) { + super(dataService, navigator, translate, modal, clipboardService, additionalInformationService); } protected condition = (element: IContainer) => Type.is(element, Process); diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/components/related-requirements-container.component.ts b/web/src/app/modules/views/main/editors/modules/contents-container/components/related-requirements-container.component.ts index 0e00f9a2b..e7a5f5152 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/components/related-requirements-container.component.ts +++ b/web/src/app/modules/views/main/editors/modules/contents-container/components/related-requirements-container.component.ts @@ -1,17 +1,13 @@ import { Component, Input } from '@angular/core'; import { ContentContainerBase } from '../base/contents-container-base'; import { IContainer } from '../../../../../../../model/IContainer'; -import { ModelFactoryBase } from '../../../../../../../factory/model-factory-base'; -import { Type } from '../../../../../../../util/type'; -import { Process } from '../../../../../../../model/Process'; -import { ProcessFactory } from '../../../../../../../factory/process-factory'; import { SpecmateDataService } from '../../../../../../data/modules/data-service/services/specmate-data.service'; import { NavigatorService } from '../../../../../../navigation/modules/navigator/services/navigator.service'; import { TranslateService } from '@ngx-translate/core'; import { ConfirmationModal } from '../../../../../../notification/modules/modals/services/confirmation-modal.service'; -import { Id } from '../../../../../../../util/id'; import { Requirement } from '../../../../../../../model/Requirement'; import { Sort } from '../../../../../../../util/sort'; +import { ClipboardService } from '../../tool-pallette/services/clipboard-service'; @Component({ moduleId: module.id.toString(), @@ -22,8 +18,12 @@ import { Sort } from '../../../../../../../util/sort'; export class RelatedRequirementsContainer extends ContentContainerBase { - constructor(dataService: SpecmateDataService, navigator: NavigatorService, translate: TranslateService, modal: ConfirmationModal) { - super(dataService, navigator, translate, modal); + constructor(dataService: SpecmateDataService, + navigator: NavigatorService, + translate: TranslateService, + modal: ConfirmationModal, + clipboardService: ClipboardService) { + super(dataService, navigator, translate, modal, clipboardService); } protected condition = (element: IContainer) => true; diff --git a/web/src/app/modules/views/main/editors/modules/contents-container/components/test-specification-container.component.html b/web/src/app/modules/views/main/editors/modules/contents-container/components/test-specification-container.component.html index 09a6653cb..2c8d09666 100644 --- a/web/src/app/modules/views/main/editors/modules/contents-container/components/test-specification-container.component.html +++ b/web/src/app/modules/views/main/editors/modules/contents-container/components/test-specification-container.component.html @@ -22,7 +22,7 @@
{{'TestSpecifications' | translate}}
  - \ No newline at end of file diff --git a/web/src/app/modules/views/main/editors/modules/tool-pallette/services/clipboard-service.ts b/web/src/app/modules/views/main/editors/modules/tool-pallette/services/clipboard-service.ts new file mode 100644 index 000000000..6db7d22af --- /dev/null +++ b/web/src/app/modules/views/main/editors/modules/tool-pallette/services/clipboard-service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { IContainer } from '../../../../../../../model/IContainer'; + +@Injectable() +export class ClipboardService { + + constructor() {} + + private static _clipboard: IContainer[] = []; + public get clipboard(): IContainer[] { + return ClipboardService._clipboard; + } + + public set clipboard(newClip: IContainer[]) { + if (!newClip) { + newClip = []; + } + ClipboardService._clipboard = newClip; + } + + public hasClipboard(): boolean { + return ClipboardService._clipboard.length > 0; + } + + public clear(): void { + ClipboardService._clipboard = []; + } +} diff --git a/web/src/app/modules/views/main/editors/modules/tool-pallette/services/editor-tools.service.ts b/web/src/app/modules/views/main/editors/modules/tool-pallette/services/editor-tools.service.ts index 0a6618085..fe86ad8fa 100644 --- a/web/src/app/modules/views/main/editors/modules/tool-pallette/services/editor-tools.service.ts +++ b/web/src/app/modules/views/main/editors/modules/tool-pallette/services/editor-tools.service.ts @@ -7,6 +7,7 @@ import { ToolProvider } from '../../graphical-editor/providers/properties/tool-p import { ToolBase } from '../tools/tool-base'; import { TranslateService } from '@ngx-translate/core'; import { MultiselectionService } from './multiselection.service'; +import { ClipboardService } from './clipboard-service'; @Injectable() @@ -23,7 +24,8 @@ export class EditorToolsService { private navigator: NavigatorService, private selectedElementService: SelectedElementService, private translate: TranslateService, - private rectService: MultiselectionService) { + private rectService: MultiselectionService, + private clipboardService: ClipboardService) { this.init(this.navigator.currentElement); this.navigator.hasNavigated.subscribe((model: IContainer) => this.init(model)); } @@ -45,7 +47,7 @@ export class EditorToolsService { } if (!this.providerMap[this.model.url]) { this.providerMap[this.model.url] = new ToolProvider(this.model, this.dataService, - this.selectedElementService, this.translate, this.rectService); + this.selectedElementService, this.translate, this.rectService, this.clipboardService); } return this.providerMap[this.model.url]; } diff --git a/web/src/app/modules/views/main/editors/modules/tool-pallette/tool-pallette.module.ts b/web/src/app/modules/views/main/editors/modules/tool-pallette/tool-pallette.module.ts index fd4fca422..ce91c5fe8 100644 --- a/web/src/app/modules/views/main/editors/modules/tool-pallette/tool-pallette.module.ts +++ b/web/src/app/modules/views/main/editors/modules/tool-pallette/tool-pallette.module.ts @@ -4,6 +4,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { EditorToolsService } from './services/editor-tools.service'; import { TranslateModule } from '@ngx-translate/core'; import { MultiselectionService } from './services/multiselection.service'; +import { ClipboardService } from './services/clipboard-service'; @NgModule({ imports: [ @@ -22,7 +23,8 @@ import { MultiselectionService } from './services/multiselection.service'; providers: [ // SERVICES EditorToolsService, - MultiselectionService + MultiselectionService, + ClipboardService ], bootstrap: [ // COMPONENTS THAT ARE BOOTSTRAPPED HERE diff --git a/web/src/app/modules/views/main/editors/modules/tool-pallette/tools/common/select-tool.ts b/web/src/app/modules/views/main/editors/modules/tool-pallette/tools/common/select-tool.ts index fab008984..ef37232a0 100644 --- a/web/src/app/modules/views/main/editors/modules/tool-pallette/tools/common/select-tool.ts +++ b/web/src/app/modules/views/main/editors/modules/tool-pallette/tools/common/select-tool.ts @@ -8,6 +8,7 @@ import { GraphTransformer } from '../../util/graphTransformer'; import { IDragAndDropTool } from '../IDragAndDropTool'; import { IKeyboardTool } from '../IKeyboardTool'; import { ToolBase } from '../tool-base'; +import { ClipboardService } from '../../services/clipboard-service'; export class SelectTool extends ToolBase implements IKeyboardTool, IDragAndDropTool { public icon = 'mouse-pointer'; @@ -19,6 +20,8 @@ export class SelectTool extends ToolBase implements IKeyboardTool, IDragAndDropT public sticky = false; + private static originType: string; + public activate() { this.selectedElements = []; } @@ -82,88 +85,70 @@ export class SelectTool extends ToolBase implements IKeyboardTool, IDragAndDropT if (ctrl && evt.key === 'c') { // Copy this.cancelEvent(evt); - this.copySelection(); + return this.copySelection(); } if (ctrl && evt.key === 'v') { // Paste this.cancelEvent(evt); - this.pasteSelection(); + return this.pasteSelection(); } if (ctrl && evt.key === 'x') { // Cut this.cancelEvent(evt); - this.cutSelection(); + return this.cutSelection(); } if (evt.keyCode === Key.BACKSPACE) { // Delete this.cancelEvent(evt); - this.deleteSelection(this.selectedElementService.selectedElements.slice()); + return this.deleteSelection(); } return Promise.resolve(); } - private static origin: IContainer; - private static cutFlag: boolean; - private static selection: IContainer[]; - - private copySelection(): void { - SelectTool.origin = this.model; - SelectTool.selection = this.selectedElementService.selectedElements.slice(); - SelectTool.cutFlag = false; + private async copySelection(): Promise { + // Copy Selection + SelectTool.originType = this.model.className; + let graphTransformer = new GraphTransformer(this.dataService, this.selectedElementService, this.model); + let sel = this.selectedElementService.selectedElements.slice(); + this.clipboardService.clipboard = await graphTransformer.cloneSubgraph(sel, Id.uuid, false); + return Promise.resolve(); } - private cutSelection(): void { - SelectTool.origin = this.model; - SelectTool.selection = this.selectedElementService.selectedElements.slice(); - SelectTool.cutFlag = true; + private cutSelection(): Promise { + return this.copySelection().then(() => this.deleteSelection()); } private async pasteSelection(): Promise { - if (!SelectTool.origin || !SelectTool.selection) { + if (!SelectTool.originType || !this.clipboardService.hasClipboard()) { // Nothing to paste return Promise.resolve(); } - if (SelectTool.origin === this.model && SelectTool.cutFlag) { - // Cut & Paste into the same model leaves the model the same - return Promise.resolve(); - } - let graphTransformer = new GraphTransformer(this.dataService, this.selectedElementService, this.model); let compoundId: string = Id.uuid; // Check Compatible Origin - if (this.model.className !== SelectTool.origin.className) { + if (this.model.className !== SelectTool.originType) { return Promise.resolve(); } - let newSelection = await graphTransformer.createSubgraph(SelectTool.selection, compoundId); - if (SelectTool.cutFlag) { - let oldTransformer = new GraphTransformer(this.dataService, this.selectedElementService, SelectTool.origin); - return oldTransformer.deleteAll(SelectTool.selection, compoundId); - } + let newSelection = await graphTransformer.cloneSubgraph(this.clipboardService.clipboard, compoundId, true); this.selectedElementService.selectedElements = newSelection; return Promise.resolve(); } - private deleteSelection(selection?: IContainer[]): Promise { - let tmpSel: IContainer[] = []; - if (selection) { - // Delete can be pressed after we have selected some other nodes so we have to safe the seleciton. - tmpSel = SelectTool.selection; - SelectTool.selection = selection; - } + private async deleteSelection(): Promise { let compoundId: string = Id.uuid; let graphTransformer = new GraphTransformer(this.dataService, this.selectedElementService, this.model); - let ret = graphTransformer.deleteAll(SelectTool.selection, compoundId); - SelectTool.selection = tmpSel; - return ret; + let selection = this.selectedElementService.selectedElements.slice(); + await graphTransformer.deleteAll(selection, compoundId); + return Promise.resolve(); } constructor(protected selectedElementService: SelectedElementService, private dataService: SpecmateDataService, - private rect: MultiselectionService, private model: IContainer) { + private rect: MultiselectionService, private clipboardService: ClipboardService, private model: IContainer) { super(selectedElementService); } } diff --git a/web/src/app/modules/views/main/editors/modules/tool-pallette/util/graphTransformer.ts b/web/src/app/modules/views/main/editors/modules/tool-pallette/util/graphTransformer.ts index f11b09383..47bd6b612 100644 --- a/web/src/app/modules/views/main/editors/modules/tool-pallette/util/graphTransformer.ts +++ b/web/src/app/modules/views/main/editors/modules/tool-pallette/util/graphTransformer.ts @@ -1,16 +1,17 @@ -import { IContainer } from '../../../../../../../model/IContainer'; -import { ElementProvider } from '../../graphical-editor/providers/properties/element-provider'; -import { GraphElementFactorySelector } from '../../../../../../../factory/util/graph-element-factory-selector'; +import { GraphElementFactorySelector, Coords } from '../../../../../../../factory/util/graph-element-factory-selector'; import { IConnection } from '../../../../../../../model/IConnection'; -import { IModelNode } from '../../../../../../../model/IModelNode'; -import { SpecmateDataService } from '../../../../../../data/modules/data-service/services/specmate-data.service'; -import { SelectedElementService } from '../../../../../side/modules/selected-element/services/selected-element.service'; -import { Url } from '../../../../../../../util/url'; +import { IContainer } from '../../../../../../../model/IContainer'; import { IModelConnection } from '../../../../../../../model/IModelConnection'; +import { IModelNode } from '../../../../../../../model/IModelNode'; +import { ISpecmatePositionableModelObject } from '../../../../../../../model/ISpecmatePositionableModelObject'; +import { FieldMetaItem, MetaInfo } from '../../../../../../../model/meta/field-meta'; import { Proxy } from '../../../../../../../model/support/proxy'; import { Arrays } from '../../../../../../../util/arrays'; -import { Id } from '../../../../../../../util/id'; -import { MetaInfo, FieldMetaItem } from '../../../../../../../model/meta/field-meta'; +import { Url } from '../../../../../../../util/url'; +import { SpecmateDataService } from '../../../../../../data/modules/data-service/services/specmate-data.service'; +import { SelectedElementService } from '../../../../../side/modules/selected-element/services/selected-element.service'; +import { ElementProvider } from '../../graphical-editor/providers/properties/element-provider'; +import { Objects } from '../../../../../../../util/objects'; export class GraphTransformer { private elementProvider: ElementProvider; @@ -19,28 +20,42 @@ export class GraphTransformer { } // Delete - public deleteAll(elements: IContainer[], compoundId: string): Promise { - let chain = Promise.resolve(); + public async deleteAll(elements: IContainer[], compoundId: string): Promise { + await this.selectionService.deselectElements(elements); + // We have to delete connections first to avoid updating already deleted nodes. + for (const element of elements) { + if (this.elementProvider.isConnection(element)) { + await this.deleteElement(element, compoundId); + } + } for (const element of elements) { - chain = chain.then(() => this.deleteElement(element, compoundId)); + if (this.elementProvider.isNode(element)) { + await this.deleteElement(element, compoundId); + } + } + if (this.selectionService !== undefined && this.selectionService !== null) { + this.selectionService.deselectElements(elements); } - chain.then(() => this.selectionService.deselectElements(elements)); - return chain; } - private deleteElement(element: IContainer, compoundId: string): Promise { - this.dataService.readElement(Url.parent(element.url), true).then((model: IContainer) => this.selectionService.select(model)); + private async deleteElement(element: IContainer, compoundId: string): Promise { + const model = await this.dataService.readElement(Url.parent(element.url), true); + if (this.selectionService !== undefined && this.selectionService !== null) { + this.selectionService.select(model); + } + if (this.elementProvider.isNode(element)) { return this.deleteNode(element as IModelNode, compoundId); } else if (this.elementProvider.isConnection(element)) { return this.deleteConnection(element as IModelConnection, compoundId); } // Tried to delete element with type element.className. This type is not supported. - return Promise.resolve(); } public deleteElementAndDeselect(element: IContainer, compoundId: string): Promise { - this.selectionService.deselectElement(element); + if (this.selectionService !== undefined && this.selectionService !== null) { + this.selectionService.deselectElement(element); + } return this.deleteElement(element, compoundId); } @@ -86,8 +101,15 @@ export class GraphTransformer { .then((target: IContainer) => this.dataService.updateElement(target, true, compoundId)); } - // Create a copy from the given templates in the current model. - public async createSubgraph(templates: IContainer[], compundId: string): Promise { + /** + * Clones a given list of elements (Nodes, Vertecies) and returns a promise for the copies + * If changeGraph is true, we use factory methods and commit the changes to the model + * This is used when you want to create new nodes/vertecies. + * + * If changeGraph is false, we only clone the objects without changing the model + * This is used when you only want to clone the data for later work. + */ + public async cloneSubgraph(templates: IContainer[], compoundId: string, changeGraph: boolean): Promise { let urlMap: {[old: string]: IModelNode} = {}; let out: IContainer[] = []; // Old URL -> New Node map @@ -95,11 +117,14 @@ export class GraphTransformer { if (this.elementProvider.isNode(template)) { let temp = template; let newCoord = { x: temp.x, y: temp.y + 100}; - let factory = GraphElementFactorySelector.getNodeFactory(template, newCoord, this.dataService); - let node = await factory.create(this.parent, false, compundId); - urlMap[template.url] = node; - this.transferData(temp, node); - await this.dataService.updateElement(node, true, compundId); + let node = await this.cloneNode(temp, newCoord, compoundId, changeGraph); + urlMap[template.url] = node; + node.incomingConnections = []; + node.outgoingConnections = []; + if (changeGraph) { + this.transferData(temp, node); + await this.updateElement(node, compoundId); + } out.push(node); } } @@ -111,10 +136,15 @@ export class GraphTransformer { if ((temp.target.url in urlMap) && (temp.source.url in urlMap)) { let source = urlMap[temp.source.url]; let target = urlMap[temp.target.url]; - let factory = GraphElementFactorySelector.getConnectionFactory(template, source, target, this.dataService); - let con = await factory.create(this.parent, false, compundId); - this.transferData(temp, con); - await this.dataService.updateElement(con, true, compundId); + let con = await this.cloneEdge(template, source, target, compoundId, changeGraph); + let conProxy = new Proxy(); + conProxy.url = con.url; + if (changeGraph) { + this.transferData(temp, con); + await this.updateElement(source, compoundId); + await this.updateElement(target, compoundId); + await this.updateElement(con, compoundId); + } out.push(con); } } @@ -122,6 +152,28 @@ export class GraphTransformer { return Promise.resolve(out); } + private cloneNode(template: IModelNode, coords: Coords, compoundId: string, createNode: boolean): + Promise { + if (!createNode) { + return Promise.resolve(Objects.clone(template)); + } + let factory = GraphElementFactorySelector.getNodeFactory(template, coords, this.dataService); + return factory.create(this.parent, false, compoundId); + } + + private cloneEdge(template: IContainer, newSource: IModelNode, newTarget: IModelNode, compoundId: string, createEdge: boolean): + Promise { + if (!createEdge) { + return Promise.resolve(Objects.clone(template)); + } + let factory = GraphElementFactorySelector.getConnectionFactory(template, newSource, newTarget, this.dataService); + return factory.create(this.parent, false, compoundId); + } + + private updateElement(element: IContainer, compoundId: string): Promise { + return this.dataService.updateElement(element, true, compoundId); + } + private transferData(from: IContainer, to: IContainer) { let fields: string[] = MetaInfo[from.className].map( (item: FieldMetaItem) => item.name); for (const field of fields) { diff --git a/web/src/app/modules/views/side/modules/history-view/base/history-provider.ts b/web/src/app/modules/views/side/modules/history-view/base/history-provider.ts new file mode 100644 index 000000000..4e9dd1c34 --- /dev/null +++ b/web/src/app/modules/views/side/modules/history-view/base/history-provider.ts @@ -0,0 +1,40 @@ +import { IContainer } from '../../../../../../model/IContainer'; +import { SpecmateDataService } from '../../../../../data/modules/data-service/services/specmate-data.service'; +import { History } from '../../../../../../model/History'; +import { Type } from '../../../../../../util/type'; +import { Folder } from '../../../../../../model/Folder'; +import { HistoryEntry } from '../../../../../../model/HistoryEntry'; + +type HistoryType = 'single' | 'container' | 'recursive'; + +export class HistoryProvider { + + constructor(private dataService: SpecmateDataService) { } + + public async getHistory(element: IContainer): Promise { + const type = this.determineHistoryType(element); + const history: History = await this.dataService.performQuery(element.url, 'history', { type: type }); + if (history === undefined) { + return []; + } + return history.entries.filter(this.getFilter(element)); + } + + private determineHistoryType(element: IContainer): HistoryType { + if (this.isSingle(element)) { + return 'single'; + } + return 'container'; + } + + private getFilter(element: IContainer): (historyEntry: HistoryEntry) => boolean { + if (this.isSingle(element)) { + return (historyEntry: HistoryEntry) => historyEntry.deletedObjects.length === 0; + } + return () => true; + } + + private isSingle(element: IContainer): boolean { + return Type.is(element, Folder); + } +} diff --git a/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.css b/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.html b/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.html deleted file mode 100644 index 3da5b570a..000000000 --- a/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.html +++ /dev/null @@ -1,21 +0,0 @@ -
-
- {{'Changes' | translate}} - -
-
    -
  • - {{getDate(entry.timestamp) | date:'yyyy-MM-dd HH:mm:ss'}} {{entry.user}} -
      -
    • -
      - {{'ElementDeleted' | translate}} -
      -
      - {{'Changed' | translate}} {{change.feature}}  {{change.newValue}} -
      -
    • -
    -
  • -
-
diff --git a/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.ts b/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.ts deleted file mode 100644 index 508239f4e..000000000 --- a/web/src/app/modules/views/side/modules/history-view/components/extended-history-view.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component } from '@angular/core'; -import { Requirement } from '../../../../../../model/Requirement'; -import { IContainer } from '../../../../../../model/IContainer'; -import { TestSpecification } from '../../../../../../model/TestSpecification'; -import { NavigatorService } from '../../../../../navigation/modules/navigator/services/navigator.service'; -import { SpecmateDataService } from '../../../../../data/modules/data-service/services/specmate-data.service'; -import { History } from '../../../../../../model/History'; -import { HistoryEntry } from '../../../../../../model/HistoryEntry'; -import { HistoryView } from './history-view.component'; - -@Component({ - moduleId: module.id.toString(), - selector: 'extended-history-view', - templateUrl: 'extended-history-view.component.html', - styleUrls: ['extended-history-view.component.css'] -}) -export class ExtendedHistoryView extends HistoryView {} diff --git a/web/src/app/modules/views/side/modules/history-view/components/simple-history-view.component.css b/web/src/app/modules/views/side/modules/history-view/components/history-view.component.css similarity index 100% rename from web/src/app/modules/views/side/modules/history-view/components/simple-history-view.component.css rename to web/src/app/modules/views/side/modules/history-view/components/history-view.component.css diff --git a/web/src/app/modules/views/side/modules/history-view/components/simple-history-view.component.html b/web/src/app/modules/views/side/modules/history-view/components/history-view.component.html similarity index 100% rename from web/src/app/modules/views/side/modules/history-view/components/simple-history-view.component.html rename to web/src/app/modules/views/side/modules/history-view/components/history-view.component.html diff --git a/web/src/app/modules/views/side/modules/history-view/components/history-view.component.ts b/web/src/app/modules/views/side/modules/history-view/components/history-view.component.ts index 864e80b3f..eb9340afd 100644 --- a/web/src/app/modules/views/side/modules/history-view/components/history-view.component.ts +++ b/web/src/app/modules/views/side/modules/history-view/components/history-view.component.ts @@ -1,40 +1,38 @@ import { Component } from '@angular/core'; -import { Requirement } from '../../../../../../model/Requirement'; -import { IContainer } from '../../../../../../model/IContainer'; -import { TestSpecification } from '../../../../../../model/TestSpecification'; import { NavigatorService } from '../../../../../navigation/modules/navigator/services/navigator.service'; import { SpecmateDataService } from '../../../../../data/modules/data-service/services/specmate-data.service'; -import { History } from '../../../../../../model/History'; import { HistoryEntry } from '../../../../../../model/HistoryEntry'; +import { HistoryProvider } from '../base/history-provider'; @Component({ moduleId: module.id.toString(), - template: '', + templateUrl: 'history-view.component.html', + styleUrls: ['history-view.component.css'], selector: 'history-view' }) export class HistoryView { - public modelHistoryEntries: HistoryEntry[]; + public modelHistoryEntries: HistoryEntry[]; public isCollapsed = true; + private historyProvider: HistoryProvider; + constructor( private navigator: NavigatorService, - private dataService: SpecmateDataService) { } + private dataService: SpecmateDataService) { + this.historyProvider = new HistoryProvider(dataService); + } ngOnInit() { - this.navigator.hasNavigated.subscribe((elem: IContainer) => { - if (elem === undefined) { - return; - } - this.dataService.performQuery(elem.url, 'history', { type: 'container' }) - .then((history: History) => { - if (history !== undefined) { - this.modelHistoryEntries = history.entries; - } else { - this.modelHistoryEntries = []; - } - }); - }); + this.navigator.hasNavigated.subscribe(() => this.loadHistory()); + this.dataService.committed.subscribe(() => this.loadHistory()); + } + + private async loadHistory(): Promise { + if (this.navigator.currentElement === undefined) { + return; + } + this.modelHistoryEntries = await this.historyProvider.getHistory(this.navigator.currentElement); } public getDeletedObjectName(s: string): string { diff --git a/web/src/app/modules/views/side/modules/history-view/components/simple-history-view.component.ts b/web/src/app/modules/views/side/modules/history-view/components/simple-history-view.component.ts deleted file mode 100644 index d6d4048d0..000000000 --- a/web/src/app/modules/views/side/modules/history-view/components/simple-history-view.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component } from '@angular/core'; -import { Requirement } from '../../../../../../model/Requirement'; -import { IContainer } from '../../../../../../model/IContainer'; -import { TestSpecification } from '../../../../../../model/TestSpecification'; -import { NavigatorService } from '../../../../../navigation/modules/navigator/services/navigator.service'; -import { SpecmateDataService } from '../../../../../data/modules/data-service/services/specmate-data.service'; -import { History } from '../../../../../../model/History'; -import { HistoryEntry } from '../../../../../../model/HistoryEntry'; -import { HistoryView } from './history-view.component'; - -@Component({ - moduleId: module.id.toString(), - selector: 'simple-history-view', - templateUrl: 'simple-history-view.component.html', - styleUrls: ['simple-history-view.component.css'] -}) -export class SimpleHistoryView extends HistoryView {} diff --git a/web/src/app/modules/views/side/modules/history-view/history-view.module.ts b/web/src/app/modules/views/side/modules/history-view/history-view.module.ts index 3be0e54f0..85929b5ad 100644 --- a/web/src/app/modules/views/side/modules/history-view/history-view.module.ts +++ b/web/src/app/modules/views/side/modules/history-view/history-view.module.ts @@ -1,14 +1,9 @@ import { NavigatorModule } from '../../../../navigation/modules/navigator/navigator.module'; import { NgModule } from '@angular/core'; import { HistoryView } from './components/history-view.component'; -import { GenericFormModule } from '../../../../forms/modules/generic-form/generic-form.module'; import { BrowserModule } from '@angular/platform-browser'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { IconsModule } from '../../../../common/modules/icons/icons.module'; import { TranslateModule } from '@ngx-translate/core'; -import { SimpleHistoryView } from './components/simple-history-view.component'; -import { ExtendedHistoryView } from './components/extended-history-view.component'; @NgModule({ imports: [ @@ -20,14 +15,11 @@ import { ExtendedHistoryView } from './components/extended-history-view.componen ], declarations: [ // COMPONENTS IN THIS MODULE - HistoryView, - SimpleHistoryView, - ExtendedHistoryView + HistoryView ], exports: [ // THE COMPONENTS VISIBLE TO THE OUTSIDE - SimpleHistoryView, - ExtendedHistoryView + HistoryView ], providers: [ // SERVICES diff --git a/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.html b/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.html index d07ef66ed..1c603c9b2 100644 --- a/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.html +++ b/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.html @@ -1,4 +1,4 @@ -
+
{{'LinksandActions' | translate}} @@ -18,11 +18,25 @@
+
  • + +
  • +
  • + +
  • +
  • + {{'exportTestspecification' | translate}}:
    +
      +
    • + +
    • +
    • + +
    • +
    • + +
    • +
    +
  • -
    - -
    -
    - -
    diff --git a/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.ts b/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.ts index 294225207..02663ca6d 100644 --- a/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.ts +++ b/web/src/app/modules/views/side/modules/links-actions/components/links-actions.component.ts @@ -15,11 +15,6 @@ import { Config } from '../../../../../../config/config'; export class LinksActions { public isCollapsed = false; - - public _requirement: Requirement; - public _model: IContainer; - public _contents: IContainer[]; - public _testSpecifications: TestSpecification[]; public descriptionVisible: boolean; constructor(private additionalInformationService: AdditionalInformationService) { } @@ -60,6 +55,10 @@ export class LinksActions { return this.additionalInformationService.canExportTestprocedure; } + public get canExportTestspecification(): boolean { + return this.additionalInformationService.canExportTestspecification; + } + public toggleDescription() { this.descriptionVisible = !this.descriptionVisible; } diff --git a/web/src/app/modules/views/side/modules/links-actions/links-actions.module.ts b/web/src/app/modules/views/side/modules/links-actions/links-actions.module.ts index 04c60e809..f1b7f48de 100644 --- a/web/src/app/modules/views/side/modules/links-actions/links-actions.module.ts +++ b/web/src/app/modules/views/side/modules/links-actions/links-actions.module.ts @@ -6,10 +6,14 @@ import { TestSpecificationGeneratorButtonModule } from '../../../../actions/modules/test-specification-generator-button/test-specification-generator-button.module'; import { ExportTestprocedureButtonModule } from '../../../../actions/modules/export-testprocedure-button/export-testprocedure-button.module'; +import { ExportTestspecificationButtonModule } from + '../../../../actions/modules/export-testspecification-button/export-testspecification-button.module'; import { AdditionalInformationService } from './services/additional-information.service'; import { TranslateModule } from '@ngx-translate/core'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { AuthModule } from '../../../main/authentication/modules/auth/auth.module'; +import { GetTestSpecificationSkeletonButtonModule } from + '../../../../actions/modules/get-test-specification-skeleton-button/get-test-specification-skeleton-button.module'; @NgModule({ imports: [ @@ -18,6 +22,8 @@ import { AuthModule } from '../../../main/authentication/modules/auth/auth.modul NavigatorModule, TestSpecificationGeneratorButtonModule, ExportTestprocedureButtonModule, + GetTestSpecificationSkeletonButtonModule, + ExportTestspecificationButtonModule, TranslateModule, AuthModule, NgbModule.forRoot() diff --git a/web/src/app/modules/views/side/modules/links-actions/services/additional-information.service.ts b/web/src/app/modules/views/side/modules/links-actions/services/additional-information.service.ts index 1fde9787a..9b5a27a46 100644 --- a/web/src/app/modules/views/side/modules/links-actions/services/additional-information.service.ts +++ b/web/src/app/modules/views/side/modules/links-actions/services/additional-information.service.ts @@ -1,4 +1,3 @@ -import {ProcessStep} from '../../../../../../model/ProcessStep'; import { Injectable, EventEmitter } from '@angular/core'; import { Requirement } from '../../../../../../model/Requirement'; import { IContainer } from '../../../../../../model/IContainer'; @@ -12,34 +11,31 @@ import { TestProcedure } from '../../../../../../model/TestProcedure'; import { CEGModel } from '../../../../../../model/CEGModel'; import { Process } from '../../../../../../model/Process'; import { AuthenticationService } from '../../../../main/authentication/modules/auth/services/authentication.service'; -import { UserToken } from '../../../../main/authentication/base/user-token'; @Injectable() export class AdditionalInformationService { - private _requirement: Requirement; - private _model: IContainer; - private _contents: IContainer[]; public element: IContainer; private parents: IContainer[]; private _testSpecifications: TestSpecification[]; - public informationLoaded: EventEmitter; - - constructor(private dataService: SpecmateDataService, private navigator: NavigatorService, private auth: AuthenticationService) { - this.informationLoaded = new EventEmitter(); + constructor(private dataService: SpecmateDataService, navigator: NavigatorService, private auth: AuthenticationService) { navigator.hasNavigated.subscribe((element: IContainer) => { - this.clear(); this.element = element; - this.loadParents() - .then(() => this.loadTestSpecifications()) - .then(() => this.informationLoaded.emit()); + this.load(); }); } - private loadTestSpecifications(): Promise { + private async load(): Promise { + await Promise.all([ + this.loadParents(), + this.loadTestSpecifications() + ]); + } + + private async loadTestSpecifications(): Promise { if (!this.canHaveTestSpecifications || !this.requirement) { - return Promise.resolve(); + return; } let baseUrl = ''; if (this.isModel(this.element)) { @@ -47,39 +43,25 @@ export class AdditionalInformationService { } else { baseUrl = this.requirement.url; } - return this.dataService.performQuery(baseUrl, 'listRecursive', { class: TestSpecification.className }) - .then((testSpecifications: TestSpecification[]) => this._testSpecifications = Sort.sortArray(testSpecifications)) - .then(() => Promise.resolve()); + + const testSpecifications = await this.dataService.performQuery(baseUrl, 'listRecursive', { class: TestSpecification.className }); + this._testSpecifications = Sort.sortArray(testSpecifications); } - private loadParents(): Promise { + private async loadParents(): Promise { if (!this.auth.isAuthenticated) { - return Promise.resolve(); + return; } let parentUrls: string[] = []; - let url: string = this.element.url; - url = Url.parent(url); + let url: string = Url.parent(this.element.url); while (!Url.isRoot(url, this.auth.token.project)) { parentUrls.push(url); url = Url.parent(url); } - let readParentsTask: Promise = Promise.resolve(0); - this.parents = []; - for (let i = 0; i < parentUrls.length; i++) { - let currentUrl: string = parentUrls[i]; - readParentsTask = readParentsTask.then(() => { - return this.dataService.readElement(currentUrl) - .then((element: IContainer) => this.parents.push(element)); - }); - } - return readParentsTask.then(() => Promise.resolve()); - } - private clear(): void { - this._model = undefined; - this._requirement = undefined; - this._contents = undefined; + const parentElements = await Promise.all(parentUrls.map(url => this.dataService.readElement(url))); + this.parents = parentElements; } public get hasAdditionalInformation(): boolean { @@ -116,7 +98,7 @@ export class AdditionalInformationService { } public get canGenerateTestSpecifications(): boolean { - return this.element && this.isModel(this.element); + return this.element && ((this.isModel(this.element) && this.requirement !== undefined) || Type.is(this.element, Requirement)); } public get canAddTestSpecifications(): boolean { @@ -127,6 +109,10 @@ export class AdditionalInformationService { return Type.is(this.element, TestProcedure); } + public get canExportTestspecification(): boolean { + return Type.is(this.element, TestSpecification); + } + private isModel(element: IContainer): boolean { return Type.is(element, CEGModel) || Type.is(element, Process); } diff --git a/web/src/app/modules/views/side/modules/properties-editor/components/properties-editor.component.ts b/web/src/app/modules/views/side/modules/properties-editor/components/properties-editor.component.ts index 0732d98c5..b5cb699f0 100644 --- a/web/src/app/modules/views/side/modules/properties-editor/components/properties-editor.component.ts +++ b/web/src/app/modules/views/side/modules/properties-editor/components/properties-editor.component.ts @@ -5,6 +5,7 @@ import { GenericForm } from '../../../../../forms/modules/generic-form/component import { SelectedElementService } from '../../selected-element/services/selected-element.service'; import { Type } from '../../../../../../util/type'; import { ProcessStep } from '../../../../../../model/ProcessStep'; +import { MetaInfo, FieldMetaItem } from '../../../../../../model/meta/field-meta'; @Component({ moduleId: module.id.toString(), @@ -26,6 +27,23 @@ export class PropertiesEditor { selectedElementService.selectionChanged.subscribe((elements: IContainer[]) => { this.hiddenFieldsProvider = new HiddenFieldsProvider(elements[0]); this._selectedElement = elements[0]; + + // try to select the most relevant field in the properties view + try { + let meta: FieldMetaItem[] = MetaInfo[this._selectedElement.className]; + if (meta) { + meta.sort((item1: FieldMetaItem, item2: FieldMetaItem) => + Number.parseInt(item1.position) - Number.parseInt(item2.position)); + setTimeout(() => { + let inputElement: HTMLElement = document.getElementById('properties-' + meta[0].name + '-textfield'); + if (inputElement) { + (inputElement as HTMLInputElement).select(); + } + }, 10); + } + } catch { + // meta field is not provided. No need to do anything + } }); } diff --git a/web/src/app/util/objects.ts b/web/src/app/util/objects.ts index e8cf4565e..e8576eaae 100644 --- a/web/src/app/util/objects.ts +++ b/web/src/app/util/objects.ts @@ -3,7 +3,6 @@ import { Type } from './type'; export class Objects { public static clone(source: any, target?: any): any { - if (source === target) { return; } @@ -14,7 +13,7 @@ export class Objects { actualTarget = Objects.getFreshInstance(source); } for (let name in source) { - if (!source[name]) { + if (!source.hasOwnProperty(name)) { continue; } actualTarget[name] = Objects.getFreshInstance(source[name]); @@ -31,6 +30,25 @@ export class Objects { return actualTarget; } + public static shallowClone(source: any, target: any): any { + if (source === target) { + return; + } + + let actualTarget = target; + + if (target === undefined) { + actualTarget = Objects.getFreshInstance(source); + } + for (let name in source) { + if (!source.hasOwnProperty(name)) { + continue; + } + actualTarget[name] = source[name]; + } + return actualTarget; + } + /** * Get (flat) the fields that are different between two objects. It only compares values, and references flat. */ @@ -45,32 +63,17 @@ export class Objects { let changedFields: string[] = []; for (let field in o1) { if (!Objects.isObject(o1[field])) { - if (!Objects.fieldsEqualIgnoreBooleanStrings(o1[field], o2[field])) { + if (o2[field] && !Objects.fieldsEqualIgnoreBooleanStrings(o1[field], o2[field])) { changedFields.push(field); } } else if (Objects.isArray(o1[field])) { - if (o1[field].length !== o2[field].length) { + if (o2[field] && !Objects.areArraysEqual(o1[field], o2[field])) { changedFields.push(field); - continue; - } - for (let i = 0; i < o1[field].length; i++) { - if (!Objects.fieldsEqualIgnoreBooleanStrings(o1[field][i], o2[field][i])) { - changedFields.push(field); - break; - } } } } - for (let field in o1) { - if (!o2[field]) { - changedFields.push(field); - } - } - for (let field in o2) { - if (!o1[field]) { - changedFields.push(field); - } - } + Objects.pushTheNotMatchingFields(o1, o2, changedFields); + Objects.pushTheNotMatchingFields(o2, o1, changedFields); return changedFields; } @@ -84,6 +87,34 @@ export class Objects { return p1 === p2; } + /** + *Return true if the 2 arrays contain the same elements. + */ + private static areArraysEqual(array1: Array, array2: Array): boolean { + if (array1.length !== array2.length) { + return false; + } + for (let i = 0; i < array1.length; i++) { + if (!Objects.fieldsEqualIgnoreBooleanStrings(array1[i], array2[i])) { + return false; + } + } + return true; + } + + /** + *It will go through all the fields from the first object and see if they + *are existing in the second object. The fields that are not matching will + *be pushed in the changedFields arrays. + */ + private static pushTheNotMatchingFields(object1: any, object2: any, changedFields: string[]) { + for (let field in object1) { + if (!object2[field]) { + changedFields.push(field); + } + } + } + private static isBoolean(p: any): boolean { return p === true || p === false; } diff --git a/web/src/app/validation/required-fields-validator.ts b/web/src/app/validation/required-fields-validator.ts index 493318b7e..6cbdebe71 100644 --- a/web/src/app/validation/required-fields-validator.ts +++ b/web/src/app/validation/required-fields-validator.ts @@ -13,7 +13,9 @@ export class RequiredFieldsValidator extends ElementValidatorBase { public validate(element: IContainer, contents: IContainer[] = []): ValidationResult { const missingFields: string[] = this.fields.filter((field: string) => !element[field] || element[field].length === 0); if (missingFields.length > 0) { - return new ValidationResult(Config.ERROR_MISSING_FIELDS, false, [element]); + let fieldText = '[' + missingFields.join(', ') + ']'; + let message = Config.ERROR_MISSING_FIELDS.replace('{{fields}}', fieldText); + return new ValidationResult(message, false, [element]); } return ValidationResult.VALID; } diff --git a/web/src/assets/i18n/de.json b/web/src/assets/i18n/de.json index 7019335dd..7afe7f519 100644 --- a/web/src/assets/i18n/de.json +++ b/web/src/assets/i18n/de.json @@ -65,6 +65,8 @@ }, "connectionLost": "Keine Verbindung", "contentsCouldNotBeRead": "Inhalte konnten nicht geladen werden", + "copy": "Kopieren", + "copyOf": "Kopie von", "couldNotLoadElement": "Element konnte nicht geladen werden", "create": "Anlegen", "createFolder": "Order anlegen", @@ -74,6 +76,7 @@ "createTestProcedure": "Testprozedur anlegen", "createTestSpecification": "Testspezifikation anlegen", "createTestStep": "Testschritt anlegen", + "csv": "CSV", "delete": "Löschen", "description": "Beschreibung", "discard": "Verwerfen", @@ -89,6 +92,7 @@ "errorLoggedOut": "Sie wurden aufgrund eines unbekannten Fehlers abgemeldet.", "expand": "", "exportTestprocedure": "Testprozedur exportieren", + "exportTestspecification": "Testspezifikation exportieren", "failed": "Fehler", "fieldInvalid": "Feld ungültig", "hideGrid": "Hilfslinien ausblenden", @@ -134,6 +138,8 @@ "operationCouldNotBePerformed": "Operation konnte nicht ausgeführt werden", "parameters": "Parameter", "password": "Passwort", + "paste": "Einfügen", + "pasteAsName": "Mit Namen einfügen", "payload": "Ladung", "procedureExportFailed": "Prozedur konnte nicht exportiert werden", "procedureExportedSuccessfully": "Prozedur erfolgreich exportiert", @@ -155,12 +161,14 @@ "showGrid": "Hilfslinien anzeigen", "showLog": "Log anzeigen", "sorrySuggestionsCouldNotBeLoaded": "Vorschläge konnten leider nicht geladen werden", + "specificationNotValid": "Spezifikation nicht gültig", "specmate": { "logo": "Specmate Logo" }, "successful": "Erfolgreich", "testspec": { - "generate": "Testspezifikation generieren" + "generate": "Testspezifikation generieren", + "skeleton": "Testspezifikationshüllen herunterladen" }, "toggleLog": "Log ein/ausblenden", "tools": { diff --git a/web/src/assets/i18n/gb.json b/web/src/assets/i18n/gb.json index c842e1cd9..cdd4cffcd 100644 --- a/web/src/assets/i18n/gb.json +++ b/web/src/assets/i18n/gb.json @@ -65,6 +65,8 @@ }, "connectionLost": "Connection lost", "contentsCouldNotBeRead": "Contents could not be read", + "copy": "Copy", + "copyOf": "Copy of", "couldNotLoadElement": "Could not load element", "create": "Create", "createFolder": "Create Folder", @@ -74,6 +76,7 @@ "createTestProcedure": "Create test procedure", "createTestSpecification": "Create test specification", "createTestStep": "Create test step", + "csv": "CSV", "delete": "Delete", "discard": "Discard", "discardUnsavedChangesConfirmation": "You have unsaved changes. Do you really want to discard them?", @@ -88,6 +91,7 @@ "errorLoggedOut": "You were logged out due to an unknown error.", "expand": "", "exportTestprocedure": "Export test procedure", + "exportTestspecification": "Export test specification", "failed": "Failed", "fieldInvalid": "Field invalid", "hideGrid": "Hide grid", @@ -133,6 +137,8 @@ "operationCouldNotBePerformed": "Operation could not be performed", "parameters": "Parameters", "password": "Password", + "paste": "Paste", + "pasteAsName": "Paste with name", "payload": "Payload", "procedureExportFailed": "Procedure could not be exported", "procedureExportedSuccessfully": "Procedure exported successfully", @@ -154,12 +160,14 @@ "showGrid": "Show grid", "showLog": "Show log", "sorrySuggestionsCouldNotBeLoaded": "Sorry, suggestions could not be loaded", + "specificationNotValid": "Specification not valid", "specmate": { "logo": "Specmate Emblem" }, "successful": "Successful", "testspec": { - "generate": "Generate test specification" + "generate": "Generate test specification", + "skeleton": "Download test specification skeletons" }, "toggleLog": "Toggle log", "tools": { diff --git a/web/src/assets/img/default_background.png b/web/src/assets/img/default_background.png new file mode 100644 index 000000000..8f8ffa4b5 Binary files /dev/null and b/web/src/assets/img/default_background.png differ diff --git a/web/src/assets/scss/specmate.extensions.scss b/web/src/assets/scss/specmate.extensions.scss index e1b06bf25..d987a5f61 100644 --- a/web/src/assets/scss/specmate.extensions.scss +++ b/web/src/assets/scss/specmate.extensions.scss @@ -138,3 +138,38 @@ textarea:focus, cursor: grabbing; cursor: -webkit-grabbing; } + +.login-background-container { + height: 100vh; + width: 100vw; +} + +.send-to-back { + position: absolute; + z-index: -10; +} + +.login-background-image { + height: 100%; + width: 100%; + object-fit: cover; +} + +.login-form { + background: #fff; + border: 1px solid #ccc; + padding: 16px; +} + +.login-top-space { + height: 100vh; + padding-top: 64px; +} + +.nav-tabs .nav-link { + color: #495057; +} + +.nav-tabs .nav-link.active { + color: #007ea8; +} diff --git a/web/webpack/webpack.common.js b/web/webpack/webpack.common.js index 1201dbe75..0803cf819 100644 --- a/web/webpack/webpack.common.js +++ b/web/webpack/webpack.common.js @@ -1,4 +1,4 @@ -const SPECMATE_VERSION = '0.2.6' +const SPECMATE_VERSION = '0.2.10' const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin');