diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..821e67d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +/.gradle +/.idea +/kubernetes +/lib +/log +/node-storage +/service +.gitignore +agent-developer.xml +LICENSE +README.md \ No newline at end of file diff --git a/.gitignore b/.gitignore index 35662fb..0a27903 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ /node-storage/ /.las2peer/ /tmp/ -/log/ /lib/ +/log/ /etc/ivy/ivy.jar /service/ /out/ @@ -14,7 +14,6 @@ /.settings/ /junitvmwatcher*.properties /junit*.properties -/etc/startup/ *.secret archiva_credentials.xml .classpath diff --git a/Dockerfile b/Dockerfile index de9c3a3..b50ac4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,9 @@ -FROM openjdk:14-jdk-alpine +FROM openjdk:17-jdk-alpine ENV HTTP_PORT=8080 ENV HTTPS_PORT=8443 -ENV LAS2PEER_PORT=9011 +ENV LAS2PEER_PORT=32061 +ENV NODE_ID_SEED=382251 RUN apk add --update bash mysql-client apache-ant tzdata curl && rm -f /var/cache/apk/* RUN addgroup -g 1000 -S las2peer && \ @@ -16,12 +17,10 @@ USER las2peer RUN dos2unix gradlew RUN dos2unix gradle.properties RUN dos2unix /src/docker-entrypoint.sh -#RUN chmod -R a+rwx /src -#RUN chmod +x /src/docker-entrypoint.sh +RUN dos2unix /src/etc/i5.las2peer.connectors.webConnector.WebConnector.properties +RUN chmod -R a+rwx /src +RUN chmod +x /src/docker-entrypoint.sh RUN chmod +x gradlew && ./gradlew build --exclude-task test -#RUN dos2unix /src/docker-entrypoint.sh -#RUN dos2unix /src/etc/i5.las2peer.connectors.webConnector.WebConnector.properties -#RUN dos2unix /src/etc/i5.las2peer.services.servicePackage.akgService.properties EXPOSE $HTTP_PORT EXPOSE $HTTPS_PORT diff --git a/README.md b/README.md index f3af8e3..be861d3 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ Distributed Noracle Backend [![Build Status](https://jenkins.dbis.rwth-aachen.de/buildStatus/icon?job=Distributed-Noracle-Backend)](https://jenkins.dbis.rwth-aachen.de/job/Distributed-Noracle-Backend/) This suite of microservices forms the backend of the Distributed Noracle Project. -Please try out our app at: [dbis.rwth-aachen.de/noracle/](http://dbis.rwth-aachen.de/noracle/) +Please try out our app at: https://noracle.tech4comp.dbis.rwth-aachen.de/ --------------- ## Java +The application uses **Java 17** and **Gradle 7.3**. -las2peer uses **Java 14**. - -## Setup -1. Build the project using `ant all` -1. Copy *launcher-configuration.ini* to *etc/* -1. Start using `./start-local.sh` for starting in the same shell (useful for testing), or `./start-node.sh` for starting Noracle in a screen (useful for production) - +## Run +``` +docker build -t noracle-service . +docker run -p 8080:8080 -p 9011:9011 noracle-service +``` +The service(s) are then available under http://localhost:8080/distributed-noracle. \ No newline at end of file diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 2f9a714..d4e3c4d 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -19,12 +19,19 @@ export SERVICE3=${SERVICE_NAME}.'NoracleSpaceService'@${SERVICE_VERSION} export SERVICE4=${SERVICE_NAME}.'NoracleQuestionService'@${SERVICE_VERSION} export SERVICE5=${SERVICE_NAME}.'NoracleQuestionRelationService'@${SERVICE_VERSION} export SERVICE6=${SERVICE_NAME}.'NoracleAgentService'@${SERVICE_VERSION} +export SERVICE7=${SERVICE_NAME}.'NoracleRecommenderService'@${SERVICE_VERSION} + +# Currently, these services cannot be used, because object serialization in the network does not work +export SERVICE8=${SERVICE_NAME}.'NoracleNormalizationService'@${SERVICE_VERSION} +export SERVICE9=${SERVICE_NAME}.'NoracleQuestionUtilityService'@${SERVICE_VERSION} + echo deploy $SERVICE1 echo deploy $SERVICE2 echo deploy $SERVICE3 echo deploy $SERVICE4 echo deploy $SERVICE5 echo deploy $SERVICE6 +echo deploy $SERVICE7 function set_in_service_config { sed -i "s?${1}[[:blank:]]*=.*?${1}=${2}?g" ${SERVICE_PROPERTY_FILE} @@ -54,7 +61,7 @@ fi # prevent glob expansion in lib/* echo prevent glob expansion in lib set -f -LAUNCH_COMMAND='java -cp lib/* i5.las2peer.tools.L2pNodeLauncher -s service -p '"${LAS2PEER_PORT} ${SERVICE_EXTRA_ARGS}" +LAUNCH_COMMAND='java -cp lib/* --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED i5.las2peer.tools.L2pNodeLauncher -s service -p '"${LAS2PEER_PORT} ${SERVICE_EXTRA_ARGS}" if [[ ! -z "${BOOTSTRAP}" ]]; then LAUNCH_COMMAND="${LAUNCH_COMMAND} -b ${BOOTSTRAP}" fi @@ -84,12 +91,12 @@ echo start the service within a las2peer node if [[ -z "${@}" ]] then if [ -n "$LAS2PEER_ETH_HOST" ]; then - echo ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED --ethereum-mnemonic "$(selectMnemonic)" uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector "node=getNodeAsEthereumNode()" "registry=node.getRegistryClient()" "n=getNodeAsEthereumNode()" "r=n.getRegistryClient()" - exec ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED --ethereum-mnemonic "$(selectMnemonic)" uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector "node=getNodeAsEthereumNode()" "registry=node.getRegistryClient()" "n=getNodeAsEthereumNode()" "r=n.getRegistryClient()" + echo ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED --ethereum-mnemonic "$(selectMnemonic)" uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE7}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector "node=getNodeAsEthereumNode()" "registry=node.getRegistryClient()" "n=getNodeAsEthereumNode()" "r=n.getRegistryClient()" + exec ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED --ethereum-mnemonic "$(selectMnemonic)" uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE7}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector "node=getNodeAsEthereumNode()" "registry=node.getRegistryClient()" "n=getNodeAsEthereumNode()" "r=n.getRegistryClient()" #exec ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED --observer --ethereum-mnemonic "$(selectMnemonic)" uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector "node=getNodeAsEthereumNode()" "registry=node.getRegistryClient()" "n=getNodeAsEthereumNode()" "r=n.getRegistryClient()" else - echo ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector - exec ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector + echo ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE7}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector + exec ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE2}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE3}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE4}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE5}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE6}""'", "'""${SERVICE_PASSPHRASE}""'"\) startService\("'""${SERVICE7}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector #exec ${LAUNCH_COMMAND} --node-id-seed $NODE_ID_SEED --observer uploadStartupDirectory startService\("'""${SERVICE1}""'", "'""${SERVICE_PASSPHRASE}""'"\) startWebConnector fi else diff --git a/etc/i5.las2peer.connectors.webConnector.WebConnector.properties b/etc/i5.las2peer.connectors.webConnector.WebConnector.properties index aaeaca5..5c226e0 100644 --- a/etc/i5.las2peer.connectors.webConnector.WebConnector.properties +++ b/etc/i5.las2peer.connectors.webConnector.WebConnector.properties @@ -1,13 +1,11 @@ httpPort = 8080 -httpsPort = 8090 +httpsPort = 8443 startHttp = TRUE startHttps = FALSE -sslKeystore = etc/example.jks -sslKeyPassword = secretpassword crossOriginResourceDomain = * crossOriginResourceMaxAge = 60 enableCrossOriginResourceSharing = TRUE onlyLocalServices = FALSE defaultLoginUser = anonymous defaultLoginPassword = anonymous -oidcProviders = https://api.learning-layers.eu/auth +oidcProviders = https://api.learning-layers.eu/o/oauth2 diff --git a/etc/i5.las2peer.services.noracleService.NoracleService.properties b/etc/i5.las2peer.services.noracleService.NoracleService.properties index 76f18a0..e69de29 100644 --- a/etc/i5.las2peer.services.noracleService.NoracleService.properties +++ b/etc/i5.las2peer.services.noracleService.NoracleService.properties @@ -1 +0,0 @@ -templateProperty="Insert your properties here" diff --git a/etc/i5.las2peer.services.servicePackage.MyNewServiceMainClass.properties b/etc/i5.las2peer.services.servicePackage.MyNewServiceMainClass.properties deleted file mode 100644 index 76f18a0..0000000 --- a/etc/i5.las2peer.services.servicePackage.MyNewServiceMainClass.properties +++ /dev/null @@ -1 +0,0 @@ -templateProperty="Insert your properties here" diff --git a/etc/nodeInfo.xml b/etc/nodeInfo.xml index 883b1a5..d0d5c99 100644 --- a/etc/nodeInfo.xml +++ b/etc/nodeInfo.xml @@ -1,6 +1,6 @@ - Simon Breuer - simon.breuer@rwth-aachen.de + Admin + admin@mail.com Advanced Community Information Systems (ACIS) Group, RWTH Aachen University - This node hosts the noracle backend service. + This node hosts a sample service. diff --git a/example/agent-noracle-example-alice.xml b/example/agent-noracle-example-alice.xml deleted file mode 100644 index d92191b..0000000 --- a/example/agent-noracle-example-alice.xml +++ /dev/null @@ -1,9 +0,0 @@ - - 0ff72d50061d34e0bc40c94a5242ffbbb4da1fa49500fa546caaa4ab7b63f4189e430ca84f688122ad04110e4155e3712316d30de07380743fc94bd527258b82 - rO0ABXNyABRqYXZhLnNlY3VyaXR5LktleVJlcL35T7OImqVDAgAETAAJYWxnb3JpdGhtdAASTGphdmEvbGFuZy9TdHJpbmc7WwAHZW5jb2RlZHQAAltCTAAGZm9ybWF0cQB+AAFMAAR0eXBldAAbTGphdmEvc2VjdXJpdHkvS2V5UmVwJFR5cGU7eHB0AANSU0F1cgACW0Ks8xf4BghU4AIAAHhwAAABJjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqoEMBjObRmZmXmgHKbyNb9aXTyFeLDInbzW5Qdqm8sEUuXQ7VLJmAodCXc28XpwyvkSFIen4PEc/S1bB5rkqlTzQyV+IhjbrAZZhqVPgW7UqG80YSR2jfEZUYefCyI0eeGyJzPFKpIVo8PILy6QvHMiDtICs5cKbcOks59sRGYjFYmdIYbJ6s60+tx8jucQGY714+9eGD3kRQjQjX0f3zEKxxFuc6D66EQ/GE2Da/yK+BmlLHnM/8AwkSBS2ZKxre52FXHj+K0Oug+6t0ferkq0LypwnsXnbhx0ZHY1nSLcxeFMpq/9HAGmzxknKj7/NBx//IrcAYqEXlGeCEMr+8CAwEAAXQABVguNTA5fnIAGWphdmEuc2VjdXJpdHkuS2V5UmVwJFR5cGUAAAAAAAAAABIAAHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AAZQVUJMSUM= - - Yt8hFW3b5R6KjqXAg/4R3A== - arWCEeaCwNjKLXUJn909a0ajk5we51rwtOC+RulCk3XR4W0O7bT0aVvPCnhis1UjqUXgjTXHHQ5TqOUblAPxhXO4wDVqkjBzQ8AJdCw9xFPr5nXtns3sG4vEdGQFoUAx+aOhnOslryk0KFSJ/SL7Y6dDkXSsCbeonfiLMNUzpTC949GYXdjAOJ0iQM6Valb3cL/D9NMPehJhHRqGYQ8pJGgxKtSPQJu0SYqpfPHDxTjHmXbwjOxY3rtl6i8S8DFRRX6BBRPbSYcGRFKE7au0v4K1F77ROsnSuGZv5OdR9irSHuRqA9qTty+Gk+VdQMLz0MffLkjpfCDh45B6IJ7NKEgoBdBwr6u/E6ZVlkVVy9I+ogYC4OkpOAZ3YXinh3weHmrp0eS02V0S4g/toWcFw7/KNmbFvyTZA1UAEzRuTEAxnWf0+60kGne/a6t84rJKW3WxaeUq+bg7KZ3/7cLhg7+Odo4YryLmgtgc4p7afnSrWOqvnD8Ye6aIPluxjgny94AoJEirfTgG9CJKR3OIu+fnBDcO2zh/r+nIsLiCeM4JjHfFb1t9bZwCqXsDt0Yey3j4zE8eEYcsBHQSk2BGGu0DkgzlTRkfNURtwDWw1gqZ3XGmf/g7/k3bljxu20Trf61WD00tjRe7gHf/4Y/cF8r5XHi1t7Qs4czLDyKMUTrJupEdk1R6n/cPqmK3nAg3TIYm5dTKKvTcZmgopGpdZP70c+dcNlazvFB+eZt+v0fwjj/NZjVLRZK/xXJKDN28Lr27X2u0GeNFOB8aN025Rz3zfj1jE47XbVcfdzFSBs3Yg6lebNXPH1+WhUvXbvA5A24IzBqzwp1fDShzlh92tTJfYMo4alJQzcYToUFCBufmi/lX3o9XmniDZ1r2EZTktJNKpOlksrF2CGpOfR2/TWFRrLOTnBgxKKXHb07yHzV+wn33x40mViw/GIbqVPMZvD3i/AyAHnBkQLYAwdKxtLz94TUE2223Tkv6pxRIb+yD1TvLsAF2LMNDXOGAkuei3aBJFAcbMOzAJOUFn5ub7gcyfqJ7nILJ+lhLvhMhYmiE//vHJFiXHQbbN+bby1u2kGVyy0r/ntUDLryoLN5rT0xwvuaeGPTijX2LeOHdzqGLoTlHLk/y61eE165Nkc1955RfvmwYETz57gBF2uHLuZR0eLY63MvGspxHJKfne8Z6v+HI6cXGyYr2BHp+Gcv8kBCxlnrlaU5lS09R3Yg8OV19Sg4gW9ZMrfrLv+fQUeT9CmDwR8IJVh1rlIkIh6Ri3ZZSz8pfHHymEr54QbdL4zao1pOOv2mhb70P6DTYPRFVyjHTfQ9k3Z3KZjX7iP2s1EQNmaTATBQc2VvLGEPUG2OXc7PIaxrA5hlpeogmA/RCrscsEuGqNLAQUhFNQz8/VybWzNbzM72dVDDT4zWPdhaURsMJdxhBsAX3GRpLyrHtJbqRbPUlSr7qtXTsoKWMlxYa58F/kUgIXKc4pmHuMAj/V0giF6HuS352QuhXTNsi4TYw22jJvjC/IvXlymTXOFc85qj6ErnChXc2Eln/kJquDJ1kr5i99oV0na3l4UeaWQiekteFaUDjPUXmy9cXnbQ8KWkG1fODUDOJZHoGrtmgkRwvPKbwPdPEBkdKF3JfWAnO0tSoOdaNAKyMf+n/EPR8Ii0mXtiifz9aL4enlV3quvG7s5VsgWi33LXB8qU6XeLThdi0uiONV7TsGbNz7kniBPYcX30hPhWTF9gGMPFWw9uoPESAzY94LPYIviIfYkQlFhUdL7sMlzKw8OlWhmBP9XZgItDwU4X+sIJlmxZGLULGKo4WA0YJIMi4X37/NgcHt1FBTz3jlEvgEbPvwwy0TWwXVrrIDvlTFYKGyps98hxcdJb9RNeHiq6oKrfsfpW6TNOi0BPuylKt4VOZj5ux5V42oKfbQL5ohJSpeNX4YX1bG4Z7vzV9lJ6gBNMD+xNLvvzvUbeh5Y2IH+xo - - noracle-example-alice - diff --git a/example/agent-noracle-example-bob.xml b/example/agent-noracle-example-bob.xml deleted file mode 100644 index ead8320..0000000 --- a/example/agent-noracle-example-bob.xml +++ /dev/null @@ -1,9 +0,0 @@ - - a4efed8afc29949b29ddca70579569dd12d80230d3f77d60fb99112205a413219e927c98bd9ba40f0a46423d353311261bca3484488f872103526e572607c1a6 - rO0ABXNyABRqYXZhLnNlY3VyaXR5LktleVJlcL35T7OImqVDAgAETAAJYWxnb3JpdGhtdAASTGphdmEvbGFuZy9TdHJpbmc7WwAHZW5jb2RlZHQAAltCTAAGZm9ybWF0cQB+AAFMAAR0eXBldAAbTGphdmEvc2VjdXJpdHkvS2V5UmVwJFR5cGU7eHB0AANSU0F1cgACW0Ks8xf4BghU4AIAAHhwAAABJjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIyWNcrjtqnuHaM2eR7hpM/mGJjpaN2b2D5938wzpAXQoLPkKcBaA126mFKxW5Htw9g20eDxa6EiyNMBXapF69zwDzX1LGModEOAkVt2Qd6EccFQO9vuQBNIhlJ4d3cMYGUL7bT98BNvS/qd/QiqBgUqmV5oySaFOLDyMovi23qNBGHVzSHmPCtn8JIYO0RU4yXm5NN/FarUIHtBhaSvpjWzRDQOtT4V7Vta2CVEnVzY+03fVW1dpn756YVZO9sF1o90nU10s2Vv5ejtWxVcTQgKHz7lYWh4Bis0+mxVZsRHILIgCQKaTKuDjwIbCSgxgIUyGCqstClqkf4rpOSURJsCAwEAAXQABVguNTA5fnIAGWphdmEuc2VjdXJpdHkuS2V5UmVwJFR5cGUAAAAAAAAAABIAAHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AAZQVUJMSUM= - - vs1wo5OtTYjifZA5ej/tcw== - fHixyzWZ88OB/lKZQHwWiFW8euVsz7X8Dwb2YTUuISa9N0WMvda8WHWSM/B8C8VAYndWn7qHq85A2W1atH93A+CMLikmyU3SL0NaIqQFi3N7I/wtNZFeufh+U+YrMg8vJ7Lab8cWsPFWsbvzVSny8p+bmbzNrxeQQQAuvEy0/gJ7G64EERMShb8DCiJpgPdw+FGAcUuacrEUYEFVtNKrHqMMG5LXo2VLs8n99aqLt1nOcDBwXiR1qsaXnLjPqa5CPJ1AC9K0VjNqmKXWwPTQl2t2RBJKPwHDQnh4TbpnPRORr7UdlOnR8yyzq9RVDHhLAczdYYkVMwUNx6n+sX6taAPKvhdupTFl/9TgcosPCKdxc1O83MIEKLRs5clWfdvjTZ7OI1Jd/beV0l0J1Q8CjFN+qqZ9Myk7rGxxa1rW/Xprwmbe5vt5wctENJuYOAdLTUg8sU/cNiQDrTjFSnlhlmVozKjhcIXdLid0EWIpm7yFr9a2sCti+M9/4WtMtPwwOzO/N/3H5x/Qak5FrLRgqzIGHMNxny3Sp9tVUCP8TLLiGlI0YtindeixhRy+iIgbZ1W0srCKhilKY9QHKv4j5y64xfONzAO9bUxzsYEHnZqy/UkoVZU1tsyNuRe0NmtIKArfmKHcgHHkgm3K4phFkmvij4OAl9VvfLblrn9D9OSOyXuAFlaykJUzR3/EUNAtU+S54+PlJpMdKT6TmGQ3TcH20Y3yic0Xhhy2q28SimZkZ2kvSKuEC7vZUN6vBHgFfeoAwWOVJmRI25wfQwYuBcn0SuwAbK+BmOK8Hqt5ljDEnhTbLcmXIT+ArJy+vyjxBoDpXv1sUYZry38YKl4Gn6u+qe6zJUqUVgBl9avpwhfaydeZ6y7Z7I1S00aDxf1QIfQXKBNPP9RzBJyBnLnhclCwrm6BtXwnQiIk/blP5UUFczg1YZeSn6IBIzrLYz0I9UCDL6hM51u/fhq/ArBp/pBFc5itz2szXNZLzY9ZYtJXrmC10tgak51jIKEwUxljqeL1ikmC8PTA6iimbFe9Arje+Qs7R9OUWZ37yRklGSAS12ivvt5KFdxYplumT/YoRPyicITWKhNcLTFbdBBNwtaKubMhlx6R1dIVKd4AsoPUQ/GQanU6bS/+F/lPpH6o8IG3LXQUk42wQAIR4cQqQ7zG1OuIVf0jdJ83WG/DYNE+u970NUEPtgfzaaktceFxLTfcjsLm5+wFjD1jRCHf6oo34/aaW/fLJjCFIOfhGoFy2zigwdeiAGAivEnNMWjIEw7jaZwzeEHjwlGLEPmAbiI13EIo3GHWfrhnS57yqBY55AoXb1zFYlZteJViIPvRknZJ4iFWdANykm4eK1KVb9jg1glTyQfZa6nUAVObXCO0UE0JDOqLtP5uQ7i5us98a9wflGYY+wEXoadRuIhcrrnauH8+/GlQuOBeta8QtSSTWDBNfuELGLeU2Ip3K9em/PZZ62NpHBEcO0VXLxwQG5qmI7wwIkjsF82WtenJyKSgFYg0+tAzW/tYt7waETbLnTVrVBmgD2VPwhfOx0Sq/caTqJn05VBtXzd0xXailec61Ie2cg9iff+YPURpKI71o0kLU/6LcJ5srY+teIRtk8k8xy0tXUKnwxFbt7vuT9MNlpQl5CH5FInQ/+XpvCShLAJQ04jaMqPs6jJj4RBbfIKn0f9UC4lDx0YMDTiJWJbO/H+1SnoGXrxkjRMa0t+24lnXFeBQvfoRWO2+M/BsWrFKzIsaLuKHZv+hsEP8hXN17CuQqzQuNYzbgTOekoZqmxWSQtKI7HCspuxuERclQZn/wPgP9hXJ+jjxVvxvh2RpMgvDDlBpL6nDsx7UIOo6fYYPjF6vAdNlgPST5Uz8rahPbtH6OwQWcjkSXXHRK0qviQsaPAYQR7TbdUDHlVgwX4zuW4BRqzTANt8Bwf0E0jGKRJnu9/Bzp0EyWzE3fuyDJ4Zd+V7Zo00FlTjCC1Dq - - noracle-example-bob - diff --git a/example/agent-noracle-example-newbie.xml b/example/agent-noracle-example-newbie.xml deleted file mode 100644 index ab20513..0000000 --- a/example/agent-noracle-example-newbie.xml +++ /dev/null @@ -1,9 +0,0 @@ - - e34da38b1d84b8d8fbf21e1d2d6811bff67c60dfe1f1cba1cfed997ee0fedc5533cc6eef5fb5937cce60693f3fdf3e2987a7b84aa254d7639b343777ed269337 - rO0ABXNyABRqYXZhLnNlY3VyaXR5LktleVJlcL35T7OImqVDAgAETAAJYWxnb3JpdGhtdAASTGphdmEvbGFuZy9TdHJpbmc7WwAHZW5jb2RlZHQAAltCTAAGZm9ybWF0cQB+AAFMAAR0eXBldAAbTGphdmEvc2VjdXJpdHkvS2V5UmVwJFR5cGU7eHB0AANSU0F1cgACW0Ks8xf4BghU4AIAAHhwAAABJjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIdFB/GXg258tZVUPTIbEuZbP5BMduta/2aaFEHtt0r3A+wEifOMxyEe81+HsCAWmFDyQfo5qdKXT6hMcGE+aJPe5Y/ptcbCUpcKJ4kxjfsG4Z04z09qpEMxGqTdmxXA6k7GMtbWG9FfF1F/DCzltGY4VqnaxDQ+7CMNLAfxWUyrS5SOcQtnlmMXaoEl26GzMAMF2220jXDT33HuaClXEhR/HR9I93w9DM7bnn9y3wjhq5nSTrxfvi/NliePDb0tEWF/Ud6lUd+8bMQbhuWv08HVFUw1vBzcWmC2pN6NIOWsSmWMHbJvb9DYyqvZvXZOQpRBDtRw8CmHpbIoPoizbhMCAwEAAXQABVguNTA5fnIAGWphdmEuc2VjdXJpdHkuS2V5UmVwJFR5cGUAAAAAAAAAABIAAHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AAZQVUJMSUM= - - qOGN+RdtIYpfhd32PMGhng== - hUcApUhRm0wnqoDA6h6scB9A/+yyB9gigKGpbigsb3t2QpHVvMpGaEHDzVu8pXI9GgN5xaHABEHhgDsNtJDn/qL79eemsiB7H+H9kgXal6CamHTDWOTtnTkSHI5JSL4S+AAJVgTlp8p/VsGqW6vuiMd0KzXEpFYiZOx6N79p3LLujcTYL8LTAf5M4umrK06LJ2xsvklrYmUqT2TvGGwE8ouFINw6za856sLKSbkn1INfhouvepF3rEgNuaaTbMlnME4aK9VhtRx/lkCvLyF5y67FkBO3L1KCxvFAl02y2d6FjANhMWKEioDRf7Qg+zS3kcs+HC3FenIDSuSAfqMvSqlm3BJGGJXWeDWdAZoxwhMF0Qh7oo05+xmWHesrxu1QdjxNhNXElJxlaFI0Ff7UARckG7hO71xmepKLPdzP0WvI/LKcZH+D0+tL07EztBWEZWk3knaKbPrs5XVxpqnj/a+h4GBzzKQW3Fp2qHkx//xqdfKxArCC584XxhBFZNgpk+O1P81g7GUjKcrRtzN4kO647Vg4hRcVLQSbTyiy3rASuZiNcf5+bAopj/0nLgdf24VnxTE5T1flRc6oExLEVZu5trWUeVX/hWv/Ufp/bJpf3ngkRih6BzaMUl99IR2up9GRQxaMKlOryIZ0BGDZTQIuffYxvFcko1XCAbe65lIDohxCEqRiCF8WnbUgfFnfjR95pBGfcNuQ/UCG/5x7gQZuvOdnM+CspfOYXqBRvM3CnO4T10pRwHxhgUvtCl1IgYHyj3/0Db/dlzzj9ZV+HUrIs0+KswZs8yveFYV7eStAtClVHzFXInJROAegcOfrcd7KTKtTV7ZHFfhZ2lPWeObn93eZ7kmPRN5iE7mlYMeAT/IhJdnSQaWjAFp1L8pkmgK0Dx+AKhNMOU/KGjp3yVgDciifZP9aHFIaOfqHF0chSs9kOJIoS1FgHyuiLp5rGTlIhkA2CmH7YY4bZi7enxL4JLNKOF+x9beediEnypG1neqO8h0P5nXSt4rxAvqe6I+oau9kznNBEjwlHV/D4lZFNa369lITR7mNfWZEXDNvZSPJkfEjSeEu+7RS/3+YgENRI++mnFbC/TzEHSPVq9htJ92QTUv4DniliQ4twUXK7jOKQRT0xHMY6NES+1RAwmsYaX2xOUe+WpgJ5mJFdWtf30TbtCSYRMpl+xocRko3hiPnLWvPDxatJMwwa+vjLFapPbxSbBfy0XJsSh9qZ30TMGOrNnmicnUjT0S63R3JgLErGV9IyQH/E1tZFNGrK42t+EWWh7al/XPC3YhI9lLFaZRx6Lj0WTzj3dFsaeHhK7z0qgyCuz4GdrgP4dFtqpTiUbLzXPe9n5SSByPEFispP7xQxfMwKnne6kZZUJuTnXLz1Y7WpUxB1v3Vh/zudVRIf3y5Mo3r7l/FAhNEONyw6tawEnniNnmjWGxWh7+0Lrx1yr2yx6hx6OStiJ+PDQa3E8j+P9nOJu8wMo/0UN0o3n0Sa9UjXywRsKCDeFn9wB1NQtzGh+F0lHL5owtIoCcIOV/ysKqs7JTH8O0PHTS9Ctlc9u3hmbaWj+/f1VxjqeSQapqbaYc8Dsc1162XNHZG2PedJU/zFU/06N3j3Jb1SUPvthnmZltD7Jac9RlS4WLJSnppbke3i58vN0B4DH50mq1/PKtKGtTiIRfpv/lpwyp0PIxS2G2XrpNpec5JYoW5xBSA8u+pO4XfCCqALKIaeZjqvOs1GR+JEF4XtGDhAufncRBZ3SlVS7jzy2cTbmeb7Xg0+fY+0SmF5JShSpLe6fJ5DTQ85Z8pSXSJiomTSmY3wUiXFM3ANIUU06sAj7YEidLtUoI6WJqdO3DcA7kSJdB2r7kIMVXWk80ykyoZcsX27WGqLxIcaQT9QhrKJGOUrbWlDHcaWjayqZ+5wD9QXG8s0xwHeS42LQUXsScQ8zefd/vLL8QfC85Qc0eM/anzGF9zA4CJ6f3P0YHP - - noracle-example-newbie - diff --git a/example/agent-noracle-example-smith.xml b/example/agent-noracle-example-smith.xml deleted file mode 100644 index 53019d5..0000000 --- a/example/agent-noracle-example-smith.xml +++ /dev/null @@ -1,9 +0,0 @@ - - 762a164ba8eb06d3d110eeeb0321cb75f2624ab311f9c0c4d0e91bdc854a02f389b91573d6c29d70d3071a8a1738cd20fac87d638777dbfcef4ded8be71e2656 - rO0ABXNyABRqYXZhLnNlY3VyaXR5LktleVJlcL35T7OImqVDAgAETAAJYWxnb3JpdGhtdAASTGphdmEvbGFuZy9TdHJpbmc7WwAHZW5jb2RlZHQAAltCTAAGZm9ybWF0cQB+AAFMAAR0eXBldAAbTGphdmEvc2VjdXJpdHkvS2V5UmVwJFR5cGU7eHB0AANSU0F1cgACW0Ks8xf4BghU4AIAAHhwAAABJjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIKDNQFgichoDhwxTh1KqjoewH7H5PwA1NuKgWE/y4UGI7CjfydghJQAOXWiyiZr5Q93xEROyO5uBO4boXuc9594YxR4L70Za3vGBHpMQ4WWWAuIvDLkjOtbK+3qKDeHsW3jCRuT1J53vh5ovm0EXCDx/o2GlymkjOoeK8jSaD6zrRIJZXOdbG60Um8u+A3t6tPxFZrxnMDMucQGSUEjA9Vlrd3xkndiPKB/eZ5QsZ+3q8k4p+i+6bNDxHLQZdPEeQbi4U/9c5othjxO0PYDg6FFqfR+am68kBiajZDfdgjEX3WbcPA9qUMi/a9gPvb1Dp7avRwkSWKVcR9mQ4K5878CAwEAAXQABVguNTA5fnIAGWphdmEuc2VjdXJpdHkuS2V5UmVwJFR5cGUAAAAAAAAAABIAAHhyAA5qYXZhLmxhbmcuRW51bQAAAAAAAAAAEgAAeHB0AAZQVUJMSUM= - - QLhIsGIp8yPX9PeFKIr1IA== - GDXcwAfQcsrp+xCopM/McBm8++CE/h2aKaHG4F7hFUMuAVOy1YRIEe2RPnY5QMWey6er2rU9u7oj+4+bfgmBWnxaCjGHXZGjotmAKjO+2Q03ukqveUp14rZB1SU//QAQ5VCbuy22XHgZjCUgLbGQPTrgdSA/0rUWoSqVrKFDWLpANtiC+A/n734l+r2CBFj14tUYGqdPqoa/qwrpbKH4mf+5xUDN5FsJPNIQL3tyGtVA2mA4sl0bqSAWNyG3om8Dv+cw9ebYMbkF9Yui00TRRZMldGDnOzqqwAWnqO1zvcu5qeC3wHMcSDwDIhJKNuk7PXizeoR2ysxZG9v2Fg58yIrJSXb/aUbmWkjMU9v11I4+scvvxCB1+a1ynn++IIKScjzeUZDOQHFh62kFs1bE4AQbrvJ2Yen3UoSgAyR+ceclwmpFiZbgzW5Uj3DiSwyKxGLd+9PUw6MTFJGRGIUZath0Q2Vk3OyGdSmVQBe0reeTMT20FMaIZT22j6Yx1LGVWp0Y5g8a5V0FS5z6OfjW3n2pdfrGGTXXfio1PayvVH6Wh0EMg4GXf8Hfe66Gc0R5GtsBROGM070GgPMTvQu1qFsEAfGy4/Sas+5wAGa2x/zcQMdEVKDMdL3f12azwcmxqXlAgrZoADb2pdZPU452sJgQ9zrA9GHB0Yn5xwhKJ9y047kpb5MEoYpkydAL6fz/O0Gq2DCiAibKptfKdLlcMH62XZ5WomntoVD7nyC2apqIektfCVVGC1AGrGirYrKglnQQq/IgFeA3FGc3mWgUnMZHTBzlLngh1FAyLGkA1tYyywkxDIYa/nm2/2ZEhTjFfp6xVLbi3+S0CEGZyEmnSe8vCx3+yyzMOIRWJB/LY83d/NkI+1JsnH53Tp8bIwk6BgPFRoMMFFtfeqiMosg7sGYh4A1UTBBX0wABCZ8YUGFDpf7n5VCuMPja5c0RVwJiNBtxEGhBWjF6MKOPBttl1EBpIwjnUEXe086sj/gfjdJGNYL/c8pA6pKoXyBL7ZE3HN1Sc4hqXM7I3nmPHqwy4w7Wh/Rt12gzAOsli2uih5m0vckzFlT2FyMvJiwl+WUJaK4HLuOO7f1vlkigLZdpg39+0LvMBLNL8bulRMhJR/6bZCoX+iXN0d3NHqDKi/gwLnG9dOugnz6eeufF4YgfAiRX7jt+FKO3LgzNJzzp7gMVP8lhRrO/1vwbdxLQ6HxkvSdxjvGz9lqPc3Xy4IS9gYHv+7WocHGSyMSAriImd4qbBVxVGP9akMCh8nOONiNZbw4aDEDqS/n0z822wJNzRv2HlLxj/K4U1Amt9sko3+b8KFt0WtAHr/9TFD1yRvwojQKx9zg/FfwdLrRBTit0vh2o49GYF+QFiByJaMKYLRhT3I28toQMlqdcWdXYheoZYza2lhOrT7xBcG1N5LcK4D09bG7/Yp4GWj0+QDRX/rqpl/Jp9zpx6o9m+KOvv/1orebvr1dHz5pDOl+1ds0wrSTAxYcIyiAlIib0NsLbmQriGwdwFAU8Lq9H7ZAffd356tWeER/HdhnLvYUQ9oQHMDgb5SKhxuB6b3YSNQIEAvh17PjJFMJGPKyRyLRv5RVAHRR4vUbClfLgD11spMyUM0kjXxM16IFPeIEtLLy6hypHC7jdPv1/rkW8GTXMc07XrIZw01HH6kCwA1tFClTAPMLq41X+y4MQP4WwgZ5/Hir5GCMUm4R9Fp/a4TE8zvL4wa9UxI7iIRo8YiTta0D4AWbePVuVWyYCvLB8MTyla+KZpd4Sbu+zk8+GblHipGsE1ttGTx/IpRcB0KVB8iN6lOW1Crs5Z1KbTU3B0zKNN4cbrfHjSI3/vjjkmADlBAKafPaR+O1cRBTVW8kl5S2SiMBwLCn7f+PleXSRlHn866N8pBhbuLZEC1XMZBGW6bosRpzlDTByAj4z3/lET/GnHhPb+mo8bq1Lk+CmnDfJqDW+8ZU5h9JJs+7vG+/TjOST - - noracle-example-smith - diff --git a/example/passphrases.txt b/example/passphrases.txt deleted file mode 100644 index 43f08e9..0000000 --- a/example/passphrases.txt +++ /dev/null @@ -1,4 +0,0 @@ -agent-noracle-example-alice.xml;testtest -agent-noracle-example-bob.xml;testtest -agent-noracle-example-newbie.xml;testtest -agent-noracle-example-smith.xml;testtest \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 339eb62..3430606 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,13 @@ -core.version=1.1.2 +core.version=1.2.1 service.name=i5.las2peer.services.noracleService -service.class=NoracleService -service.version=1.0.0 -java.version=14 \ No newline at end of file +service1.class=NoracleService +service2.class=NoracleVoteService +service3.class=NoracleSpaceService +service4.class=NoracleQuestionService +service5.class=NoracleQuestionRelationService +service6.class=NoracleAgentService +service7.class=NoracleRecommenderService +service8.class=NoracleNormalizationService +service9.class=NoracleQuestionUtilityService +service.version=1.0.1 +java.version=17 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index da9702f..e750102 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..1b6c787 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/kubernetes/noracle-pvc.yaml b/kubernetes/noracle-pvc.yaml new file mode 100644 index 0000000..dd31c9e --- /dev/null +++ b/kubernetes/noracle-pvc.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: noracle-pvc + namespace: ma-breuer +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 8Gi + storageClassName: nfs-client + volumeMode: Filesystem diff --git a/kubernetes/noracle-service.yaml b/kubernetes/noracle-service.yaml new file mode 100644 index 0000000..67ff58c --- /dev/null +++ b/kubernetes/noracle-service.yaml @@ -0,0 +1,35 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: noracle-service + namespace: ma-breuer + labels: + app: noracle-service +spec: + replicas: 1 + selector: + matchLabels: + app: noracle-service + template: + metadata: + labels: + app: noracle-service + spec: + volumes: + - name: noracle-storage-persistent + persistentVolumeClaim: + claimName: noracle-pvc + containers: + - name: noracle-service + image: >- + registry.tech4comp.dbis.rwth-aachen.de/rwthacis/noracle-service:1.0.0 + env: + - name: LAS2PEER_PORT + value: '32061' + - name: NODE_ID_SEED + value: '382251' + - name: BOOTSTRAP + value: las2peer-bootstrap.sbf-dev:32011 + volumeMounts: + - name: noracle-storage-persistent + mountPath: /src/node-storage diff --git a/launcher-configuration.ini b/launcher-configuration.ini deleted file mode 100644 index 4236906..0000000 --- a/launcher-configuration.ini +++ /dev/null @@ -1,22 +0,0 @@ -port = 9081 -storageMode = MEMORY -useMonitoringObserver = false - -[bootstrap] - -[serviceDirectories] -service - -[commands] -uploadStartupDirectory('example') -uploadServicePackage('service/i5.las2peer.services.fileService-2.2.5.jar', 'agent-developer.xml', 'topsecret') -startService('i5.las2peer.services.fileService.FileService@2.2.5','testtest') -uploadServicePackage('service/i5.las2peer.services.noracleService-1.0.0.jar', 'agent-developer.xml', 'topsecret') -startService('i5.las2peer.services.noracleService.NoracleSpaceService@1.0.0','testtest') -startService('i5.las2peer.services.noracleService.NoracleQuestionService@1.0.0','testtest') -startService('i5.las2peer.services.noracleService.NoracleQuestionRelationService@1.0.0','testtest') -startService('i5.las2peer.services.noracleService.NoracleAgentService@1.0.0','testtest') -startService('i5.las2peer.services.noracleService.NoracleVoteService@1.0.0','testtest') -startService('i5.las2peer.services.noracleService.NoracleService@1.0.0','testtest') -startWebConnector -interactive diff --git a/noracle-generate-examples.sh b/noracle-generate-examples.sh deleted file mode 100755 index 6672a3f..0000000 --- a/noracle-generate-examples.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/bash - -endpoint="https://steen.informatik.rwth-aachen.de:9082/distributed-noracle/v1.0.0" - -space_creator_agent_id="762a164ba8eb06d3d110eeeb0321cb75f2624ab311f9c0c4d0e91bdc854a02f389b91573d6c29d70d3071a8a1738cd20fac87d638777dbfcef4ded8be71e2656" -space_creator_agent_login="noracle-example-smith" - -agent_pw="testtest" - -num_spaces=5 -num_questions_per_space=25 -num_relations_per_space=15 - -relation_types=() -relation_types+=("\"name\": \"Similarity\", \"directed\": \"false\"") -relation_types+=("\"name\": \"FollowUp\", \"directed\": \"true\"") -relation_types+=("\"name\": \"LinksWith\", \"directed\": \"false\"") - -random_lengthLorem() { - #1703 chars - question_text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi." - # should be possible to at least print 200 chars - start=$((RANDOM % ((${#question_text} - (RANDOM % 1500))))) - # max 500 chars, not more then avaible after starting position - printf '%s' "${question_text:$start:(RANDOM % (500 % (1703-$start)))}" -} - -# create example spaces - -for (( num=1; num<=${num_spaces}; num++ )); do - curl -s -D - --user noracle-example-smith:${agent_pw} -X POST --header 'Content-Type: application/json' -d '{ "name": "example-space-'"${num}"'" }' "${endpoint}"'/spaces' --insecure & -done -# wait till all requests terminated -wait - - -# get all subscribed spaces for agent smith -example_space_ids=() -out="$( { curl -s --user noracle-example-smith:${agent_pw} -X GET --header 'Accept: application/json' "${endpoint}"'/agents/'"${space_creator_agent_id}"'/spacesubscriptions' --insecure ; } 2>&1 )" -while read spaceId ; do - example_space_ids+=("${spaceId}") -done < <(echo "${out}" | jq -r '.[].spaceId') - -for spaceId in "${example_space_ids[@]}" ; do - # create questions inside space - question_ids=() - for (( num=1; num<=${num_questions_per_space}; num++ )); do - random=$(random_lengthLorem) - out="$( { curl -s -D - --user noracle-example-smith:"${agent_pw}" -X POST --header 'Content-Type: application/json' -d '{ "text": "'"${random}"'" }' "${endpoint}"'/spaces/'"${spaceId}"'/questions' --insecure ; } 2>&1 )" - echo "${out}" - location_header="$( echo "${out}" | tr -d '\r' | sed -En 's/^Location: (.*)/\1/p' )" - question_id=${location_header##*/} - if [ -n "${question_ids}" ]; then # relate to existing question (if any exists) - relation_type=${relation_types[$RANDOM % ${#relation_types[@]} ]} - first_question_id=${question_ids[$RANDOM % ${#question_ids[@]} ]} - second_question_id=${question_ids[$RANDOM % ${#question_ids[@]} ]} - out="$( { curl -s -D - --user noracle-example-smith:"${agent_pw}" -X POST --header 'Content-Type: application/json' -d '{ '"${relation_type}"', "firstQuestionId": "'"${first_question_id}"'", "secondQuestionId": "'"${second_question_id}"'" }' "${endpoint}"'/spaces/'"${spaceId}"'/relations' --insecure ; } 2>&1 )" - echo "${out}" - fi - question_ids+=(${question_id}) - done - # create random relations between questions - for (( num=1; num<=${num_relations_per_space}; num++ )); do - relation_type=${relation_types[$RANDOM % ${#relation_types[@]} ]} - first_question_id=${question_ids[$RANDOM % ${#question_ids[@]} ]} - second_question_id=${question_ids[$RANDOM % ${#question_ids[@]} ]} - out="$( { curl -s -D - --user noracle-example-smith:"${agent_pw}" -X POST --header 'Content-Type: application/json' -d '{ '"${relation_type}"', "firstQuestionId": "'"${first_question_id}"'", "secondQuestionId": "'"${second_question_id}"'" }' "${endpoint}"'/spaces/'"${spaceId}"'/relations' --insecure ; } 2>&1 )" - echo "${out}" - done -done - -# generate join links -space_join_links="" -for spaceId in "${example_space_ids[@]}" ; do - out="$( { curl -s -D - --user noracle-example-smith:${agent_pw} -X GET --header 'Accept: application/json' "${endpoint}"'/spaces/'"${spaceId}" --insecure ; } 2>&1 )" - while read spaceSecret ; do - space_join_links="${space_join_links}
Click here to join example space ${spaceId}
" - done < <(echo "${out}" | jq -r '.spaceSecret') -done - -# write invitation links to file -read -d '' join_space_file_content <<- EOF - - -Join A Noracle Example Space - - -

Please click on a link below to join the appropriate Noracle example space

-${space_join_links} - - - -EOF - -echo "${join_space_file_content}" > "join-example-space.html" - diff --git a/noracleService/build.gradle b/noracleService/build.gradle index f4869c4..656be68 100644 --- a/noracleService/build.gradle +++ b/noracleService/build.gradle @@ -1,17 +1,18 @@ plugins { // Apply the application plugin to add support for building a CLI application in Java. id 'application' - id 'eclipse' + // id 'eclipse' id 'jacoco' } repositories { // Use JCenter for resolving dependencies. - jcenter() + mavenCentral() // DBIS Archiva maven { url "https://archiva.dbis.rwth-aachen.de:9911/repository/internal/" + //url "https://repo1.maven.org/maven2/" } } @@ -34,23 +35,24 @@ dependencies { // las2peer bundle which is not necessary in the runtime path // compileOnly will be moved into the lib dir afterwards - compileOnly "i5:las2peer-bundle:${project.property('core.version')}" - compile urlFile("https://github.com/rwth-acis/las2peer-FileService/releases/download/2.2.5/i5.las2peer.services.fileService-2.2.5.jar", 'i5.las2peer.services.fileService-2.2.5') + implementation "i5:las2peer-bundle:${project.property('core.version')}" + // compile urlFile("https://github.com/rwth-acis/las2peer-FileService/releases/download/2.2.5/i5.las2peer.services.fileService-2.2.5.jar", 'i5.las2peer.services.fileService-2.2.5') // Add service dependencies here implementation 'com.google.code.gson:gson:2.8.7' - - + implementation 'org.apache.lucene:lucene-analyzers-common:8.0.0' + implementation 'com.github.jaytaylor:jaws:1.3.1' + implementation 'info.debatty:java-string-similarity:2.0.0' } configurations { // This ensures las2peer is available in the tests, but won't be bundled - testCompile.extendsFrom compileOnly + testImplementation.extendsFrom implementation } jar { manifest { - attributes "Main-Class": "${project.property('service.name')}.${project.property('service.class')}" + attributes "Main-Class": "${project.property('service.name')}.${project.property('service1.class')}" attributes "Library-Version": "${project.property('service.version')}" attributes "Library-SymbolicName": "${project.property('service.name')}" } @@ -63,20 +65,23 @@ jar { application { // Define the main class for the application. - mainClass = "${project.property('service.name')}.${project.property('service.class')}" + mainClass = "${project.property('service.name')}.${project.property('service1.class')}" group = "${project.property('service.name')}" archivesBaseName = group version = "${project.property('service.version')}" - mainClassName = "i5.las2peer.tools.L2pNodeLauncher" + //mainClassName = "i5.las2peer.tools.L2pNodeLauncher" + mainClass.set("i5.las2peer.tools.L2pNodeLauncher") sourceCompatibility = "${project.property('java.version')}" targetCompatibility = "${project.property('java.version')}" } // put all .jar files into export/jars folder tasks.withType(Jar) { - destinationDir = file("$projectDir/export/jars") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + destinationDirectory = file("$projectDir/export/jars") } javadoc { @@ -126,13 +131,21 @@ task startscripts { new File("$rootDir/bin", "start_network.sh").text = """#!/bin/bash # this script is autogenerated by 'gradle startscripts' -# it starts a las2peer node providing the service '${project.property('service.name')}.${project.property('service.class')}' of this project +# it starts a las2peer node providing the service '${project.property('service.name')}.${project.property('service1.class')}' of this project # pls execute it from the root folder of your deployment, e. g. ./bin/start_network.sh -java -cp "lib/*" i5.las2peer.tools.L2pNodeLauncher --port 9011 --service-directory service uploadStartupDirectory startService\\(\\'${project.property('service.name')}.${project.property('service.class')}@${project.property('service.version')}\\'\\) startWebConnector interactive +java -cp "lib/*" --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED i5.las2peer.tools.L2pNodeLauncher --port 9012 --service-directory service uploadStartupDirectory \\ + startService\\(\\'${project.property('service.name')}.${project.property('service1.class')}@${project.property('service.version')}\\'\\) \\ + startService\\(\\'${project.property('service.name')}.${project.property('service2.class')}@${project.property('service.version')}\\'\\) \\ + startService\\(\\'${project.property('service.name')}.${project.property('service3.class')}@${project.property('service.version')}\\'\\) \\ + startService\\(\\'${project.property('service.name')}.${project.property('service4.class')}@${project.property('service.version')}\\'\\) \\ + startService\\(\\'${project.property('service.name')}.${project.property('service5.class')}@${project.property('service.version')}\\'\\) \\ + startService\\(\\'${project.property('service.name')}.${project.property('service6.class')}@${project.property('service.version')}\\'\\) \\ + startService\\(\\'${project.property('service.name')}.${project.property('service7.class')}@${project.property('service.version')}\\'\\) \\ + startWebConnector interactive """ new File("$rootDir/bin", "start_network.bat").text = """:: this script is autogenerated by 'gradle startscripts' -:: it starts a las2peer node providing the service '${project.property('service.name')}.${project.property('service.class')}' of this project +:: it starts a las2peer node providing the service '${project.property('service.name')}.${project.property('service1.class')}' of this project :: pls execute it from the bin folder of your deployment by double-clicking on it %~d0 @@ -140,8 +153,9 @@ cd %~p0 cd .. set BASE=%CD% set CLASSPATH="%BASE%/lib/*;" +set ADD_OPENS=--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED -java -cp %CLASSPATH% i5.las2peer.tools.L2pNodeLauncher --port 9011 --service-directory service uploadStartupDirectory startService('${project.property('service.name')}.${project.property('service.class')}@${project.property('service.version')}') startWebConnector interactive +java -cp %CLASSPATH% %ADD_OPENS% i5.las2peer.tools.L2pNodeLauncher --port 9011 --service-directory service uploadStartupDirectory startService('${project.property('service.name')}.${project.property('service1.class')}@${project.property('service.version')}', 'ans') startService('${project.property('service.name')}.${project.property('service2.class')}@${project.property('service.version')}', 'ans') startService('${project.property('service.name')}.${project.property('service3.class')}@${project.property('service.version')}', 'ans') startService('${project.property('service.name')}.${project.property('service4.class')}@${project.property('service.version')}', 'ans') startService('${project.property('service.name')}.${project.property('service5.class')}@${project.property('service.version')}', 'ans') startService('${project.property('service.name')}.${project.property('service6.class')}@${project.property('service.version')}', 'ans') startService('${project.property('service.name')}.${project.property('service7.class')}@${project.property('service.version')}', 'ans') startWebConnector interactive pause """ @@ -168,7 +182,7 @@ task cleanAll { } jacoco { - toolVersion = "0.8.6" + toolVersion = "0.8.7" reportsDirectory = file("$projectDir/export/jacoco") } @@ -185,12 +199,13 @@ jacocoTestReport { // enable the xml report (html is also enabled) reports { - xml.enabled true + // xml.enabled true + xml.required.set(true) } } // configuration for eclipse (this allows to import the template project as a gradle project in eclipse without any problems) -eclipse { +/*eclipse { classpath { file { whenMerged { @@ -206,4 +221,4 @@ eclipse { } } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleAgentService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleAgentService.java index 9be2772..2cdc51d 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleAgentService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleAgentService.java @@ -15,10 +15,10 @@ import i5.las2peer.services.noracleService.model.NoracleAgentProfile; import i5.las2peer.services.noracleService.model.SpaceSubscription; import i5.las2peer.services.noracleService.model.SpaceSubscriptionList; -import i5.las2peer.services.noracleService.resources.SpacesResource; +import java.util.Arrays; import java.util.Iterator; -import java.util.logging.Level; +import java.util.List; /** * Noracle Agents Service @@ -37,6 +37,12 @@ public SpaceSubscription subscribeToSpace(String spaceId, String spaceSecret) th } else if (mainAgent instanceof AnonymousAgent) { throw new ServiceAccessDeniedException("You have to be logged in to subscribe to a space"); } + + // Check if we are already subscribed to space + if (checkIfAlreadySubscribedToSpace(mainAgent.getIdentifier(), spaceId)) { + return new SpaceSubscription(spaceId, spaceSecret); + } + Context.get().invoke( new ServiceNameVersion(NoracleSpaceService.class.getCanonicalName(), NoracleService.API_VERSION), "joinSpace", spaceId, spaceSecret); @@ -47,8 +53,10 @@ public SpaceSubscription subscribeToSpace(String spaceId, String spaceSecret) th try { try { env = Context.get().requestEnvelope(envIdentifier); + //logger.info("(SpaceSubscriptionList) env.getContent()"); subscriptionList = (SpaceSubscriptionList) env.getContent(); } catch (EnvelopeNotFoundException e) { + //logger.info("Context.get().createEnvelope(envIdentifier);"); env = Context.get().createEnvelope(envIdentifier); subscriptionList = new SpaceSubscriptionList(); } @@ -57,6 +65,7 @@ public SpaceSubscription subscribeToSpace(String spaceId, String spaceSecret) th } catch (EnvelopeOperationFailedException e) { throw new InternalServiceException("Could not create envelope for space subscription", e); } + //logger.info("subscriptionList.add(subscription);"); subscriptionList.add(subscription); env.setContent(subscriptionList); try { @@ -66,9 +75,49 @@ public SpaceSubscription subscribeToSpace(String spaceId, String spaceSecret) th } catch (EnvelopeOperationFailedException e) { throw new InternalServiceException("Could not store space subscription envelope", e); } + //logger.info("return subscription"); + //logger.info(subscription.toString()); + //logger.info(subscription.getSpaceId()); return subscription; } + @Override + public Boolean checkIfAlreadySubscribedToSpace(String agentId, String spaceId) throws ServiceInvocationException { + //logger.info("NoracleAgentService -> checkIfAlreadySubscribedToSpace(...)"); + SpaceSubscriptionList subscriptionList = getSubscriptionListForAgent(agentId); + if (subscriptionList == null) { + return false; + } + Iterator itSubscription = subscriptionList.iterator(); + while (itSubscription.hasNext()) { + SpaceSubscription subscription = itSubscription.next(); + if (subscription.getSpaceId().equals(spaceId)) { + return true; + } + } + return false; + } + + public SpaceSubscriptionList getSubscriptionListForAgent(String agentId) throws ServiceInvocationException { + //logger.info("NoracleAgentService -> getSubscriptionListForAgent(...)"); + String envIdentifier = buildSubscriptionId(agentId); + Envelope env; + SpaceSubscriptionList subscriptionList; + try { + try { + env = Context.get().requestEnvelope(envIdentifier); + subscriptionList = (SpaceSubscriptionList) env.getContent(); + } catch (EnvelopeNotFoundException e) { + return null; + } + } catch (EnvelopeAccessDeniedException e) { + throw new ServiceAccessDeniedException("Envelope Access Denied"); + } catch (EnvelopeOperationFailedException e) { + throw new InternalServiceException("Could not read envelope for space unsubscription", e); + } + return subscriptionList; + } + @Override public void unsubscribeFromSpace(String spaceId) throws ServiceInvocationException { Agent mainAgent = Context.get().getMainAgent(); @@ -111,10 +160,21 @@ public void unsubscribeFromSpace(String spaceId) throws ServiceInvocationExcepti @Override public SpaceSubscriptionList getSpaceSubscriptions(String agentId) throws ServiceInvocationException { + //logger.info("NoracleAgentService -> getSpaceSubscriptions(...)"); + //long start = System.currentTimeMillis(); String envIdentifier = buildSubscriptionId(agentId); try { + //logger.info("Context.get().requestEnvelope(envIdentifier);"); Envelope env = Context.get().requestEnvelope(envIdentifier); - return (SpaceSubscriptionList) env.getContent(); + //logger.info("(SpaceSubscriptionList) env.getContent()"); + SpaceSubscriptionList spaceSubscriptionList = (SpaceSubscriptionList) env.getContent(); + //logger.info("Size of List: " + spaceSubscriptionList.size()); + //for (SpaceSubscription s : spaceSubscriptionList) { + //logger.info(s.getSpaceId()); + //} + //long end = System.currentTimeMillis(); + //System.out.println("getSpaceSubscriptions(...) took in seconds: "+ ((end-start) / 1000.0)); + return spaceSubscriptionList; } catch (EnvelopeAccessDeniedException e) { throw new ServiceAccessDeniedException("Envelope Access Denied"); } catch (EnvelopeOperationFailedException e) { @@ -126,16 +186,18 @@ public SpaceSubscriptionList getSpaceSubscriptions(String agentId) throws Servic } @Override - public SpaceSubscription updateSpaceSubscription(String agentId, String spaceId, String[] selectedQuestions) + public SpaceSubscription updateSpaceSubscription(String agentId, String spaceId, List selectedQuestions) throws ServiceInvocationException { Agent mainAgent = Context.get().getMainAgent(); String envIdentifier = buildSubscriptionId(agentId); + try { Envelope env = Context.get().requestEnvelope(envIdentifier); SpaceSubscriptionList spaceSubscriptionList = (SpaceSubscriptionList) env.getContent(); for (SpaceSubscription spaceSubscription : spaceSubscriptionList) { if (spaceSubscription.getSpaceId().equals(spaceId)) { - spaceSubscription.setSelectedQuestionIds(selectedQuestions); + // TODO: is this line important? + // spaceSubscription.setSelectedQuestionIds(selectedQuestions); env.setContent(spaceSubscriptionList); try { Context.get().storeEnvelope(env, mainAgent); @@ -159,6 +221,7 @@ public SpaceSubscription updateSpaceSubscription(String agentId, String spaceId, @Override public NoracleAgentProfile updateAgentProfile(String agentName) throws ServiceInvocationException { + logger.info("NoracleAgentService -> updateAgentProfile(...)"); Agent mainAgent = Context.get().getMainAgent(); String envIdentifier = buildAgentProfileId(mainAgent.getIdentifier()); Envelope env; @@ -217,6 +280,6 @@ private String buildAgentProfileId(String agentId) { return "noracleagentprofile-" + agentId; } - private final L2pLogger logger = L2pLogger.getInstance(SpacesResource.class.getName()); + private final L2pLogger logger = L2pLogger.getInstance(NoracleAgentService.class.getName()); } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleNormalizationService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleNormalizationService.java new file mode 100644 index 0000000..7da3a67 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleNormalizationService.java @@ -0,0 +1,128 @@ +package i5.las2peer.services.noracleService; + +import edu.smu.tspell.wordnet.Synset; +import edu.smu.tspell.wordnet.WordNetDatabase; +import i5.las2peer.api.Service; +import i5.las2peer.logging.L2pLogger; +import i5.las2peer.services.noracleService.api.INoracleNormalizationService; +import i5.las2peer.services.noracleService.model.Question; +import i5.las2peer.services.noracleService.model.VotedQuestion; + +import i5.las2peer.services.noracleService.model.VotedQuestionList; +import org.tartarus.snowball.ext.PorterStemmer; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; + +public class NoracleNormalizationService extends Service implements INoracleNormalizationService { + + @Override + public VotedQuestion normalizeQuestion(VotedQuestion question) { + logger.info("NoracleNormalizationService -> normalizeQuestion(...) called"); + VotedQuestion normQuestion = new VotedQuestion(question); + String text = normQuestion.getText(); + // 1. to lower case + text = text.toLowerCase(); + + // 2. Expanding contractions + text = expandContractions(text); + + // 3. Removing dashes + text = text.replaceAll("[\\s\\-()]", " "); + + // 4. Remove stop words + text = removeStopWords(text); + + // 5. Stemming + text = stemming(text); + + // 6. Remove all non-letter characters + //text = text.replaceAll("[^a-zA-Z ]", ""); + + // 7. Replacing words with synonyms + // TODO: Do actual replacing with words or index which leads to a pool of synonyms + //text = replaceWithSynonyms(text); + + normQuestion.setText(text); + + return normQuestion; + } +private String replaceWithSynonyms(String text) { + // TODO: Do actual replacing with words or index which leads to a pool of synonyms + File f = new File("WordNet/2.1/dict"); + System.setProperty("wordnet.database.dir", f.toString()); + WordNetDatabase database = WordNetDatabase.getFileInstance(); + Synset[] synsets; + try { + synsets = database.getSynsets(text); + } catch (Exception ex) { + throw ex; + } + if (synsets.length > 0) { + ArrayList al = new ArrayList<>(); + // add elements to al, including duplicates + HashSet hs = new HashSet(); + for (int i = 0; i < synsets.length; i++) { + String[] wordForms = synsets[i].getWordForms(); + for (int j = 0; j < wordForms.length; j++) + { + al.add(wordForms[j]); + } + + + //removing duplicates + hs.addAll(al); + al.clear(); + al.addAll(hs); + } + //showing all synsets + for (int k = 0; k < al.size(); k++) { + //System.out.println(al.get(k)); + } + } else { + //System.err.println("No synsets exist that contain the word form '" + wordForm + "'"); + } + return text; + } + + + private String removeStopWords(String inputString) { + inputString = inputString.replace(" a ", " "); + inputString = inputString.replace(" the ", " "); + // inputString = inputString.replace(" is ", " "); + inputString = inputString.replace(" are ", " "); + return inputString; + } + + @Override + public VotedQuestionList normalizeQuestions(VotedQuestionList questionList) { + logger.info("NoracleNormalizationService -> normalizeQuestions(...) called"); + questionList.stream().forEach(q -> logger.info(q.getText())); + VotedQuestionList normQuestionList = new VotedQuestionList(); + for (VotedQuestion q : questionList) { + VotedQuestion normQ = normalizeQuestion(q); + normQuestionList.add(normQ); + } + return normQuestionList; + } + + private String expandContractions(String inputString) { + inputString = inputString.replaceAll("n't", " not"); + inputString = inputString.replaceAll("'re", " are"); + inputString = inputString.replaceAll("'m", " am"); + inputString = inputString.replaceAll("'ll", " will"); + inputString = inputString.replaceAll("'ve", " have"); + inputString = inputString.replaceAll("'s", " is"); + return inputString; + } + + private String stemming(String string) { + PorterStemmer stem = new PorterStemmer(); + stem.setCurrent(string); + stem.stem(); + return stem.getCurrent(); + } + + private final L2pLogger logger = L2pLogger.getInstance(NoracleNormalizationService.class.getName()); +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionRelationService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionRelationService.java index cf7171d..0e8cb59 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionRelationService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionRelationService.java @@ -9,11 +9,14 @@ import i5.las2peer.api.persistency.EnvelopeOperationFailedException; import i5.las2peer.api.security.Agent; import i5.las2peer.api.security.AnonymousAgent; +import i5.las2peer.logging.L2pLogger; import i5.las2peer.services.noracleService.api.INoracleQuestionRelationService; import i5.las2peer.services.noracleService.model.QuestionRelation; import i5.las2peer.services.noracleService.model.QuestionRelationList; import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import java.util.Random; /** @@ -156,8 +159,8 @@ public QuestionRelationList getQuestionRelations(String spaceId, String order, I } catch (EnvelopeNotFoundException e) { break; } - String questionId = (String) spaceQuestionRelationEnv.getContent(); - Envelope questionEnv = Context.get().requestEnvelope(getQuestionRelationEnvelopeIdentifier(questionId)); + String relationId = (String) spaceQuestionRelationEnv.getContent(); + Envelope questionEnv = Context.get().requestEnvelope(getQuestionRelationEnvelopeIdentifier(relationId)); result.add((QuestionRelation) questionEnv.getContent()); } catch (Exception e) { // XXX logging @@ -201,4 +204,34 @@ public QuestionRelation changeQuestionRelation(String relationId, String name, S } } + @Override + public List getQuestionRelationIds(String spaceId, String questionId) { + List questionRelations = new ArrayList<>(); + Envelope spaceQuestionRelationEnv; + Envelope questionEnv; + for (int relationNumber = 1; relationNumber < MAX_RELATIONS_PER_SPACE; ++relationNumber) { + try { + spaceQuestionRelationEnv = Context.get().requestEnvelope(buildSpaceQuestionRelationNumberId(spaceId, relationNumber)); + String relationId = (String) spaceQuestionRelationEnv.getContent(); + questionEnv = Context.get().requestEnvelope(getQuestionRelationEnvelopeIdentifier(relationId)); + QuestionRelation qr = (QuestionRelation) questionEnv.getContent(); + if (qr.getFirstQuestionId().equals(questionId)) { + questionRelations.add(qr.getSecondQuestionId()); + } else if (qr.getSecondQuestionId().equals(questionId)) { + questionRelations.add(qr.getFirstQuestionId()); + } else { + // do nothing, no necessary relation + } + } catch (EnvelopeNotFoundException e) { + break; // no relation left + } catch (EnvelopeOperationFailedException e) { + e.printStackTrace(); + } catch (EnvelopeAccessDeniedException e) { + e.printStackTrace(); + } + } + return questionRelations; + } + + private final L2pLogger logger = L2pLogger.getInstance(NoracleRecommenderService.class.getName()); } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionService.java index 14f674c..78be599 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionService.java @@ -9,13 +9,14 @@ import i5.las2peer.api.persistency.EnvelopeNotFoundException; import i5.las2peer.api.persistency.EnvelopeOperationFailedException; import i5.las2peer.api.security.*; +import i5.las2peer.logging.L2pLogger; import i5.las2peer.services.noracleService.api.INoracleQuestionService; -import i5.las2peer.services.noracleService.model.Question; -import i5.las2peer.services.noracleService.model.QuestionList; -import i5.las2peer.services.noracleService.model.Space; +import i5.las2peer.services.noracleService.model.*; +import i5.las2peer.services.noracleService.resources.QuestionVotesResource; import java.io.Serializable; import java.time.Instant; +import java.util.ArrayList; import java.util.Random; /** @@ -76,7 +77,7 @@ public Question createQuestion(String questionSpaceId, String text) throws Servi } env.addReader(targetReaderGroup); Question question = new Question(questionId, text, questionSpaceId, mainAgent.getIdentifier(), - Instant.now().toString()); + Instant.now().toString());; env.setContent(question); try { Context.get().storeEnvelope(env, mainAgent); @@ -141,7 +142,7 @@ public Question getQuestion(String questionId) throws ServiceInvocationException private String buildQuestionId() { String result = ""; - for (int c = 0; c < 10; c++) { + for (int c = 0; c < 20; c++) { result += myRandom.nextInt(10); } return result; @@ -191,25 +192,93 @@ public QuestionList getQuestions(String spaceId, String order, Integer limit, In return result; } + public QuestionList getAllQuestions(String spaceId) { + QuestionList questionList = new QuestionList(); + for (int questionNumber = 1; questionNumber < MAX_QUESTIONS_PER_SPACE; questionNumber++) { + try { + if (!retrieveQuestion(questionList, spaceId, questionNumber)) { + break; + } + } catch (EnvelopeNotFoundException e) { + break; + } + } + return questionList; + } + + @Override + public VotedQuestionList getAllVotedQuestions(String spaceId) throws ResourceNotFoundException { + //logger.info("NoracleQuestionService -> getAllVotedQuestions(...) called"); + VotedQuestionList votedQuestionList = new VotedQuestionList(); + QuestionList questionList = new QuestionList(); + for (int questionNumber = 1; questionNumber < MAX_QUESTIONS_PER_SPACE; questionNumber++) { + try { + if (!retrieveQuestion(questionList, spaceId, questionNumber)) { + break; + } + } catch (EnvelopeNotFoundException e) { + break; // found free question number + } + } + + //logger.info("Found " + questionList.size() + " questions!"); + + for (Question question : questionList) { + VotedQuestion votedQuestion = new VotedQuestion(question); + String objectId = QuestionVotesResource.buildObjectId(spaceId, question.getQuestionId()); + //logger.info("objectId: " + objectId); + Serializable rmiResult = null; + try { + rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleVoteService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAllVotes", objectId); + } catch (Exception ex) { + ex.printStackTrace(); + } + if (rmiResult instanceof VoteList) { + //System.out.println("rmiResult instanceof VoteList"); + VoteList list = (VoteList) rmiResult; + if (list != null) { + //list.stream().forEach(v -> System.out.println(v.getValue())); + } + votedQuestion.setVotes((VoteList) rmiResult); + //System.out.println(votedQuestion.getVotes().size()); + } + votedQuestionList.add(votedQuestion); + } + + return votedQuestionList; + } + + @Override + public ArrayList getAllVotedQuestions(String spaceId, String agentId) throws ServiceInvocationException { + ArrayList questionList = getAllVotedQuestions(spaceId); + questionList.removeIf(q -> !q.getAuthorId().equals(agentId)); +/* for (VotedQuestion q : questionList) { + if (!q.getAuthorId().equals(agentId)) { + questionList.remove(q); + } + }*/ + return questionList; + } + private boolean retrieveQuestion(QuestionList result, String spaceId, int questionNumber) throws EnvelopeNotFoundException { try { Envelope spaceQuestionEnv = Context.get() .requestEnvelope(buildSpaceQuestionNumberId(spaceId, questionNumber)); String questionId = (String) spaceQuestionEnv.getContent(); + // logger.info("Found question with questionId: " + questionId); Envelope questionEnv = Context.get().requestEnvelope(getQuestionEnvelopeIdentifier(questionId)); Question question = (Question) questionEnv.getContent(); - // TODO check if author is a member of this space? -// String authorId = question.getAuthorId(); -// if (authorId == null || authorId.isEmpty()) { -// return false; -// } + result.add(question); return true; } catch (EnvelopeNotFoundException e) { throw e; } catch (Exception e) { - // XXX logging + // logger.warning("Exception inside NoracleQuestionService -> retrieveQuestion(...)"); + e.printStackTrace(); } return false; } @@ -258,4 +327,6 @@ public Question changeQuestionDepth(String questionId, int depth) throws Service } } + private final L2pLogger logger = L2pLogger.getInstance(NoracleQuestionService.class.getName()); + } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionUtilityService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionUtilityService.java new file mode 100644 index 0000000..71b1582 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleQuestionUtilityService.java @@ -0,0 +1,140 @@ +package i5.las2peer.services.noracleService; + +import i5.las2peer.api.Context; +import i5.las2peer.api.Service; +import i5.las2peer.api.execution.*; +import i5.las2peer.api.p2p.ServiceNameVersion; +import i5.las2peer.logging.L2pLogger; +import i5.las2peer.services.noracleService.api.INoracleQuestionUtilityService; +import i5.las2peer.services.noracleService.model.*; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import info.debatty.java.stringsimilarity.Cosine; + +public class NoracleQuestionUtilityService extends Service implements INoracleQuestionUtilityService { + + // weights + private final double cosineSimilarityWeight = 0.25; + private final double voteSimilarityWeight = 0.25; + private final double relativeVoteCountWeight = 0.5; + + private final Cosine cosine = new Cosine(); + + @Override + public HashMap computeUtilityForQuestions(String agentId, VotedQuestionList questions) { + logger.info("NoracleQuestionUtilityService -> computeUtilityForQuestions(...)"); + HashMap utilityMap = new HashMap<>(); + double utility; + for (VotedQuestion q : questions) { + utility = 0.0; + if (!q.getAuthorId().equals(agentId)) { + // begin simple + double cosineSimilarity = computeMaxCosineSimilarity(agentId, q); + double voteSimilarity = computeMaxVoteSimilarity(agentId, q); + double relativeVoteCount = computeRelativeVoteCount(questions, q); + + utility = cosineSimilarityWeight * cosineSimilarity + + voteSimilarityWeight * voteSimilarity + + relativeVoteCountWeight * relativeVoteCount; + } + + utilityMap.put(q.getQuestionId(), utility); + } + return utilityMap; + } + + private double computeMaxCosineSimilarity(String agentId, VotedQuestion question) { + logger.info("NoracleQuestionUtilityService -> computeMaxCosineSimilarity(...)"); + double maxCosineSimilarity = 0.0; + String spaceId = question.getSpaceId(); + try { + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleQuestionService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAllVotedQuestions", spaceId, agentId); + + VotedQuestionList userQuestions = (VotedQuestionList) rmiResult; + for (VotedQuestion userQuestion : userQuestions) { + double cosineSimilarity = cosine.similarity(userQuestion.getText(), question.getText()); + maxCosineSimilarity = Math.max(maxCosineSimilarity, cosineSimilarity); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + logger.info("maxCosineSimilarity: " + maxCosineSimilarity); + return maxCosineSimilarity; + } + + private double computeMaxVoteSimilarity(String agentId, VotedQuestion question) { + logger.info("NoracleQuestionUtilityService -> computeMaxVoteSimilarity(...)"); + double maxVoteSimilarity = 0.0; + String spaceId = question.getSpaceId(); + try { + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleQuestionService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAllVotedQuestions", spaceId, agentId); + + VotedQuestionList userQuestions = (VotedQuestionList) rmiResult; + for (VotedQuestion userQuestion : userQuestions) { + double voteSimilarity = computeVoteSimilarity(userQuestion, question); + maxVoteSimilarity = Math.max(maxVoteSimilarity, voteSimilarity); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + logger.info("maxVoteSimilarity: " + maxVoteSimilarity); + return maxVoteSimilarity; + } + + private double computeVoteSimilarity(VotedQuestion q1, VotedQuestion q2) { + VoteList v1 = q1.getVotes(); + VoteList v2 = q2.getVotes(); + Map noOfUsers = new HashMap<>(); + + for (Vote v : v1) { + noOfUsers.put(v.getVoterAgentId(), 1); + } + + for (Vote v : v2) { + if (noOfUsers.containsKey(v.getVoterAgentId())) { + noOfUsers.put(v.getVoterAgentId(), 2); + } else { + noOfUsers.put(v.getVoterAgentId(), 1); + } + } + + int noOfDistinctUsers = 0; + for (var entry : noOfUsers.entrySet()) { + if (entry.getValue() == 2) { + noOfDistinctUsers++; + } + } + + if (noOfUsers.size() == 0) { + return 0.0; + } else { + return (double) noOfDistinctUsers / noOfUsers.size(); + } + } + + private double computeRelativeVoteCount(VotedQuestionList questions, VotedQuestion q) { + logger.info("NoracleQuestionUtilityService -> computeRelativeVoteCount(...)"); + int voteCount = q.getVotes().size(); + int voteCountAll = 0; + for (VotedQuestion question : questions) { + voteCountAll += question.getVotes().size(); + } + double relativeVoteCount = 0.0; + if (voteCountAll != 0) { + relativeVoteCount = (1.0 / voteCountAll) * voteCount; + } + logger.info("relativeVoteCount: " + relativeVoteCount); + return relativeVoteCount; + } + + private final L2pLogger logger = L2pLogger.getInstance(NoracleQuestionUtilityService.class.getName()); +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleRecommenderService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleRecommenderService.java new file mode 100644 index 0000000..a9ceeea --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleRecommenderService.java @@ -0,0 +1,535 @@ +package i5.las2peer.services.noracleService; + +import edu.smu.tspell.wordnet.Synset; +import edu.smu.tspell.wordnet.WordNetDatabase; +import i5.las2peer.api.Context; +import i5.las2peer.api.Service; +import i5.las2peer.api.execution.*; +import i5.las2peer.api.p2p.ServiceNameVersion; +import i5.las2peer.logging.L2pLogger; +import i5.las2peer.services.noracleService.api.INoracleRecommenderService; +import i5.las2peer.services.noracleService.model.*; +import info.debatty.java.stringsimilarity.Cosine; +import org.tartarus.snowball.ext.PorterStemmer; + +import java.io.*; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +public class NoracleRecommenderService extends Service implements INoracleRecommenderService { + + private RecommenderQuestionList getRecommendations(String agentId, VotedQuestionList votedQuestionList, int limit) throws ServiceInvocationException { + + // Normalize questions - At the moment not possible in NoracleNormalizationService because + // no complex objects can be passed with serialization + /*Serializable rmiResultNorm = Context.get().invoke( + new ServiceNameVersion(NoracleNormalizationService.class.getCanonicalName(), NoracleService.API_VERSION), + "normalizeQuestions", votedQuestionList);*/ + + VotedQuestionList normVotedQuestionList = normalizeQuestions(votedQuestionList); + + // Compute Utility of questions + /*rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleQuestionUtilityService.class.getCanonicalName(), NoracleService.API_VERSION), + "computeUtilityForQuestions", agentId, votedQuestionList);*/ + //HashMap recommendationUtility = computeUtilityForQuestions(agentId, votedQuestionList); + HashMap recommendationUtility = computeUtilityForQuestions(agentId, normVotedQuestionList); + + List topNormRecommendations = recommendationUtility + .entrySet() + .stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .limit(limit) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + // re-normalize + List topRecommendations = new VotedQuestionList(); + for (int i = 0; i < topNormRecommendations.size(); i++) { + VotedQuestion vq = topNormRecommendations.get(i); + votedQuestionList.stream().filter(t -> t.getQuestionId().equals(vq.getQuestionId())).findFirst().ifPresent(v -> topRecommendations.add(v)); + } + + RecommenderQuestionList recommendations = new RecommenderQuestionList(); + RecommenderQuestion rq; + for (VotedQuestion q : topRecommendations) { + + rq = new RecommenderQuestion(); + rq.setQuestion(q); + + // set author name + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleAgentService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAgentProfile", q.getAuthorId()); + NoracleAgentProfile ap = (NoracleAgentProfile) rmiResult; + if (ap != null || ap.getName() != null) { + rq.setAuthorName(ap.getName()); + } + + recommendations.add(rq); + } + + return recommendations; + } + + @Override + public RecommenderQuestionList getRecommendedQuestions(String agentId) throws ServiceInvocationException { + //logger.info("NoracleRecommenderService -> getRecommendedQuestions() with agentid " + agentId); + + // Retrieving questions + //logger.info("Get all (voted) questions for agent with agentId = " + agentId); + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleAgentService.class.getCanonicalName(), NoracleService.API_VERSION), + "getSpaceSubscriptions", agentId); + + SpaceSubscriptionList spaces; + if (rmiResult instanceof SpaceSubscriptionList) { + spaces = (SpaceSubscriptionList) rmiResult; + } else { + spaces = new SpaceSubscriptionList(); + logger.warning("RmiResult not an instance of SpaceSubscriptionList!"); + } + + VotedQuestionList votedQuestionList = new VotedQuestionList(); + for (SpaceSubscription s : spaces) { + rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleQuestionService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAllVotedQuestions", s.getSpaceId()); + if (rmiResult instanceof VotedQuestionList) { + votedQuestionList.addAll((VotedQuestionList) rmiResult); + } else { + logger.warning("RmiResult not an instance of VotedQuestionList!"); + } + } + + RecommenderQuestionList recommenderQuestionList = getRecommendations(agentId, votedQuestionList, 9); + return recommenderQuestionList; + } + + @Override + public RecommenderQuestionList getRecommendedQuestionsForSpace(String agentId, String spaceId) throws ServiceInvocationException { + //logger.info("NoracleRecommenderService -> getRecommendedQuestionsForSpace() with agentid " + agentId + " and spaceId " + spaceId + " called"); + + // Retrieving questions + //logger.info("Get all (voted) questions of space with spaceId " + spaceId); + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleQuestionService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAllVotedQuestions", spaceId); + + VotedQuestionList votedQuestionList = new VotedQuestionList(); + if (rmiResult instanceof VotedQuestionList) { + //System.out.println("rmiResult instanceof VotedQuestionList"); + votedQuestionList = (VotedQuestionList) rmiResult; + for(int i = 0; i < votedQuestionList.size(); i++) { + VotedQuestion vq = votedQuestionList.get(i); + if (vq.getVotes() != null) { + //System.out.println(vq.getVotes().size()); + } else { + //System.out.println("vq getVotes() is null"); + } + } + } else { + logger.warning("RmiResult not an instance of VotedQuestionList!"); + } + + //logger.info("Found " + votedQuestionList.size() + " voted questions!"); + + RecommenderQuestionList recommenderQuestionList = getRecommendations(agentId, votedQuestionList, 6); + return recommenderQuestionList; + } + + // ######################################################################### + // TEMP -> Utility service! + // weights + private final double cosineSimilarityWeight = 1; + private final double voteSimilarityWeight = 1; + private final double relativePositiveVoteCountWeight = 1; + private final double relativeNegativeVoteCountWeight = -1; + private final double positiveVoteCountWeight = 10000; + private final double negativeVoteCountWeight = -10000; + private final double timeFeatureWeight = 1; + + private final double sumWeights = cosineSimilarityWeight + + voteSimilarityWeight + + relativePositiveVoteCountWeight + + relativeNegativeVoteCountWeight + + positiveVoteCountWeight + + negativeVoteCountWeight + + timeFeatureWeight; + + private final Cosine cosine = new Cosine(); + + private HashMap computeUtilityForQuestions(String agentId, VotedQuestionList questions) { + logger.info("NoracleQuestionUtilityService -> computeUtilityForQuestions(...)"); + HashMap utilityMap = new HashMap<>(); + Date oldestDate = null; + try { + oldestDate = getOldestDate(questions); + } catch (Exception ex) { + ex.printStackTrace(); + } + double utility; + for (VotedQuestion q : questions) { + + //logger.info("compute utility for question: " + q.getText()); + utility = 0.0; + boolean questionAsked = q.getAuthorId().equals(agentId); + boolean alreadyVoted = alreadyVoted(q, agentId); + // check if user did not create the question or gave already a vote to it + if (!questionAsked && !alreadyVoted) { + double cosineSimilarity = cosineSimilarityWeight * computeMaxCosineSimilarity(agentId, q); + double voteSimilarity = voteSimilarityWeight * computeMaxVoteSimilarity(agentId, q); + double relativePositiveVoteCount = relativePositiveVoteCountWeight * computeRelativePositiveVoteCount(questions, q); + double relativeNegativeVoteCount = relativeNegativeVoteCountWeight * computeRelativeNegativeVoteCount(questions, q); + double positiveVoteCount = positiveVoteCountWeight * computeVoteCount(q, 1); + double negativeVoteCount = negativeVoteCountWeight * computeVoteCount(q, -1); + double timeFeature = 0.0; + try { + if (oldestDate != null) { + timeFeature = timeFeatureWeight * computeTimeFeature(q, oldestDate); + } + } catch (ParseException e) { + e.printStackTrace(); + } + + /* + System.out.println(q.getText()); + System.out.println("cosineSimilarity: " + cosineSimilarity); + System.out.println("voteSimilarity: " + voteSimilarity); + System.out.println("relativePositiveVoteCount: " + relativePositiveVoteCount); + System.out.println("relativeNegativeVoteCount: " + relativeNegativeVoteCount); + System.out.println("positiveVoteCount: " + positiveVoteCount); + System.out.println("negativeVoteCount: " + negativeVoteCount); + System.out.println("timeFeature: " + timeFeature); + */ + + utility = + cosineSimilarity + + voteSimilarity + + relativePositiveVoteCount + + relativeNegativeVoteCount + + positiveVoteCount + + negativeVoteCount + + timeFeature; + + utility /= sumWeights; + + //System.out.println("total utility: " + utility); + } + + // never recommend questions that are asked by the user itself + if (questionAsked) { + utility = -100.0; + } + //logger.info("Utility is " + utility); + utilityMap.put(q, utility); + } + return utilityMap; + } + + private Date getOldestDate(VotedQuestionList questions) { + if (questions.size() == 0) { + return new Date(); + } + String timestampLastModified = questions.get(0).getTimestampLastModified(); + Date oldestDate = getDate(timestampLastModified); + for(int i = 0; i < questions.size(); i++) { + timestampLastModified = questions.get(i).getTimestampLastModified(); + //System.out.println(timestampLastModified); + Date date = getDate(timestampLastModified); + //System.out.println(date.getTime()); + oldestDate = date.getTime() < oldestDate.getTime() ? date : oldestDate; + } + return oldestDate; + } + + private boolean alreadyVoted(VotedQuestion q, String agentId) { + if (q.getVotes() != null) { + return q.getVotes().stream().anyMatch(v -> v.getVoterAgentId().equals(agentId)); + } + return false; + } + + private double computeTimeFeature(VotedQuestion q, Date oldestDate) throws ParseException { + double secondsToToday = System.currentTimeMillis() / 1000.0; + double seconds1 = secondsToToday - (getDate(q.getTimestampLastModified()).getTime() / 1000.0); + double seconds2 = secondsToToday - (oldestDate.getTime() / 1000.0); + return seconds1 / seconds2; + + } + + public Date getDate (String timestampLastModified) { + int year = Integer.parseInt(timestampLastModified.substring(0, 4)); + int month = Integer.parseInt(timestampLastModified.substring(5, 7)) - 1; + int day = Integer.parseInt(timestampLastModified.substring(8, 10)); + int hour = Integer.parseInt(timestampLastModified.substring(11, 13)); + int minute = Integer.parseInt(timestampLastModified.substring(14, 16)); + int second = Integer.parseInt(timestampLastModified.substring(17, 19)); + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, month); + cal.set(Calendar.DAY_OF_MONTH, day); + cal.set(Calendar.HOUR_OF_DAY, hour); + cal.set(Calendar.MINUTE, minute); + cal.set(Calendar.SECOND, second); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + private double computeVoteCount(VotedQuestion q, int value) { + if (q.getVotes() == null) { + return 0.0; + } + double ret = q.getVotes().stream().filter(v -> v.getValue() == value).collect(Collectors.toList()).size(); + ret = ret / NoracleVoteService.MAX_VOTES_PER_OBJECT; + return ret; + } + + private double computeMaxCosineSimilarity(String agentId, VotedQuestion question) { + // logger.info("NoracleQuestionUtilityService -> computeMaxCosineSimilarity(...)"); + if (question == null) { + return 0; + } + double maxCosineSimilarity = 0.0; + String spaceId = question.getSpaceId(); + try { + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleQuestionService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAllVotedQuestions", spaceId, agentId); + + VotedQuestionList userQuestions = new VotedQuestionList(); + if (rmiResult instanceof VotedQuestionList) { + userQuestions = (VotedQuestionList) rmiResult; + } + + for (VotedQuestion userQuestion : userQuestions) { + double cosineSimilarity = cosine.similarity(userQuestion.getText(), question.getText()); + maxCosineSimilarity = Math.max(maxCosineSimilarity, cosineSimilarity); + } + } catch (Exception ex) { + logger.warning("Exception inside computeMaxCosineSimilarity:"); + ex.printStackTrace(); + } + // logger.info("maxCosineSimilarity: " + maxCosineSimilarity); + return maxCosineSimilarity; + } + + private double computeMaxVoteSimilarity(String agentId, VotedQuestion question) { + // logger.info("NoracleQuestionUtilityService -> computeMaxVoteSimilarity(...)"); + double maxVoteSimilarity = 0.0; + String spaceId = question.getSpaceId(); + try { + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleQuestionService.class.getCanonicalName(), NoracleService.API_VERSION), + "getAllVotedQuestions", spaceId, agentId); + + VotedQuestionList userQuestions = (VotedQuestionList) rmiResult; + for (VotedQuestion userQuestion : userQuestions) { + double voteSimilarity = computeVoteSimilarity(userQuestion, question); + maxVoteSimilarity = Math.max(maxVoteSimilarity, voteSimilarity); + } + + } catch (Exception ex) { + ex.printStackTrace(); + } + // logger.info("maxVoteSimilarity: " + maxVoteSimilarity); + return maxVoteSimilarity; + } + + private double computeVoteSimilarity(VotedQuestion q1, VotedQuestion q2) { + VoteList v1 = q1.getVotes(); + VoteList v2 = q2.getVotes(); + if (v1 == null || v2 == null) { + return 0.0; + } + + Map noOfUsers = new HashMap<>(); + + for (Vote v : v1) { + noOfUsers.put(v.getVoterAgentId(), 1); + } + + for (Vote v : v2) { + if (noOfUsers.containsKey(v.getVoterAgentId())) { + noOfUsers.put(v.getVoterAgentId(), 2); + } else { + noOfUsers.put(v.getVoterAgentId(), 1); + } + } + + int noOfDistinctUsers = 0; + for (var entry : noOfUsers.entrySet()) { + if (entry.getValue() == 2) { + noOfDistinctUsers++; + } + } + + if (noOfUsers.size() == 0) { + return 0.0; + } else { + //System.out.println("noOfDistinctUsers: " + noOfDistinctUsers); + //System.out.println("noOfUsers: " + noOfUsers.size()); + return (double) noOfDistinctUsers / (double) noOfUsers.size(); + } + } + + private double computeRelativePositiveVoteCount(VotedQuestionList questions, VotedQuestion q) { + return computeRelativeVoteCount(questions, q, 1); + } + + private double computeRelativeNegativeVoteCount(VotedQuestionList questions, VotedQuestion q) { + return computeRelativeVoteCount(questions, q, -1); + } + + private double computeRelativeVoteCount(VotedQuestionList questions, VotedQuestion q, int value) { + if (q == null || q.getVotes() == null) { + return 0.0; + } + + int voteCount = q.getVotes().stream().filter(v -> v.getValue() == value).collect(Collectors.toList()).size(); + int voteCountAll = 0; + for (VotedQuestion question : questions) { + if (q.getSpaceId().equals(question.getSpaceId())) { + voteCountAll += question.getVotes().size(); + } + } + double relativeVoteCount = 0.0; + if (voteCountAll > 0) { + relativeVoteCount = (1.0 / voteCountAll) * voteCount; + } + return relativeVoteCount; + } + + // ######################################################################### + // TEMP -> Normalization service! + + public VotedQuestion normalizeQuestion(VotedQuestion question) { + //logger.info("NoracleNormalizationService -> normalizeQuestion(...) called"); + VotedQuestion normQuestion = new VotedQuestion(question); + String text = normQuestion.getText(); + + // 0 strip + text = text.strip(); + + // 1. to lower case + text = text.toLowerCase(); + + // 2. Expanding contractions + text = expandContractions(text); + + // 3. Removing dashes + text = text.replaceAll("[\\s\\-()]", " "); + + // 4. Remove stop words + text = removeStopWords(text); + + // 5. Remove question marks + text = text.replace("?", ""); + + // 6. Stemming + text = stemming(text); + + // 7. Remove all non-letter characters + //text = text.replaceAll("[^a-zA-Z ]", ""); + + // 7. Replacing words with synonyms + // TODO: Do actual replacing with words or index which leads to a pool of synonyms + //text = replaceWithSynonyms(text); + + normQuestion.setText(text); + + return normQuestion; + } + + private String replaceWithSynonyms(String text) { + // TODO: Do actual replacing with words or index which leads to a pool of synonyms + File f = new File("WordNet/2.1/dict"); + System.setProperty("wordnet.database.dir", f.toString()); + WordNetDatabase database = WordNetDatabase.getFileInstance(); + Synset[] synsets; + try { + synsets = database.getSynsets(text); + } catch (Exception ex) { + throw ex; + } + if (synsets.length > 0) { + ArrayList al = new ArrayList(); + // add elements to al, including duplicates + HashSet hs = new HashSet(); + for (int i = 0; i < synsets.length; i++) { + String[] wordForms = synsets[i].getWordForms(); + for (int j = 0; j < wordForms.length; j++) + { + al.add(wordForms[j]); + } + + + //removing duplicates + hs.addAll(al); + al.clear(); + al.addAll(hs); + } + //showing all synsets + for (int k = 0; k < al.size(); k++) { + //System.out.println(al.get(k)); + } + } else { + //System.err.println("No synsets exist that contain the word form '" + wordForm + "'"); + } + return text; + } + + + private String removeStopWords(String inputString) { + inputString = inputString.replace(" a ", " "); + inputString = inputString.replace(" the ", " "); + inputString = inputString.replace(" is ", " "); + inputString = inputString.replace(" are ", " "); + return inputString; + } + + public VotedQuestionList normalizeQuestions(VotedQuestionList questionList) { + logger.info("NoracleNormalizationService -> normalizeQuestions(...) called"); + //questionList.stream().forEach(q -> logger.info(q.getText())); + VotedQuestionList normQuestionList = new VotedQuestionList(); + for (VotedQuestion q : questionList) { + VotedQuestion normQ = normalizeQuestion(q); + normQuestionList.add(normQ); + } + return normQuestionList; + } + + private String expandContractions(String inputString) { + inputString = inputString.replaceAll("n't", " not"); + inputString = inputString.replaceAll("'re", " are"); + inputString = inputString.replaceAll("'m", " am"); + inputString = inputString.replaceAll("'ll", " will"); + inputString = inputString.replaceAll("'ve", " have"); + inputString = inputString.replaceAll("'s", " is"); + return inputString; + } + + private String stemming(String text) { + String[] words = text.split(" "); + String ret = ""; + for (int i = 0; i < words.length; i++) { + if (words[i].isEmpty()) { + continue; + } + if (i > 0) { + ret += " "; + } + porterStemmer.setCurrent(words[i]); + porterStemmer.stem(); + ret += porterStemmer.getCurrent(); + } + return ret; + } + + private static final DateFormat formatter1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); + private static final PorterStemmer porterStemmer = new PorterStemmer(); + private final L2pLogger logger = L2pLogger.getInstance(NoracleRecommenderService.class.getName()); +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleService.java index 58ca094..682c7c5 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleService.java @@ -1,18 +1,18 @@ package i5.las2peer.services.noracleService; +import i5.las2peer.api.Context; import i5.las2peer.restMapper.RESTService; import i5.las2peer.restMapper.annotations.ServicePath; -import i5.las2peer.services.noracleService.resources.AgentsResource; -import i5.las2peer.services.noracleService.resources.QuestionRelationsResource; -import i5.las2peer.services.noracleService.resources.QuestionsResource; -import i5.las2peer.services.noracleService.resources.SpacesResource; +import i5.las2peer.services.noracleService.model.BotResponse; +import i5.las2peer.services.noracleService.model.NoracleAgent; +import i5.las2peer.services.noracleService.resources.*; import io.swagger.annotations.Api; import io.swagger.annotations.Info; import io.swagger.annotations.License; import io.swagger.annotations.SwaggerDefinition; -import javax.ws.rs.GET; -import javax.ws.rs.Path; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; @Api @SwaggerDefinition( @@ -27,7 +27,7 @@ public class NoracleService extends RESTService { public static final String RESOURCE_NAME = "distributed-noracle"; - public static final String API_VERSION = "1.0.0"; + public static final String API_VERSION = "1.0.1"; @Override protected void initResources() { @@ -48,8 +48,31 @@ public AgentsResource agents() { return new AgentsResource(); } + @Path("/" + RecommenderResource.RESOURCE_NAME) + public RecommenderResource recommendations() { + return new RecommenderResource(); + } + @GET @Path("/version") - public String version() { return this.API_VERSION; } + public String version() { + + return this.API_VERSION; + } + + @GET + @Path("/versionForBot") + @Produces(MediaType.APPLICATION_JSON) + public BotResponse versionForBot() { + return new BotResponse("The version of the Distributed Noracle application is " + this.API_VERSION, true); + } + + @GET + @Path("/mainAgent") + @Produces(MediaType.APPLICATION_JSON) + public NoracleAgent getMainAgentId() { + String agentid = Context.get().getMainAgent().getIdentifier(); + return new NoracleAgent(agentid); + } } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleSpaceService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleSpaceService.java index 3ecc21d..cd32de4 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleSpaceService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleSpaceService.java @@ -3,23 +3,19 @@ import i5.las2peer.api.Context; import i5.las2peer.api.Service; import i5.las2peer.api.execution.*; -import i5.las2peer.api.persistency.Envelope; -import i5.las2peer.api.persistency.EnvelopeAccessDeniedException; -import i5.las2peer.api.persistency.EnvelopeNotFoundException; -import i5.las2peer.api.persistency.EnvelopeOperationFailedException; +import i5.las2peer.api.persistency.*; import i5.las2peer.api.security.*; +import i5.las2peer.logging.L2pLogger; import i5.las2peer.security.GroupAgentImpl; import i5.las2peer.security.UserAgentImpl; import i5.las2peer.serialization.SerializationException; import i5.las2peer.services.noracleService.api.INoracleSpaceService; -import i5.las2peer.services.noracleService.model.NoracleAgentProfile; -import i5.las2peer.services.noracleService.model.Space; -import i5.las2peer.services.noracleService.model.SpaceInviteAgent; -import i5.las2peer.services.noracleService.model.SpaceSubscribersList; +import i5.las2peer.services.noracleService.model.*; import i5.las2peer.tools.CryptoException; +import java.io.Serializable; import java.security.SecureRandom; -import java.util.Random; +import java.util.*; /** * Noracle Space Service @@ -38,7 +34,7 @@ public NoracleSpaceService() { } @Override - public Space createSpace(String name) throws ServiceInvocationException { + public Space createSpace(String name, boolean isPrivate) throws ServiceInvocationException { Agent mainAgent = Context.get().getMainAgent(); if (mainAgent instanceof AnonymousAgent) { throw new ServiceNotAuthorizedException("You have to be logged in to create a space"); @@ -89,16 +85,105 @@ public Space createSpace(String name) throws ServiceInvocationException { } env.addReader(spaceMemberGroupAgent); Space space = new Space(spaceId, spaceSecret, name, mainAgent.getIdentifier(), - spaceMemberGroupAgent.getIdentifier()); + spaceMemberGroupAgent.getIdentifier(), isPrivate); env.setContent(space); try { Context.get().storeEnvelope(env, mainAgent); } catch (EnvelopeAccessDeniedException | EnvelopeOperationFailedException e) { throw new InternalServiceException("Could not store space envelope", e); } + + // Handle public spaces + if(!isPrivate) { + Envelope envelope; + try { + envelope = Context.get().requestEnvelope(getPublicSpacesIdentifier()); + SpaceList list = (SpaceList) envelope.getContent(); + list.add(space); + envelope.setContent(list); + Context.get().storeEnvelope(envelope, mainAgent); + } catch (EnvelopeOperationFailedException e) { + e.printStackTrace(); + } catch (EnvelopeNotFoundException e) { + try { + envelope = Context.get().createEnvelope(getPublicSpacesIdentifier()); + envelope.setPublic(); + SpaceList list = new SpaceList(); + list.add(space); + envelope.setContent(list); + Context.get().storeEnvelope(envelope, mainAgent); + } catch (EnvelopeOperationFailedException ex) { + ex.printStackTrace(); + } catch (EnvelopeAccessDeniedException ex) { + ex.printStackTrace(); + } + } catch (EnvelopeAccessDeniedException e) { + e.printStackTrace(); + } + } + return space; } + @Override + public void deleteSpace(String spaceId) throws ServiceInvocationException { + // Delete space and reclaim corresponding envelopes + try { + Context.get().reclaimEnvelope(getInviteMappingIdentifier(spaceId)); + } catch (EnvelopeAccessDeniedException e) { + e.printStackTrace(); + } catch (EnvelopeNotFoundException e) { + e.printStackTrace(); + } catch (EnvelopeOperationFailedException e) { + e.printStackTrace(); + } + + try { + Context.get().reclaimEnvelope(getMemberMappingIdentifier(spaceId)); + } catch (EnvelopeAccessDeniedException e) { + e.printStackTrace(); + } catch (EnvelopeNotFoundException e) { + e.printStackTrace(); + } catch (EnvelopeOperationFailedException e) { + e.printStackTrace(); + } + + //Space space = null; + try { + //space = (Space) Context.get().requestEnvelope(getSpaceEnvelopeIdentifier(spaceId)); + Context.get().reclaimEnvelope(getSpaceEnvelopeIdentifier(spaceId)); + } catch (EnvelopeAccessDeniedException e) { + e.printStackTrace(); + } catch (EnvelopeNotFoundException e) { + e.printStackTrace(); + } catch (EnvelopeOperationFailedException e) { + e.printStackTrace(); + } + + // Handle public spaces + Envelope envelope; + try { + envelope = Context.get().requestEnvelope(getPublicSpacesIdentifier()); + SpaceList list = (SpaceList) envelope.getContent(); + if (list != null) { + list.removeIf(s -> s.getSpaceId().equals(spaceId)); + } + envelope.setContent(list); + Context.get().storeEnvelope(envelope, (toStore, inNetwork) -> { + logger.info("onCollision was called...."); + return toStore; + }); + } catch (EnvelopeOperationFailedException e) { + e.printStackTrace(); + } catch (EnvelopeNotFoundException e) { + e.printStackTrace(); + } catch (EnvelopeAccessDeniedException e) { + e.printStackTrace(); + } + + //return space; + } + @Override public Space getSpace(String spaceId) throws ServiceInvocationException { if (spaceId == null || spaceId.isEmpty()) { @@ -143,7 +228,24 @@ public SpaceSubscribersList getSubscribers(String spaceId) throws ServiceInvocat } } + public SpaceList getPublicSpaces() { + Envelope envelope = null; + SpaceList list = new SpaceList(); + try { + envelope = Context.get().requestEnvelope(getPublicSpacesIdentifier()); + list = (SpaceList) envelope.getContent(); + } catch (EnvelopeAccessDeniedException e) { + e.printStackTrace(); + } catch (EnvelopeNotFoundException e) { + // No public spaces + } catch (EnvelopeOperationFailedException e) { + e.printStackTrace(); + } + return list; + } + public void joinSpace(String spaceId, String spaceSecret) throws ServiceInvocationException { + // logger.info("NoracleSpaceService -> joinSpace() with spaceId " + spaceId + " and spaceSecret " + spaceSecret + " called"); if (spaceId == null || spaceId.isEmpty()) { throw new InvocationBadArgumentException("No space id given"); } else if (spaceSecret == null || spaceSecret.isEmpty()) { @@ -203,8 +305,14 @@ private String getMemberMappingIdentifier(String spaceId) { return "group-" + spaceId; } - private String getSpaceEnvelopeIdentifier(String questionId) { - return "space-" + questionId; + private String getSpaceEnvelopeIdentifier(String spaceId) { + return "space-" + spaceId; } + private String getPublicSpacesIdentifier() { + return "spaces-public"; + } + + private final L2pLogger logger = L2pLogger.getInstance(NoracleSpaceService.class.getName()); + } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleVoteService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleVoteService.java index 8d195ce..ebe5b21 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleVoteService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/NoracleVoteService.java @@ -21,7 +21,7 @@ public class NoracleVoteService extends Service implements INoracleVoteService { - private static final int MAX_VOTES_PER_OBJECT = 1000000; + public static final int MAX_VOTES_PER_OBJECT = 100000; private final L2pLogger logger = L2pLogger.getInstance(SpacesResource.class.getName()); @@ -124,7 +124,7 @@ public Vote getAgentVote(String objectId, String agentId) throws ServiceInvocati } @Override - public VoteList getAllVotes(String objectId) throws ServiceInvocationException { + public VoteList getAllVotes(String objectId) { VoteList result = new VoteList(); for (int num = 1; num < MAX_VOTES_PER_OBJECT; num++) { try { @@ -140,7 +140,6 @@ public VoteList getAllVotes(String objectId) throws ServiceInvocationException { Vote normalizedVote = new Vote(normalizedVal, vote.getVoterAgentId()); result.add(normalizedVote); } catch (EnvelopeNotFoundException e) { - logger.warning( "EnvelopeNotFoundException inside NoracleVoteService.getAllVotes(...): " + e.getMessage()); break; } catch (Exception e) { logger.warning( "Exception inside NoracleVoteService.getAllVotes(...): " + e.getMessage()); diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleAgentService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleAgentService.java index 4dceb81..3e04d17 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleAgentService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleAgentService.java @@ -5,6 +5,8 @@ import i5.las2peer.services.noracleService.model.SpaceSubscription; import i5.las2peer.services.noracleService.model.SpaceSubscriptionList; +import java.util.List; + public interface INoracleAgentService { NoracleAgentProfile updateAgentProfile(String agentName) throws ServiceInvocationException; @@ -17,7 +19,9 @@ public interface INoracleAgentService { SpaceSubscriptionList getSpaceSubscriptions(String agentId) throws ServiceInvocationException; - SpaceSubscription updateSpaceSubscription(String agentId, String spaceId, String[] selectedQuestions) + SpaceSubscription updateSpaceSubscription(String agentId, String spaceId, List selectedQuestions) throws ServiceInvocationException; + Boolean checkIfAlreadySubscribedToSpace(String agentId, String spaceId) throws ServiceInvocationException; + } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleNormalizationService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleNormalizationService.java new file mode 100644 index 0000000..fe8f41a --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleNormalizationService.java @@ -0,0 +1,10 @@ +package i5.las2peer.services.noracleService.api; + +import i5.las2peer.services.noracleService.model.VotedQuestion; +import i5.las2peer.services.noracleService.model.VotedQuestionList; + +public interface INoracleNormalizationService { + VotedQuestion normalizeQuestion(VotedQuestion question); + + VotedQuestionList normalizeQuestions(VotedQuestionList questionList); +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionRelationService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionRelationService.java index 8c12b95..30c3c1f 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionRelationService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionRelationService.java @@ -1,9 +1,12 @@ package i5.las2peer.services.noracleService.api; import i5.las2peer.api.execution.ServiceInvocationException; +import i5.las2peer.services.noracleService.model.Question; import i5.las2peer.services.noracleService.model.QuestionRelation; import i5.las2peer.services.noracleService.model.QuestionRelationList; +import java.util.List; + public interface INoracleQuestionRelationService { QuestionRelation createQuestionRelation(String spaceId, String name, String questionId1, String questionId2, @@ -17,4 +20,5 @@ QuestionRelationList getQuestionRelations(String spaceId, String order, Integer QuestionRelation changeQuestionRelation(String relationId, String name, String questionId1, String questionId2, Boolean directed) throws ServiceInvocationException; + List getQuestionRelationIds(String spaceId, String questionId); } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionService.java index 729ee2a..7f44bba 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionService.java @@ -3,6 +3,10 @@ import i5.las2peer.api.execution.ServiceInvocationException; import i5.las2peer.services.noracleService.model.Question; import i5.las2peer.services.noracleService.model.QuestionList; +import i5.las2peer.services.noracleService.model.VotedQuestion; +import i5.las2peer.services.noracleService.model.VotedQuestionList; + +import java.util.ArrayList; public interface INoracleQuestionService { @@ -13,6 +17,9 @@ public interface INoracleQuestionService { QuestionList getQuestions(String spaceId, String order, Integer limit, Integer startAt) throws ServiceInvocationException; + ArrayList getAllVotedQuestions(String spaceId) throws ServiceInvocationException; + ArrayList getAllVotedQuestions(String spaceId, String agentId) throws ServiceInvocationException; + Question changeQuestionText(String questionId, String text) throws ServiceInvocationException; Question changeQuestionDepth(String questionId, int depth) throws ServiceInvocationException; diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionUtilityService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionUtilityService.java new file mode 100644 index 0000000..2742b8f --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleQuestionUtilityService.java @@ -0,0 +1,13 @@ +package i5.las2peer.services.noracleService.api; + +import i5.las2peer.services.noracleService.model.VotedQuestionList; + +import java.util.HashMap; +import java.util.Map; + +public interface INoracleQuestionUtilityService { + // Key: QuestionId, Value: Utility + HashMap computeUtilityForQuestions(String agentId, VotedQuestionList questions); + + // Map.Entry computeUtilityForQuestion(String agentId, Question question); +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleRecommenderService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleRecommenderService.java new file mode 100644 index 0000000..6cc19b7 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleRecommenderService.java @@ -0,0 +1,13 @@ +package i5.las2peer.services.noracleService.api; + +import i5.las2peer.api.execution.ServiceInvocationException; +import i5.las2peer.services.noracleService.model.RecommenderQuestion; +import i5.las2peer.services.noracleService.model.RecommenderQuestionList; + +import java.util.List; + +public interface INoracleRecommenderService { + RecommenderQuestionList getRecommendedQuestionsForSpace(String agentId, String spaceId) throws ServiceInvocationException; + + RecommenderQuestionList getRecommendedQuestions(String agentId) throws ServiceInvocationException; +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleSpaceService.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleSpaceService.java index 7bb9707..ac9036f 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleSpaceService.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/api/INoracleSpaceService.java @@ -2,14 +2,23 @@ import i5.las2peer.api.execution.ServiceInvocationException; import i5.las2peer.services.noracleService.model.Space; +import i5.las2peer.services.noracleService.model.SpaceList; +import i5.las2peer.services.noracleService.model.SpacePublic; import i5.las2peer.services.noracleService.model.SpaceSubscribersList; +import java.util.ArrayList; +import java.util.List; + public interface INoracleSpaceService { - Space createSpace(String name) throws ServiceInvocationException; + Space createSpace(String name, boolean isPrivate) throws ServiceInvocationException; + + void deleteSpace(String spaceId) throws ServiceInvocationException; Space getSpace(String spaceId) throws ServiceInvocationException; SpaceSubscribersList getSubscribers(String spaceId) throws ServiceInvocationException; + SpaceList getPublicSpaces() throws ServiceInvocationException; + } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/BotRequest.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/BotRequest.java new file mode 100644 index 0000000..e06f291 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/BotRequest.java @@ -0,0 +1,108 @@ +package i5.las2peer.services.noracleService.model; + +import java.io.Serial; +import java.io.Serializable; + +public class BotRequest implements Serializable { + @Serial + private static final long serialVersionUID = 6240095834112330251L; + + // The message, the user send to the bot + private String msg; + // The agentId of the bot? + private String botName; + // Id of the channel + private String channel; + // Intent derived by the bot + private String intent; + private Object entities; + private String email; + private String user; + private String time; + + public BotRequest() { + this.msg = ""; + this.botName = ""; + this.channel = ""; + this.intent = ""; + this.entities = ""; + this.email = ""; + this.user = ""; + this.time = ""; + } + + public BotRequest(String msg, String botName, String channel, String intent, String entities, String email, String user, String time) { + this.msg = msg; + this.botName = botName; + this.channel = channel; + this.intent = intent; + this.entities = entities; + this.email = email; + this.user = user; + this.time = time; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getBotName() { + return botName; + } + + public void setBotName(String botName) { + this.botName = botName; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getIntent() { + return intent; + } + + public void setIntent(String intent) { + this.intent = intent; + } + + public Object getEntities() { + return entities; + } + + public void setEntities(String entities) { + this.entities = entities; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/BotResponse.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/BotResponse.java new file mode 100644 index 0000000..3616beb --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/BotResponse.java @@ -0,0 +1,41 @@ +package i5.las2peer.services.noracleService.model; + +import java.io.Serial; +import java.io.Serializable; + +public class BotResponse implements Serializable { + @Serial + private static final long serialVersionUID = -2348162648183479462L; + + // Text that is send via the chat to the user + private String text; + + // Determines if the communication between the bot and the service should be hold + private boolean closeContext; + + public BotResponse() { + this.text = "default text"; + this.closeContext = true; + } + + public BotResponse(String text, boolean closeContext) { + this.text = text; + this.closeContext = closeContext; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public boolean isCloseContext() { + return closeContext; + } + + public void setCloseContext(boolean closeContext) { + this.closeContext = closeContext; + } +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/NoracleAgent.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/NoracleAgent.java new file mode 100644 index 0000000..ba3bb5e --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/NoracleAgent.java @@ -0,0 +1,19 @@ +package i5.las2peer.services.noracleService.model; + +public class NoracleAgent { + private String agentid; + + public String getAgentid() { + return agentid; + } + + public void getAgentid(String agentid) { + this.agentid = agentid; + } + + NoracleAgent() {} + + public NoracleAgent(String agentId) { + this.agentid = agentId; + } +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/NoracleAgentProfile.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/NoracleAgentProfile.java index 634a42e..4d89bbe 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/NoracleAgentProfile.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/NoracleAgentProfile.java @@ -1,10 +1,13 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.io.Serializable; public class NoracleAgentProfile implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = -843933540208902830L; + private String name; public String getName() { diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Question.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Question.java index 6710488..b7794df 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Question.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Question.java @@ -1,10 +1,13 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.io.Serializable; +import java.time.Instant; public class Question implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 220865019536362474L; private String questionId; private String text; @@ -15,6 +18,8 @@ public class Question implements Serializable { private int depth; public Question() { // used in tests + this.timestampCreated = Instant.now().toString(); + this.timestampLastModified = Instant.now().toString(); } public Question(String questionId, String text, String spaceId, String authorId, String timestampCreated) { @@ -27,6 +32,16 @@ public Question(String questionId, String text, String spaceId, String authorId, this.depth = 0; } + public Question(Question question) { + this.questionId = question.questionId; + this.text = question.text; + this.spaceId = question.spaceId; + this.authorId = question.authorId; + this.timestampCreated = question.timestampCreated; + this.timestampLastModified = question.timestampLastModified; + this.depth = question.depth; + } + public String getQuestionId() { return questionId; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionList.java index d6c54b2..7f1da3d 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionList.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionList.java @@ -1,9 +1,10 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.util.ArrayList; public class QuestionList extends ArrayList { - private static final long serialVersionUID = 1L; - + @Serial + private static final long serialVersionUID = -8360998753379224176L; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionNeighbourIds.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionNeighbourIds.java new file mode 100644 index 0000000..a7cfc45 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionNeighbourIds.java @@ -0,0 +1,11 @@ +package i5.las2peer.services.noracleService.model; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; + +public class QuestionNeighbourIds extends ArrayList implements Serializable { + + @Serial + private static final long serialVersionUID = -7329067583561313197L; +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelation.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelation.java index 63c1308..d1fb01e 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelation.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelation.java @@ -1,10 +1,12 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.io.Serializable; public class QuestionRelation implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 20370840289622276L; private String relationId; private String spaceId; diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelationList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelationList.java index 64aa970..d50bbd1 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelationList.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/QuestionRelationList.java @@ -1,9 +1,10 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.util.ArrayList; public class QuestionRelationList extends ArrayList { - private static final long serialVersionUID = 1L; - + @Serial + private static final long serialVersionUID = 5133039776218945909L; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/RecommenderQuestion.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/RecommenderQuestion.java new file mode 100644 index 0000000..379de4b --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/RecommenderQuestion.java @@ -0,0 +1,49 @@ +package i5.las2peer.services.noracleService.model; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +public class RecommenderQuestion implements Serializable { + + @Serial + private static final long serialVersionUID = 3652217404875516479L; + + public RecommenderQuestion() { + this.authorName = "unknown user"; + } + +/* public RecommenderQuestion(QuestionNeighbourIds questionNeighbourIds, VotedQuestion question, String authorName) { + this.questionNeighbourIds = questionNeighbourIds; + this.question = question; + this.authorName = authorName; + }*/ + + //private QuestionNeighbourIds questionNeighbourIds; + private VotedQuestion question; + private String authorName; + +/* public List getQuestionNeighbourIds() { + return questionNeighbourIds; + }*/ + +/* public void setQuestionNeighbourIds(QuestionNeighbourIds questionNeighbourIds) { + this.questionNeighbourIds = questionNeighbourIds; + }*/ + + public Question getQuestion() { + return question; + } + + public void setQuestion(VotedQuestion question) { + this.question = question; + } + + public String getAuthorName() { + return authorName; + } + + public void setAuthorName(String authorName) { + this.authorName = authorName; + } +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/RecommenderQuestionList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/RecommenderQuestionList.java new file mode 100644 index 0000000..d16fa6d --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/RecommenderQuestionList.java @@ -0,0 +1,9 @@ +package i5.las2peer.services.noracleService.model; + +import java.io.Serial; +import java.util.ArrayList; + +public class RecommenderQuestionList extends ArrayList { + @Serial + private static final long serialVersionUID = -4103589562058452140L; +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Space.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Space.java index 4438af9..ff9233c 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Space.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Space.java @@ -1,26 +1,30 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.io.Serializable; public class Space implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 8800170853451989942L; private String spaceId; private String spaceSecret; private String name; private String spaceOwnerId; private String spaceReaderGroupId; + private boolean isPrivate; public Space() { // used in tests } - public Space(String spaceId, String spaceSecret, String name, String spaceOwnerId, String spaceReaderGroupId) { + public Space(String spaceId, String spaceSecret, String name, String spaceOwnerId, String spaceReaderGroupId, boolean isPrivate) { this.setSpaceId(spaceId); this.setSpaceSecret(spaceSecret); this.setName(name); this.setSpaceOwnerId(spaceOwnerId); this.setSpaceReaderGroupId(spaceReaderGroupId); + this.setPrivate(isPrivate); } public String getSpaceId() { @@ -63,4 +67,11 @@ public void setSpaceReaderGroupId(String spaceReaderGroupId) { this.spaceReaderGroupId = spaceReaderGroupId; } + public boolean isPrivate() { + return isPrivate; + } + + public void setPrivate(boolean aPrivate) { + isPrivate = aPrivate; + } } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceList.java new file mode 100644 index 0000000..9dd7784 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceList.java @@ -0,0 +1,7 @@ +package i5.las2peer.services.noracleService.model; + +import java.io.Serializable; +import java.util.ArrayList; + +public class SpaceList extends ArrayList implements Serializable { +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpacePublic.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpacePublic.java new file mode 100644 index 0000000..ecfbf90 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpacePublic.java @@ -0,0 +1,31 @@ +package i5.las2peer.services.noracleService.model; + +import java.io.Serializable; + +public class SpacePublic implements Serializable { + private Space space; + private int numberOfQuestions; + + public SpacePublic() {} + + public SpacePublic(Space space, int numberOfQuestions) { + this.space = space; + this.numberOfQuestions = numberOfQuestions; + } + + public Space getSpace() { + return space; + } + + public void setSpace(Space space) { + this.space = space; + } + + public int getNumberOfQuestions() { + return numberOfQuestions; + } + + public void setNumberOfQuestions(int numberOfQuestions) { + this.numberOfQuestions = numberOfQuestions; + } +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscribersList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscribersList.java index 78cbf27..e635cc1 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscribersList.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscribersList.java @@ -1,9 +1,10 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.util.ArrayList; public class SpaceSubscribersList extends ArrayList { - private static final long serialVersionUID = 1L; - + @Serial + private static final long serialVersionUID = 4872193456745354020L; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscription.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscription.java index fb61b4a..5d2ad65 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscription.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscription.java @@ -1,20 +1,24 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; public class SpaceSubscription implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = -3983233729934822604L; private String spaceId; - private String[] selectedQuestionIds; + //private List selectedQuestionIds; - public SpaceSubscription() { // used in tests + public SpaceSubscription() { // used in test } public SpaceSubscription(String spaceId, String name) { this.setSpaceId(spaceId); - this.setSelectedQuestionIds(new String[0]); + //this.selectedQuestionIds = new ArrayList<>(); } public String getSpaceId() { @@ -25,12 +29,12 @@ public void setSpaceId(String spaceId) { this.spaceId = spaceId; } - public String[] getSelectedQuestionIds() { +/* public List getSelectedQuestionIds() { return selectedQuestionIds; } - public void setSelectedQuestionIds(String[] selectedQuestionIds) { + public void setSelectedQuestionIds(ListselectedQuestionIds) { this.selectedQuestionIds = selectedQuestionIds; - } + }*/ } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscriptionList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscriptionList.java index bd5296f..7f87de4 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscriptionList.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/SpaceSubscriptionList.java @@ -1,9 +1,10 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; +import java.io.Serializable; import java.util.ArrayList; -public class SpaceSubscriptionList extends ArrayList { - - private static final long serialVersionUID = 1L; - +public class SpaceSubscriptionList extends ArrayList implements Serializable { + @Serial + private static final long serialVersionUID = -6597296485670834116L; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Vote.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Vote.java index 8416028..3347b85 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Vote.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/Vote.java @@ -1,10 +1,12 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.io.Serializable; public class Vote implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 7487058393243794605L; private int value; private String voterAgentId; diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteEntry.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteEntry.java index 8b362e5..604f248 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteEntry.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteEntry.java @@ -1,10 +1,12 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.io.Serializable; public class VoteEntry implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = -602296952601769113L; private String objectId; private int pubIndex; diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteList.java index 5128424..c446692 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteList.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VoteList.java @@ -1,9 +1,10 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.util.ArrayList; public class VoteList extends ArrayList { - private static final long serialVersionUID = 1L; - + @Serial + private static final long serialVersionUID = -1891206418191408041L; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestion.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestion.java index 0abb6ac..f81f4cc 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestion.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestion.java @@ -1,8 +1,13 @@ package i5.las2peer.services.noracleService.model; -public class VotedQuestion extends Question { +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; - private static final long serialVersionUID = 1L; +public class VotedQuestion extends Question implements Serializable { + + @Serial + private static final long serialVersionUID = -7969518021993650216L; private VoteList votes; @@ -18,6 +23,9 @@ public VotedQuestion(Question q) { this.setTimestampCreated(q.getTimestampCreated()); this.setTimestampLastModified(q.getTimestampLastModified()); this.setDepth(q.getDepth()); + if (q instanceof VotedQuestion) { + this.setVotes(((VotedQuestion) q).getVotes()); + } } public VoteList getVotes() { diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionList.java index 06e3fe0..e797d2e 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionList.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionList.java @@ -1,9 +1,9 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.util.ArrayList; public class VotedQuestionList extends ArrayList { - - private static final long serialVersionUID = 1L; - + @Serial + private static final long serialVersionUID = -3212649458627992281L; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelation.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelation.java index 5deac3f..90574fe 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelation.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelation.java @@ -1,8 +1,11 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; + public class VotedQuestionRelation extends QuestionRelation { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 937101316665902373L; private VoteList votes; diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelationList.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelationList.java index 5b92b0e..240b481 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelationList.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/model/VotedQuestionRelationList.java @@ -1,9 +1,10 @@ package i5.las2peer.services.noracleService.model; +import java.io.Serial; import java.util.ArrayList; public class VotedQuestionRelationList extends ArrayList { - private static final long serialVersionUID = 1L; - + @Serial + private static final long serialVersionUID = -1797758854152288318L; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/CreateSpacePojo.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/CreateSpacePojo.java index 31ec20d..a0f5761 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/CreateSpacePojo.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/CreateSpacePojo.java @@ -3,6 +3,15 @@ public class CreateSpacePojo { private String name; + private boolean isPrivate; + + public boolean isPrivate() { + return isPrivate; + } + + public void setPrivate(boolean isPrivate) { + this.isPrivate = isPrivate; + } public String getName() { return name; diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/RecommendPojo.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/RecommendPojo.java new file mode 100644 index 0000000..58f963c --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/RecommendPojo.java @@ -0,0 +1,22 @@ +package i5.las2peer.services.noracleService.pojo; + +public class RecommendPojo { + private String agentId; + private String spaceId; + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public String getSpaceId() { + return spaceId; + } + + public void setSpaceId(String spaceId) { + this.spaceId = spaceId; + } +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/UpdateSelectedQuestionsPojo.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/UpdateSelectedQuestionsPojo.java index 9b5db02..8e0b3ce 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/UpdateSelectedQuestionsPojo.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/pojo/UpdateSelectedQuestionsPojo.java @@ -1,14 +1,16 @@ package i5.las2peer.services.noracleService.pojo; +import java.util.List; + public class UpdateSelectedQuestionsPojo { - private String[] selectedQuestions; + private List selectedQuestions; - public String[] getSelectedQuestions() { + public List getSelectedQuestions() { return selectedQuestions; } - public void setSelectedQuestions(String[] selectedQuestions) { + public void setSelectedQuestions(List selectedQuestions) { this.selectedQuestions = selectedQuestions; } diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/AgentsResource.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/AgentsResource.java index 7ad88db..832bebf 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/AgentsResource.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/AgentsResource.java @@ -5,6 +5,7 @@ import i5.las2peer.api.execution.ServiceInvocationException; import i5.las2peer.api.logging.MonitoringEvent; import i5.las2peer.api.p2p.ServiceNameVersion; +import i5.las2peer.logging.L2pLogger; import i5.las2peer.restMapper.ExceptionEntity; import i5.las2peer.services.noracleService.NoracleAgentService; import i5.las2peer.services.noracleService.NoracleService; @@ -28,6 +29,8 @@ import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; @Api( tags = { AgentsResource.RESOURCE_NAME }) @@ -38,21 +41,22 @@ public class AgentsResource implements INoracleAgentService { @Override @GET - @Produces(MediaType.APPLICATION_JSON) - @ApiResponses({ @ApiResponse( +/* @ApiResponses({ @ApiResponse( code = HttpURLConnection.HTTP_OK, message = "Subscriptions successfully fetched", response = SpaceSubscriptionList.class), @ApiResponse( code = HttpURLConnection.HTTP_INTERNAL_ERROR, message = "Internal Server Error", - response = ExceptionEntity.class) }) + response = ExceptionEntity.class) })*/ @Path("/" + SUBSCRIPTIONS_RESOURCE_NAME) - public SpaceSubscriptionList getSpaceSubscriptions(@PathParam("agentid") String agentId) - throws ServiceInvocationException { + @Produces(MediaType.APPLICATION_JSON) + public SpaceSubscriptionList getSpaceSubscriptions(@PathParam("agentid") String agentId) throws ServiceInvocationException { + logger.info("AgentsResource -> getSpaceSubscriptions(...) with agentid: " + agentId); Serializable rmiResult = Context.get().invoke( new ServiceNameVersion(NoracleAgentService.class.getCanonicalName(), NoracleService.API_VERSION), "getSpaceSubscriptions", agentId); + logger.info("AgentsResource -> RMI Result: " + ((SpaceSubscriptionList) rmiResult).size()); if (rmiResult instanceof SpaceSubscriptionList) { return (SpaceSubscriptionList) rmiResult; } else { @@ -138,6 +142,9 @@ public SpaceSubscription subscribeToSpace(String spaceId, String spaceSecret) th response = ExceptionEntity.class) }) public NoracleAgentProfile updateAgentProfile(@PathParam("agentid") String agentId, @ApiParam( required = true) ChangeProfilePojo createProfilePojo) throws ServiceInvocationException { + logger.info("AgentsResource -> updateAgentProfile"); + logger.info("mainAgentId: " + Context.get().getMainAgent().getIdentifier()); + logger.info("agentId: " + agentId); if (!Context.get().getMainAgent().getIdentifier().equals(agentId)) { throw new ForbiddenException("Only update your own profile"); } @@ -259,15 +266,17 @@ public SpaceSubscription updateSelectedQuestions(@PathParam("agentid") String ag @PathParam("spaceId") String spaceId, @ApiParam( required = true) UpdateSelectedQuestionsPojo updateSelectedQuestionsPojo) throws ServiceInvocationException { + logger.info("AgentsResource -> updateSelectedQuestions(...)"); return updateSpaceSubscription(agentId, spaceId, updateSelectedQuestionsPojo.getSelectedQuestions()); } @Override public SpaceSubscription updateSpaceSubscription(String agentId, String spaceId, @ApiParam( - required = true) String[] selectedQuestions) throws ServiceInvocationException { + required = true) List selectedQuestions) throws ServiceInvocationException { + logger.info("AgentsResource -> updateSpaceSubscription(...)"); Serializable rmiResult = Context.get().invoke( new ServiceNameVersion(NoracleAgentService.class.getCanonicalName(), NoracleService.API_VERSION), - "updateSpaceSubscription", agentId, spaceId, selectedQuestions); + "updateSpaceSubscription", agentId, spaceId, (Serializable) selectedQuestions); if (rmiResult instanceof SpaceSubscription) { return (SpaceSubscription) rmiResult; } else { @@ -276,4 +285,11 @@ public SpaceSubscription updateSpaceSubscription(String agentId, String spaceId, } } + @Override + public Boolean checkIfAlreadySubscribedToSpace(String agentId, String spaceId) throws ServiceInvocationException { + return null; + } + + private final L2pLogger logger = L2pLogger.getInstance(AgentsResource.class.getName()); + } \ No newline at end of file diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionRelationsResource.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionRelationsResource.java index d012cbb..3edd279 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionRelationsResource.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionRelationsResource.java @@ -32,6 +32,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.time.Instant; +import java.util.List; public class QuestionRelationsResource implements INoracleQuestionRelationService { @@ -366,6 +367,11 @@ public QuestionRelation changeQuestionRelation(String relationId, String name, S } } + @Override + public List getQuestionRelationIds(String spaceId, String questionId) { + return null; // not used + } + @Path("/{relationId}/" + QuestionVotesResource.RESOURCE_NAME) public RelationVotesResource votes() { return new RelationVotesResource(); diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionsResource.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionsResource.java index fe6304f..de39774 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionsResource.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/QuestionsResource.java @@ -316,7 +316,7 @@ public Response getQuestionsWeb(@PathParam("spaceId") String spaceId, @QueryPara QuestionList questionList = getQuestions(spaceId, order, limit, startAt); VotedQuestionList votedQuestionList = new VotedQuestionList(); - for (Question question:questionList) { + for (Question question : questionList) { VotedQuestion votedQuestion = new VotedQuestion(question); String objectId = QuestionVotesResource.buildObjectId(spaceId, question.getQuestionId()); Serializable rmiResult = Context.get().invoke( @@ -370,6 +370,16 @@ public QuestionList getQuestions(String spaceId, String order, Integer limit, In } } + @Override + public VotedQuestionList getAllVotedQuestions(String spaceId) throws ServiceInvocationException { + return null; + } + + @Override + public VotedQuestionList getAllVotedQuestions(String spaceId, String agentId) throws ServiceInvocationException { + return null; + } + @PUT @Path("/{questionId}") @Consumes(MediaType.APPLICATION_JSON) diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/RecommenderResource.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/RecommenderResource.java new file mode 100644 index 0000000..e7636b7 --- /dev/null +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/RecommenderResource.java @@ -0,0 +1,299 @@ +package i5.las2peer.services.noracleService.resources; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import i5.las2peer.api.Context; +import i5.las2peer.api.execution.*; +import i5.las2peer.api.p2p.ServiceNameVersion; +import i5.las2peer.api.persistency.*; +import i5.las2peer.api.security.AgentNotFoundException; +import i5.las2peer.api.security.AgentOperationFailedException; +import i5.las2peer.logging.L2pLogger; +import i5.las2peer.restMapper.ExceptionEntity; +import i5.las2peer.services.noracleService.NoracleAgentService; +import i5.las2peer.services.noracleService.NoracleRecommenderService; +import i5.las2peer.services.noracleService.NoracleService; +import i5.las2peer.services.noracleService.api.INoracleRecommenderService; +import i5.las2peer.services.noracleService.model.*; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.io.Serializable; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class RecommenderResource implements INoracleRecommenderService { + public static final String RESOURCE_NAME = "recommend"; + + @GET + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses({ @ApiResponse( + code = HttpURLConnection.HTTP_OK, + message = "Recommendations successfully created", + response = RecommenderQuestionList.class), + @ApiResponse( + code = HttpURLConnection.HTTP_INTERNAL_ERROR, + message = "Internal Server Error", + response = ExceptionEntity.class) }) + @Path("/{agentId}/{spaceId}") + public RecommenderQuestionList getRecommendedQuestionsForSpace(@PathParam("agentId") String agentId, + @PathParam("spaceId") String spaceId) throws ServiceInvocationException { + logger.info("RecommenderResource -> getRecommendedQuestions() with agentid " + agentId + " and spaceId " + spaceId + " called"); + //long start = System.currentTimeMillis(); + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleRecommenderService.class.getCanonicalName(), NoracleService.API_VERSION), + "getRecommendedQuestionsForSpace", agentId, spaceId); + if (rmiResult instanceof RecommenderQuestionList) { + //logger.info("Computed " + ((RecommenderQuestionList) rmiResult).size() + " recommended questions!"); + //long end = System.currentTimeMillis(); + //System.out.println("getRecommendedQuestionsForSpace(...) took in seconds: "+ ((end-start) / 1000.0)); + return (RecommenderQuestionList) rmiResult; + } else { + throw new InternalServiceException( + "Unexpected result (" + rmiResult.getClass().getCanonicalName() + ") of RMI call -> getRecommendedQuestionsForSpace(...)"); + } + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses({ @ApiResponse( + code = HttpURLConnection.HTTP_OK, + message = "Recommendations successfully created", + response = RecommenderQuestionList.class), + @ApiResponse( + code = HttpURLConnection.HTTP_INTERNAL_ERROR, + message = "Internal Server Error", + response = ExceptionEntity.class) }) + @Path("/{agentId}") + public RecommenderQuestionList getRecommendedQuestions(@PathParam("agentId") String agentId) throws ServiceInvocationException { + logger.info("RecommenderResource -> getRecommendedQuestions() with agentid " + agentId); + //long start = System.currentTimeMillis(); + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleRecommenderService.class.getCanonicalName(), NoracleService.API_VERSION), + "getRecommendedQuestions", agentId); + //logger.info("recommendations: check rmi Result"); + if (rmiResult instanceof RecommenderQuestionList) { + //logger.info("return recommendations!"); + //long end = System.currentTimeMillis(); + //System.out.println("getRecommendedQuestions(...) took in seconds: "+ ((end-start) / 1000.0)); + return (RecommenderQuestionList) rmiResult; + } else { + throw new InternalServiceException( + "Unexpected result (" + rmiResult.getClass().getCanonicalName() + ") of RMI call -> getRecommendedQuestions(...)"); + } + } + + // Everything related to the Noracle Bot + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.TEXT_HTML) + @ApiResponses({ @ApiResponse( + code = HttpURLConnection.HTTP_OK, + message = "Recommendations successfully created for bot", + response = BotResponse.class), + @ApiResponse( + code = HttpURLConnection.HTTP_INTERNAL_ERROR, + message = "Internal Server Error", + response = ExceptionEntity.class) }) + @Path("/bot") + public BotResponse getRecommendedQuestionsForBot(@ApiParam(required = true) String request) throws AgentOperationFailedException, AgentNotFoundException, ServiceNotAvailableException, ServiceInvocationFailedException, ServiceNotFoundException, ServiceAccessDeniedException, ServiceNotAuthorizedException, ServiceMethodNotFoundException, InternalServiceException { + Gson gson = new Gson(); + BotRequest botRequest; + botRequest = gson.fromJson(request, BotRequest.class); + + System.out.println(botRequest.getMsg()); + System.out.println(botRequest.getBotName()); + System.out.println(botRequest.getChannel()); + System.out.println(botRequest.getIntent()); + System.out.println(botRequest.getEntities()); + System.out.println(botRequest.getEmail()); + System.out.println(botRequest.getUser()); + System.out.println(botRequest.getTime()); + + if (botRequest.getMsg().startsWith("http")) { + return getRecommendationsFromSpaceLink(botRequest); + } else if (botRequest.getIntent().equals("number_selection")) { + // Recommendations for your saved spaces + if (botRequest.getMsg().equals("1")) { + try { + Envelope env = Context.get().requestEnvelope(buildBotSpacesId(botRequest.getUser())); + List spaceIds = (List) env.getContent(); + RecommenderQuestionList rqList = new RecommenderQuestionList(); + // Read out users profile + String loginName = botRequest.getUser(); + String agentId = Context.get().getUserAgentIdentifierByLoginName(loginName); + + for (String spaceId : spaceIds) { + RecommenderQuestionList list = (RecommenderQuestionList) Context.get().invoke( + new ServiceNameVersion(NoracleRecommenderService.class.getCanonicalName(), NoracleService.API_VERSION), + "getRecommendedQuestionsForSpace", agentId, spaceId); + rqList.addAll(list); + } + return createBotResponseFromRecommendations(rqList); + } catch (EnvelopeNotFoundException | EnvelopeAccessDeniedException | EnvelopeOperationFailedException e) { + String msg = "You do not have any saved spaces."; + msg += "\n" + optionMsg; + return new BotResponse(msg, false); + } + // Recommendations for a specific space + } else if (botRequest.getMsg().equals("2")) { + return new BotResponse("Can you send me the invitation (share) link of the space where you want to get recommendations from?", false); + } else if (botRequest.getMsg().equals("3")) { + return new BotResponse("Okay :/", true); + } + } + + String msg = "Sorry, but I cannot answer.\n\n" + optionMsg; + return new BotResponse(msg, false); + + } + + private BotResponse getRecommendationsFromSpaceLink(BotRequest botRequest) { + RecommenderQuestionList recommenderQuestionList = new RecommenderQuestionList(); + try { + // invite the bot into the space + String invitationLink = botRequest.getMsg(); + String spaceSecret = ""; + String spaceId = ""; + try { + new URL(invitationLink); + spaceSecret = invitationLink.substring(invitationLink.indexOf("?pw=") + 4); + spaceId = invitationLink.substring(invitationLink.indexOf("/spaces/") + 8, invitationLink.indexOf("?pw=")); + } catch (MalformedURLException | IndexOutOfBoundsException ex) { + String msg = "Sorry, but I cannot use this link.\n\n" + optionMsg; + return new BotResponse(msg, false); + } + + // Read out users profile + String loginName = botRequest.getUser(); + String agentId = Context.get().getUserAgentIdentifierByLoginName(loginName); + + System.out.println("mainAgentId: " + Context.get().getMainAgent().getIdentifier()); + System.out.println("agentId: " + agentId); + System.out.println("SpaceSecret: " + spaceSecret); + System.out.println("spaceId: " + spaceId); + + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleAgentService.class.getCanonicalName(), NoracleService.API_VERSION), + "checkIfAlreadySubscribedToSpace", Context.get().getMainAgent().getIdentifier(), spaceId); + + if (rmiResult instanceof Boolean) { + if (!((Boolean) rmiResult)) { + System.out.println("The Bot is not subscribed to this space"); + Context.get().invoke( + new ServiceNameVersion(NoracleAgentService.class.getCanonicalName(), NoracleService.API_VERSION), + "subscribeToSpace", spaceId, spaceSecret); + } else { + System.out.println("The Bot is already subscribed to this space"); + } + } else { + throw new InternalServiceException( + "Unexpected result (" + rmiResult.getClass().getCanonicalName() + ") of RMI call -> getRecommendedQuestions(...)"); + } + + // Create or extend envelope + Envelope env; + List spaceIdList; + try { + env = Context.get().requestEnvelope(buildBotSpacesId(botRequest.getUser())); + spaceIdList = (List) env.getContent(); + if (!spaceIdList.contains(spaceId)) { + spaceIdList.add(spaceId); + } + } catch (EnvelopeNotFoundException ex) { + env = Context.get().createEnvelope(buildBotSpacesId(botRequest.getUser())); + spaceIdList = new ArrayList<>(); + spaceIdList.add(spaceId); + } + env.setContent((Serializable) spaceIdList); + Context.get().storeEnvelope(env, (toStore, inNetwork) -> { + logger.info("onCollision was called...."); + return toStore; + }); + + rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleRecommenderService.class.getCanonicalName(), NoracleService.API_VERSION), + "getRecommendedQuestionsForSpace", agentId, spaceId); + if (rmiResult instanceof RecommenderQuestionList) { + recommenderQuestionList = (RecommenderQuestionList) rmiResult; + } else { + throw new InternalServiceException( + "Unexpected result (" + rmiResult.getClass().getCanonicalName() + ") of RMI call -> getRecommendedQuestions(...)"); + } + + } catch (JsonSyntaxException ex) { + System.out.println("Input is invalid json."); + System.out.println(ex.getMessage()); + } catch (Exception ex) { + // error + ex.printStackTrace(); + } + + if (recommenderQuestionList.isEmpty()) { + return new BotResponse("Sorry, I could not find any recommendations for you :(", true); + } + + return createBotResponseFromRecommendations(recommenderQuestionList); + } + + private BotResponse createBotResponseFromRecommendations(RecommenderQuestionList recommenderQuestionList) { + // TODO: Order by Utility!!! + if (recommenderQuestionList.size() > 6) { + Collections.shuffle(recommenderQuestionList); + } + int nrRec = Math.min(6, recommenderQuestionList.size()); + + String text = "Here are the top " + nrRec + " questions for you :)\n"; + int index = 1; + DateFormat formatter1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + DateFormat formatter2 = new SimpleDateFormat("E, dd MMM yyyy HH:mm"); + for (RecommenderQuestion rq : recommenderQuestionList) { + if (index == nrRec + 1) { + break; + } + if (!text.isEmpty()) { + text += "\n"; + } + // Markdown style [text](https://url.com) + String q = rq.getQuestion().getText(); + q = q.replace("\n", "").replace("\r", ""); + //text += index + ". [" + q + "]"; + text += ":speech_balloon: [" + q + "]"; + + text += "(https://noracle.tech4comp.dbis.rwth-aachen.de/spaces/"; + text += rq.getQuestion().getSpaceId(); + text += "?sq=%5B%22"; + text += rq.getQuestion().getQuestionId(); + text += "%22%5D)"; + + try { + Date date = formatter1.parse(rq.getQuestion().getTimestampCreated()); + text += ", Asked by " + rq.getAuthorName(); + text += ", Created at " + formatter2.format(date) + "\n"; + } catch (ParseException ex) { + logger.warning(ex.getMessage()); + } + index++; + } + return new BotResponse(text, true); + } + + private String buildBotSpacesId(String user) { + return "bot-recommender-spaces-user-" + user; + } + + private final L2pLogger logger = L2pLogger.getInstance(RecommenderResource.class.getName()); + + private final String optionMsg = "1. Recommended questions for your saved spaces\\n" + + "2. Recommended questions for a specific space (+ save the space)\\n" + + "3. Cancel\\n" + + "Please specify one option (1 - 3)."; +} diff --git a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/SpacesResource.java b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/SpacesResource.java index 998da0a..b3cace0 100644 --- a/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/SpacesResource.java +++ b/noracleService/src/main/java/i5/las2peer/services/noracleService/resources/SpacesResource.java @@ -8,12 +8,11 @@ import i5.las2peer.logging.L2pLogger; import i5.las2peer.restMapper.ExceptionEntity; import i5.las2peer.services.noracleService.NoracleAgentService; +import i5.las2peer.services.noracleService.NoracleQuestionService; import i5.las2peer.services.noracleService.NoracleService; import i5.las2peer.services.noracleService.NoracleSpaceService; import i5.las2peer.services.noracleService.api.INoracleSpaceService; -import i5.las2peer.services.noracleService.model.Space; -import i5.las2peer.services.noracleService.model.SpaceSubscribersList; -import i5.las2peer.services.noracleService.model.SpaceSubscription; +import i5.las2peer.services.noracleService.model.*; import i5.las2peer.services.noracleService.pojo.CreateSpacePojo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiParam; @@ -23,6 +22,7 @@ import net.minidev.json.parser.JSONParser; import net.minidev.json.parser.ParseException; +import javax.print.attribute.standard.Media; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -30,6 +30,7 @@ import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; +import java.util.List; @Api( tags = { SpacesResource.RESOURCE_NAME }) @@ -55,7 +56,9 @@ public class SpacesResource implements INoracleSpaceService { response = ExceptionEntity.class) }) public Response createSpace(@ApiParam( required = true) CreateSpacePojo createSpacePojo) throws ServiceInvocationException { - Space space = createSpace(createSpacePojo.getName()); + //logger.info("SpacesResource -> CreateSpace: " + createSpacePojo.getName() + ", " + createSpacePojo.isPrivate()); + Space space = createSpace(createSpacePojo.getName(), createSpacePojo.isPrivate()); + //logger.info("Created Space: " + space.getName() + "/" + space.getSpaceId() + "/" + space.getSpaceSecret()); try { Gson gson = new Gson(); @@ -89,10 +92,10 @@ public Response createSpace(@ApiParam( } @Override - public Space createSpace(String name) throws ServiceInvocationException { + public Space createSpace(String name, boolean isPrivate) throws ServiceInvocationException { Serializable rmiResult = Context.get().invoke( new ServiceNameVersion(NoracleSpaceService.class.getCanonicalName(), NoracleService.API_VERSION), - "createSpace", name); + "createSpace", name, isPrivate); Space space; if (rmiResult instanceof Space) { space = (Space) rmiResult; @@ -103,6 +106,25 @@ public Space createSpace(String name) throws ServiceInvocationException { return space; } + @Override + @DELETE + @Path("/{spaceId}") + //@Produces(MediaType.APPLICATION_JSON) + public void deleteSpace(@PathParam("spaceId") String spaceId) throws ServiceInvocationException { + //logger.info("delete space called with spaceId = " + spaceId); + Serializable rmiResult = Context.get().invoke( + new ServiceNameVersion(NoracleSpaceService.class.getCanonicalName(), NoracleService.API_VERSION), + "deleteSpace", spaceId); + /*Space space; + if (rmiResult instanceof Space) { + space = (Space) rmiResult; + } else { + throw new InternalServiceException( + "Unexpected result (" + rmiResult.getClass().getCanonicalName() + ") of RMI call"); + } + return space;*/ + } + @Override @GET @Path("/{spaceId}") @@ -128,11 +150,13 @@ public Space createSpace(String name) throws ServiceInvocationException { message = "Internal Server Error", response = ExceptionEntity.class) }) public Space getSpace(@PathParam("spaceId") String spaceId) { + //logger.info("SpacesResource -> getSpace with spaceId: " + spaceId); try { Serializable rmiResult = Context.get().invoke( new ServiceNameVersion(NoracleSpaceService.class.getCanonicalName(), NoracleService.API_VERSION), "getSpace", spaceId); if (rmiResult instanceof Space) { + //logger.info("found space with: " + ((Space) rmiResult).getName() + "/" + ((Space) rmiResult).getSpaceSecret()); return (Space) rmiResult; } else { throw new InternalServiceException( @@ -195,6 +219,29 @@ public SpaceSubscribersList getSubscribers(@PathParam("spaceId") String spaceId) } } + @Override + @GET + @Path("/public") + @Produces(MediaType.APPLICATION_JSON) + public SpaceList getPublicSpaces() { + logger.info("SpacesResource -> getPublicSpaces(..)"); + try { + SpaceList list = (SpaceList) Context.get().invoke( + new ServiceNameVersion(NoracleSpaceService.class.getCanonicalName(), NoracleService.API_VERSION), + "getPublicSpaces"); + logger.info("Returned list with size: " + list.size()); + return list; + } catch (InvocationBadArgumentException e) { + throw new BadRequestException(e.getMessage(), e.getCause()); + } catch (ResourceNotFoundException e) { + throw new NotFoundException(e.getMessage(), e.getCause()); + } catch (ServiceAccessDeniedException e) { + throw new ForbiddenException(e.getMessage(), e.getCause()); + } catch (Exception e) { + throw new InternalServerErrorException("Exception during RMI call", e); + } + } + @Path("/{spaceId}/" + QuestionsResource.RESOURCE_NAME) public QuestionsResource questions() { return new QuestionsResource(); diff --git a/noracleService/src/test/java/i5/las2peer/services/noracleService/NoracleRecommenderServiceTest.java b/noracleService/src/test/java/i5/las2peer/services/noracleService/NoracleRecommenderServiceTest.java new file mode 100644 index 0000000..bbc80b3 --- /dev/null +++ b/noracleService/src/test/java/i5/las2peer/services/noracleService/NoracleRecommenderServiceTest.java @@ -0,0 +1,254 @@ +package i5.las2peer.services.noracleService; + +import i5.las2peer.api.p2p.ServiceNameVersion; +import i5.las2peer.connectors.webConnector.WebConnector; +import i5.las2peer.p2p.Node; +import i5.las2peer.p2p.PastryNodeImpl; +import i5.las2peer.security.ServiceAgentImpl; +import i5.las2peer.security.UserAgentImpl; +import i5.las2peer.services.noracleService.model.Question; +import i5.las2peer.services.noracleService.model.RecommenderQuestionList; +import i5.las2peer.services.noracleService.model.Space; +import i5.las2peer.services.noracleService.pojo.CreateQuestionPojo; +import i5.las2peer.services.noracleService.pojo.CreateSpacePojo; +import i5.las2peer.services.noracleService.pojo.SetVotePojo; +import i5.las2peer.services.noracleService.resources.*; +import i5.las2peer.testing.MockAgentFactory; +import i5.las2peer.testing.TestSuite; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.client.*; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; + +public class NoracleRecommenderServiceTest { + private static final String TEST_SPACE_NAME = "so many questions"; + private static final String TEST_QUESTION_TEXT_1 = "How are you?"; + private static final String TEST_QUESTION_TEXT_2 = "What's up in-your-life?"; + private static final String TEST_QUESTION_TEXT_3 = "What is going on?"; + + protected int networkSize = 1; + protected ArrayList nodes; + protected WebConnector connector; + protected Client webClient; + protected UserAgentImpl testAgent; + protected UserAgentImpl testAgent2; + protected UserAgentImpl testAgent3; + protected String basicAuthHeader; + protected String basicAuthHeader2; + protected String basicAuthHeader3; + protected String baseUrl; + + /** + * Called before a test starts. + * + * Sets up the node, initializes connector and adds user agent that can be used throughout the test. + * + * @throws Exception + */ + @Before + public void beforeTest() { + + try { + nodes = TestSuite.launchNetwork(networkSize); + connector = new WebConnector(null); + connector.start(nodes.get(0)); + // don't follow redirects, some tests want to test for correct redirect + // responses + webClient = ClientBuilder.newBuilder().register(MultiPartFeature.class) + .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.FALSE).build(); + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleService", + NoracleService.API_VERSION); + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleAgentService", + NoracleService.API_VERSION); + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleSpaceService", + NoracleService.API_VERSION); + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleQuestionService", + NoracleService.API_VERSION); + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleQuestionRelationService", + NoracleService.API_VERSION); + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleVoteService", + NoracleService.API_VERSION); + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleRecommenderService", + NoracleService.API_VERSION); + testAgent = MockAgentFactory.getAdam(); + testAgent.unlock("adamspass"); + PastryNodeImpl activeNode = nodes.get(0); + activeNode.storeAgent(testAgent); + basicAuthHeader = "basic " + Base64.getEncoder() + .encodeToString((testAgent.getLoginName() + ":" + "adamspass").getBytes(StandardCharsets.UTF_8)); + + testAgent2 = MockAgentFactory.getEve(); + testAgent2.unlock("evespass"); + activeNode.storeAgent(testAgent2); + basicAuthHeader2 = "basic " + Base64.getEncoder() + .encodeToString((testAgent2.getLoginName() + ":" + "evespass").getBytes(StandardCharsets.UTF_8)); + + testAgent3 = MockAgentFactory.getAbel(); + testAgent3.unlock("abelspass"); + activeNode.storeAgent(testAgent3); + basicAuthHeader3 = "basic " + Base64.getEncoder() + .encodeToString((testAgent3.getLoginName() + ":" + "abelspass").getBytes(StandardCharsets.UTF_8)); + + baseUrl = connector.getHttpEndpoint() + "/" + NoracleService.RESOURCE_NAME + "/v" + + NoracleService.API_VERSION; + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); + } + } + + private void startService(Node node, String clsName, String version) throws Exception { + ServiceAgentImpl serviceAgent = ServiceAgentImpl.createServiceAgent(new ServiceNameVersion(clsName, version), + "testtest"); + serviceAgent.unlock("testtest"); + node.storeAgent(serviceAgent); + node.registerReceiver(serviceAgent); + } + + /** + * Called after the test has finished. Shuts down the server and prints out the connector log file for reference. + * + * @throws Exception + */ + @After + public void afterTest() { + for (PastryNodeImpl node : nodes) { + try { + node.shutDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Test + public void testGetSimpleRecommendationsForSpace() { + long start = System.nanoTime(); + try { + // create test space and questions with testAgent + Space space = createAndFetchTestSpace(); + String questionId1 = createTestQuestions(space.getSpaceId(), TEST_QUESTION_TEXT_1); + String questionId2 = createTestQuestions(space.getSpaceId(), TEST_QUESTION_TEXT_2); + String questionId3 = createTestQuestions(space.getSpaceId(), TEST_QUESTION_TEXT_3); + + // set votes with testAgent2 + setVote("/" + SpacesResource.RESOURCE_NAME + "/" + space.getSpaceId() + "/" + QuestionsResource.RESOURCE_NAME + "/" + + questionId1 + "/" + QuestionVotesResource.RESOURCE_NAME + "/" + testAgent2.getIdentifier(), + basicAuthHeader, 0); + setVote("/" + SpacesResource.RESOURCE_NAME + "/" + space.getSpaceId() + "/" + QuestionsResource.RESOURCE_NAME + "/" + + questionId2 + "/" + QuestionVotesResource.RESOURCE_NAME + "/" + testAgent2.getIdentifier(), + basicAuthHeader, 1); + setVote("/" + SpacesResource.RESOURCE_NAME + "/" + space.getSpaceId() + "/" + QuestionsResource.RESOURCE_NAME + "/" + + questionId3 + "/" + QuestionVotesResource.RESOURCE_NAME + "/" + testAgent2.getIdentifier(), + basicAuthHeader, -1); + + // call recommender service with testAgent3 + WebTarget target = webClient.target(baseUrl + "/" + RecommenderResource.RESOURCE_NAME + "/" + testAgent3.getIdentifier() + "/" + space.getSpaceId()); + Invocation.Builder request = target.request().header(HttpHeaders.AUTHORIZATION, basicAuthHeader); + Response response = request.get(); + Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + Assert.assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType()); + + RecommenderQuestionList recommendations = response.readEntity(RecommenderQuestionList.class); + Assert.assertEquals(recommendations.size(), 3); + Assert.assertEquals(recommendations.get(0).getQuestion().getQuestionId(), questionId2); + Assert.assertEquals(recommendations.get(1).getQuestion().getQuestionId(), questionId1); + Assert.assertEquals(recommendations.get(2).getQuestion().getQuestionId(), questionId3); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); + } + long end = System.nanoTime(); + System.out.println("start: " + start + "ns"); + System.out.println("end: " + end + "ns"); + System.out.println("result: " + (end-start)); + } + + @Test + public void testGetSimpleRecommendations() { + try { + // create test space with questions + Space space = createAndFetchTestSpace(); + createTestQuestions(space.getSpaceId(), TEST_QUESTION_TEXT_1); + createTestQuestions(space.getSpaceId(), TEST_QUESTION_TEXT_2); + createTestQuestions(space.getSpaceId(), TEST_QUESTION_TEXT_3); + WebTarget target = webClient.target(baseUrl + "/" + RecommenderResource.RESOURCE_NAME + "/" + testAgent.getIdentifier()); + Invocation.Builder request = target.request().header(HttpHeaders.AUTHORIZATION, basicAuthHeader); + Response response = request.get(); + Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + Assert.assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType()); + + RecommenderQuestionList recommendations = response.readEntity(RecommenderQuestionList.class); + recommendations.stream().forEach(r -> System.out.println(r.getQuestion().getText())); + Assert.assertEquals(recommendations.size(), 3); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); + } + } + + protected Space createAndFetchTestSpace() { + // create test space + CreateSpacePojo body = new CreateSpacePojo(); + body.setName(TEST_SPACE_NAME); + WebTarget target = webClient.target(baseUrl + "/" + SpacesResource.RESOURCE_NAME); + Invocation.Builder request = target.request().header(HttpHeaders.AUTHORIZATION, basicAuthHeader); + Response response = request.post(Entity.json(body)); + Assert.assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); + Assert.assertEquals(MediaType.TEXT_HTML_TYPE, response.getMediaType()); + // fetch test space + String locationHeader = response.getHeaderString(HttpHeaders.LOCATION); + WebTarget targetSpace = webClient.target(locationHeader); + Invocation.Builder requestSpace = targetSpace.request().header(HttpHeaders.AUTHORIZATION, basicAuthHeader); + Response responseSpace = requestSpace.get(); + Assert.assertEquals(Response.Status.OK.getStatusCode(), responseSpace.getStatus()); + Assert.assertEquals(MediaType.APPLICATION_JSON_TYPE, responseSpace.getMediaType()); + Space space = responseSpace.readEntity(Space.class); + return space; + } + + protected String createTestQuestions(String testSpaceId, String testQuestion) throws Exception { + // create question in space + CreateQuestionPojo body = new CreateQuestionPojo(); + body.setText(testQuestion); + WebTarget target = webClient.target(baseUrl + "/" + SpacesResource.RESOURCE_NAME + "/" + testSpaceId + "/" + + QuestionsResource.RESOURCE_NAME); + Invocation.Builder request = target.request().header(HttpHeaders.AUTHORIZATION, basicAuthHeader); + Response response = request.post(Entity.json(body)); + Assert.assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); + Assert.assertEquals(MediaType.TEXT_HTML_TYPE, response.getMediaType()); + // fetch test question + String locationHeader = response.getHeaderString(HttpHeaders.LOCATION); + WebTarget targetQuestion = webClient.target(locationHeader); + Invocation.Builder requestQuestion = targetQuestion.request().header(HttpHeaders.AUTHORIZATION, basicAuthHeader); + Response responseQuestion = requestQuestion.get(); + Assert.assertEquals(Response.Status.OK.getStatusCode(), responseQuestion.getStatus()); + Assert.assertEquals(MediaType.APPLICATION_JSON_TYPE, responseQuestion.getMediaType()); + Question question = responseQuestion.readEntity(Question.class); + Assert.assertEquals(testSpaceId, question.getSpaceId()); + Assert.assertEquals(testQuestion, question.getText()); + Assert.assertEquals(question.getTimestampCreated(), question.getTimestampLastModified()); + return question.getQuestionId(); + } + + private void setVote(String path, String authHeader, int value) { + SetVotePojo body = new SetVotePojo(); + body.setValue(value); + WebTarget target = webClient.target(baseUrl + path); + Invocation.Builder request = target.request().header(HttpHeaders.AUTHORIZATION, authHeader); + Response response = request.put(Entity.json(body)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + Assert.assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType()); + } + +} diff --git a/noracleService/src/test/java/i5/las2peer/services/noracleService/NoracleServiceTest.java b/noracleService/src/test/java/i5/las2peer/services/noracleService/NoracleServiceTest.java index 9f0ea72..1839d4a 100644 --- a/noracleService/src/test/java/i5/las2peer/services/noracleService/NoracleServiceTest.java +++ b/noracleService/src/test/java/i5/las2peer/services/noracleService/NoracleServiceTest.java @@ -76,8 +76,7 @@ public void beforeTest() { NoracleService.API_VERSION); startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleQuestionRelationService", NoracleService.API_VERSION); - startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleVoteSe" + - "rvice", + startService(nodes.get(0), "i5.las2peer.services.noracleService.NoracleVoteService", NoracleService.API_VERSION); testAgent = MockAgentFactory.getAdam(); testAgent.unlock("adamspass"); @@ -259,7 +258,7 @@ public void testAgentProfile() { } } - @Test +/* @Test public void testUpdateSelectedQuestions() { try { String testSpaceId = createAndFetchTestSpace().getSpaceId(); @@ -292,7 +291,7 @@ public void testUpdateSelectedQuestions() { e.printStackTrace(); Assert.fail(e.toString()); } - } + }*/ @Test public void testSpaceForeignSubscribeNoSecret() { @@ -468,7 +467,7 @@ public void testGetQuestions() { Response response = request.get(); Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); Assert.assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType()); - VotedQuestionList questionList = response.readEntity(VotedQuestionList.class); + ArrayList questionList = response.readEntity(VotedQuestionList.class); Assert.assertEquals(3, questionList.size()); Assert.assertEquals(questionList.get(0).getQuestionId(), questionId1); Assert.assertEquals(questionList.get(1).getQuestionId(), questionId2); diff --git a/start-local.sh b/start-local.sh deleted file mode 100755 index f8f3fb2..0000000 --- a/start-local.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -PORT=9012 - -echo "launching node at port ${PORT}" -java -cp "lib/*" i5.las2peer.tools.L2pNodeLauncher diff --git a/start-node.sh b/start-node.sh deleted file mode 100755 index 3850357..0000000 --- a/start-node.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -PIDFILE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/node-screen.pid -echo "$PIDFILE" - -# ASSUMES THAT THE DIRECTORY THIS FILE IS LOCATED IN HAS THE SAME NAME AS THE PORT OF THIS NODE!!! -PORT=${PWD##*/} - -echo "launching node at port ${PORT}" -screen -S "${PORT}" -D -m java -cp "lib/*" i5.las2peer.tools.L2pNodeLauncher & -# save process id to be used later -echo $! > "$PIDFILE" - diff --git a/stop-node.sh b/stop-node.sh deleted file mode 100755 index 3ad5318..0000000 --- a/stop-node.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -PIDFILE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/node-screen.pid -echo "$PIDFILE" - -# ASSUMES THAT THE DIRECTORY THIS FILE IS LOCATED IN HAS THE SAME NAME AS THE PORT OF THIS NODE!!! -PORT=${PWD##*/} - -echo "stopping node at port ${PORT}" -while read pid; do - echo "killing process $pid" - kill $pid -done < "$PIDFILE" -/bin/rm "$PIDFILE" - diff --git a/upload-frontend.sh b/upload-frontend.sh deleted file mode 100755 index 866a987..0000000 --- a/upload-frontend.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -cd frontend && find "noracle/" -type f -exec curl --user "noracle-example-smith:testtest" --form "filecontent=@{};filename={}" --form identifier="{}" http://localhost:9082/fileservice/files --insecure \; -exec echo "" \;