From 7b3c53fcb9cfc87b723ee33bc189684a862bafbd Mon Sep 17 00:00:00 2001 From: Athou Date: Wed, 20 Mar 2013 20:33:42 +0100 Subject: [PATCH] initial commit --- .gitignore | 12 + .openshift/action_hooks/build | 5 + .openshift/action_hooks/deploy | 5 + .openshift/action_hooks/post_deploy | 4 + .../action_hooks/post_start_jbosseap-6.0 | 14 + .../action_hooks/post_stop_jbosseap-6.0 | 14 + .openshift/action_hooks/pre_build | 5 + .../action_hooks/pre_build_jbosseap-6.0 | 5 + .../action_hooks/pre_start_jbosseap-6.0 | 14 + .openshift/action_hooks/pre_stop_jbosseap-6.0 | 14 + .openshift/config/modules/README | 3 + .openshift/config/standalone.xml | 519 ++++++++++++++++++ .openshift/cron/README.cron | 22 + .openshift/cron/daily/.gitignore | 0 .openshift/cron/daily/log-cleanup.sh | 1 + .openshift/cron/hourly/.gitignore | 0 .openshift/cron/minutely/.gitignore | 0 .openshift/cron/monthly/.gitignore | 0 .openshift/cron/weekly/README | 16 + .openshift/cron/weekly/chrono.dat | 1 + .openshift/cron/weekly/chronograph | 3 + .openshift/cron/weekly/jobs.allow | 12 + .openshift/cron/weekly/jobs.deny | 7 + .openshift/markers/README | 22 + .openshift/markers/java7 | 0 README.md | 5 + deployments/.gitkeep | 0 pom.xml | 225 ++++++++ src/main/java/.gitkeep | 0 .../com/commafeed/backend/StartupBean.java | 74 +++ .../backend/dao/FeedCategoryService.java | 17 + .../backend/dao/FeedEntryService.java | 31 ++ .../commafeed/backend/dao/FeedService.java | 10 + .../backend/dao/FeedSubscriptionService.java | 18 + .../com/commafeed/backend/dao/GenericDAO.java | 89 +++ .../commafeed/backend/dao/UserService.java | 30 + .../commafeed/backend/feeds/FeedFetcher.java | 53 ++ .../commafeed/backend/feeds/FeedParser.java | 49 ++ .../commafeed/backend/feeds/FeedTimer.java | 48 ++ .../security/PasswordEncryptionService.java | 89 +++ .../frontend/CommaFeedApplication.java | 116 ++++ .../commafeed/frontend/CommaFeedSession.java | 51 ++ .../frontend/components/CssTreeView.html | 24 + .../frontend/components/CssTreeView.java | 82 +++ .../frontend/components/auth/LoginPage.html | 16 + .../frontend/components/auth/LoginPage.java | 21 + .../frontend/components/auth/LoginPanel.html | 28 + .../frontend/components/auth/LoginPanel.java | 12 + .../frontend/components/auth/Role.java | 6 + .../commafeed/frontend/pages/BasePage.html | 10 + .../commafeed/frontend/pages/BasePage.java | 19 + .../frontend/pages/feed/FeedViewPage.html | 17 + .../frontend/pages/feed/FeedViewPage.java | 115 ++++ .../frontend/pages/home/HomePage.java | 7 + .../csstree/CssTreeViewReference.java | 25 + .../references/csstree/css3-treeview.css | 115 ++++ .../frontend/references/csstree/icons.png | Bin 0 -> 762 bytes .../frontend/utils/MapToListModel.java | 40 ++ .../frontend/utils/ModelFactory.java | 58 ++ .../commafeed/frontend/utils/WicketUtils.java | 135 +++++ .../utils/exception/DisplayException.java | 23 + .../utils/exception/DisplayExceptionPage.html | 31 ++ .../utils/exception/DisplayExceptionPage.java | 40 ++ .../BootstrapStatelessAjaxButton.java | 93 ++++ .../stateless/BootstrapStatelessAjaxLink.java | 55 ++ .../stateless/StatelessAjaxEventBehavior.java | 36 ++ ...lessAjaxFormComponentUpdatingBehavior.java | 37 ++ .../StatelessAjaxFormSubmitBehavior.java | 43 ++ .../utils/stateless/StatelessAjaxLink.java | 70 +++ .../utils/stateless/StatelessEncoder.java | 42 ++ .../utils/stateless/StatelessLink.java | 43 ++ src/main/java/com/commafeed/model/Feed.java | 64 +++ .../com/commafeed/model/FeedCategory.java | 78 +++ .../java/com/commafeed/model/FeedEntry.java | 86 +++ .../com/commafeed/model/FeedEntryStatus.java | 71 +++ .../com/commafeed/model/FeedSubscription.java | 73 +++ src/main/java/com/commafeed/model/User.java | 61 ++ src/main/resources/.gitkeep | 0 src/main/resources/META-INF/persistence.xml | 18 + src/main/resources/log4j.properties | 16 + src/main/webapp/WEB-INF/beans.xml | 11 + src/main/webapp/WEB-INF/web.xml | 22 + 82 files changed, 3346 insertions(+) create mode 100644 .gitignore create mode 100644 .openshift/action_hooks/build create mode 100644 .openshift/action_hooks/deploy create mode 100644 .openshift/action_hooks/post_deploy create mode 100644 .openshift/action_hooks/post_start_jbosseap-6.0 create mode 100644 .openshift/action_hooks/post_stop_jbosseap-6.0 create mode 100644 .openshift/action_hooks/pre_build create mode 100644 .openshift/action_hooks/pre_build_jbosseap-6.0 create mode 100644 .openshift/action_hooks/pre_start_jbosseap-6.0 create mode 100644 .openshift/action_hooks/pre_stop_jbosseap-6.0 create mode 100644 .openshift/config/modules/README create mode 100644 .openshift/config/standalone.xml create mode 100644 .openshift/cron/README.cron create mode 100644 .openshift/cron/daily/.gitignore create mode 100644 .openshift/cron/daily/log-cleanup.sh create mode 100644 .openshift/cron/hourly/.gitignore create mode 100644 .openshift/cron/minutely/.gitignore create mode 100644 .openshift/cron/monthly/.gitignore create mode 100644 .openshift/cron/weekly/README create mode 100644 .openshift/cron/weekly/chrono.dat create mode 100644 .openshift/cron/weekly/chronograph create mode 100644 .openshift/cron/weekly/jobs.allow create mode 100644 .openshift/cron/weekly/jobs.deny create mode 100644 .openshift/markers/README create mode 100644 .openshift/markers/java7 create mode 100644 README.md create mode 100644 deployments/.gitkeep create mode 100644 pom.xml create mode 100644 src/main/java/.gitkeep create mode 100644 src/main/java/com/commafeed/backend/StartupBean.java create mode 100644 src/main/java/com/commafeed/backend/dao/FeedCategoryService.java create mode 100644 src/main/java/com/commafeed/backend/dao/FeedEntryService.java create mode 100644 src/main/java/com/commafeed/backend/dao/FeedService.java create mode 100644 src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java create mode 100644 src/main/java/com/commafeed/backend/dao/GenericDAO.java create mode 100644 src/main/java/com/commafeed/backend/dao/UserService.java create mode 100644 src/main/java/com/commafeed/backend/feeds/FeedFetcher.java create mode 100644 src/main/java/com/commafeed/backend/feeds/FeedParser.java create mode 100644 src/main/java/com/commafeed/backend/feeds/FeedTimer.java create mode 100644 src/main/java/com/commafeed/backend/security/PasswordEncryptionService.java create mode 100644 src/main/java/com/commafeed/frontend/CommaFeedApplication.java create mode 100644 src/main/java/com/commafeed/frontend/CommaFeedSession.java create mode 100644 src/main/java/com/commafeed/frontend/components/CssTreeView.html create mode 100644 src/main/java/com/commafeed/frontend/components/CssTreeView.java create mode 100644 src/main/java/com/commafeed/frontend/components/auth/LoginPage.html create mode 100644 src/main/java/com/commafeed/frontend/components/auth/LoginPage.java create mode 100644 src/main/java/com/commafeed/frontend/components/auth/LoginPanel.html create mode 100644 src/main/java/com/commafeed/frontend/components/auth/LoginPanel.java create mode 100644 src/main/java/com/commafeed/frontend/components/auth/Role.java create mode 100644 src/main/java/com/commafeed/frontend/pages/BasePage.html create mode 100644 src/main/java/com/commafeed/frontend/pages/BasePage.java create mode 100644 src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.html create mode 100644 src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.java create mode 100644 src/main/java/com/commafeed/frontend/pages/home/HomePage.java create mode 100644 src/main/java/com/commafeed/frontend/references/csstree/CssTreeViewReference.java create mode 100644 src/main/java/com/commafeed/frontend/references/csstree/css3-treeview.css create mode 100644 src/main/java/com/commafeed/frontend/references/csstree/icons.png create mode 100644 src/main/java/com/commafeed/frontend/utils/MapToListModel.java create mode 100644 src/main/java/com/commafeed/frontend/utils/ModelFactory.java create mode 100644 src/main/java/com/commafeed/frontend/utils/WicketUtils.java create mode 100644 src/main/java/com/commafeed/frontend/utils/exception/DisplayException.java create mode 100644 src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.html create mode 100644 src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxButton.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxLink.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxEventBehavior.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormComponentUpdatingBehavior.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormSubmitBehavior.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxLink.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/StatelessEncoder.java create mode 100644 src/main/java/com/commafeed/frontend/utils/stateless/StatelessLink.java create mode 100644 src/main/java/com/commafeed/model/Feed.java create mode 100644 src/main/java/com/commafeed/model/FeedCategory.java create mode 100644 src/main/java/com/commafeed/model/FeedEntry.java create mode 100644 src/main/java/com/commafeed/model/FeedEntryStatus.java create mode 100644 src/main/java/com/commafeed/model/FeedSubscription.java create mode 100644 src/main/java/com/commafeed/model/User.java create mode 100644 src/main/resources/.gitkeep create mode 100644 src/main/resources/META-INF/persistence.xml create mode 100644 src/main/resources/log4j.properties create mode 100644 src/main/webapp/WEB-INF/beans.xml create mode 100644 src/main/webapp/WEB-INF/web.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f9c6420c --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +#log files +commafeed.log +derby.log + +# Maven build directory +target + +# Eclipse files +.project +.classpath +.settings +.factorypath diff --git a/.openshift/action_hooks/build b/.openshift/action_hooks/build new file mode 100644 index 00000000..f0861010 --- /dev/null +++ b/.openshift/action_hooks/build @@ -0,0 +1,5 @@ +#!/bin/bash +# This is a simple build script and will be executed on your CI system if +# available. Otherwise it will execute while your application is stopped +# before the deploy step. This script gets executed directly, so it +# could be python, php, ruby, etc. diff --git a/.openshift/action_hooks/deploy b/.openshift/action_hooks/deploy new file mode 100644 index 00000000..ed5eb993 --- /dev/null +++ b/.openshift/action_hooks/deploy @@ -0,0 +1,5 @@ +#!/bin/bash +# This deploy hook gets executed after dependencies are resolved and the +# build hook has been run but before the application has been started back +# up again. This script gets executed directly, so it could be python, php, +# ruby, etc. \ No newline at end of file diff --git a/.openshift/action_hooks/post_deploy b/.openshift/action_hooks/post_deploy new file mode 100644 index 00000000..a57d1f58 --- /dev/null +++ b/.openshift/action_hooks/post_deploy @@ -0,0 +1,4 @@ +#!/bin/bash +# This is a simple post deploy hook executed after your application +# is deployed and started. This script gets executed directly, so +# it could be python, php, ruby, etc. \ No newline at end of file diff --git a/.openshift/action_hooks/post_start_jbosseap-6.0 b/.openshift/action_hooks/post_start_jbosseap-6.0 new file mode 100644 index 00000000..ff0debda --- /dev/null +++ b/.openshift/action_hooks/post_start_jbosseap-6.0 @@ -0,0 +1,14 @@ +#!/bin/bash + +# The pre_start_cartridge and pre_stop_cartridge hooks are *SOURCED* +# immediately before (re)starting or stopping the specified cartridge. +# They are able to make any desired environment variable changes as +# well as other adjustments to the application environment. + +# The post_start_cartridge and post_stop_cartridge hooks are executed +# immediately after (re)starting or stopping the specified cartridge. + +# Exercise caution when adding commands to these hooks. They can +# prevent your application from stopping cleanly or starting at all. +# Application start and stop is subject to different timeouts +# throughout the system. diff --git a/.openshift/action_hooks/post_stop_jbosseap-6.0 b/.openshift/action_hooks/post_stop_jbosseap-6.0 new file mode 100644 index 00000000..ff0debda --- /dev/null +++ b/.openshift/action_hooks/post_stop_jbosseap-6.0 @@ -0,0 +1,14 @@ +#!/bin/bash + +# The pre_start_cartridge and pre_stop_cartridge hooks are *SOURCED* +# immediately before (re)starting or stopping the specified cartridge. +# They are able to make any desired environment variable changes as +# well as other adjustments to the application environment. + +# The post_start_cartridge and post_stop_cartridge hooks are executed +# immediately after (re)starting or stopping the specified cartridge. + +# Exercise caution when adding commands to these hooks. They can +# prevent your application from stopping cleanly or starting at all. +# Application start and stop is subject to different timeouts +# throughout the system. diff --git a/.openshift/action_hooks/pre_build b/.openshift/action_hooks/pre_build new file mode 100644 index 00000000..10cd5446 --- /dev/null +++ b/.openshift/action_hooks/pre_build @@ -0,0 +1,5 @@ +#!/bin/bash +# This is a simple script and will be executed on your CI system if +# available. Otherwise it will execute while your application is stopped +# before the build step. This script gets executed directly, so it +# could be python, php, ruby, etc. \ No newline at end of file diff --git a/.openshift/action_hooks/pre_build_jbosseap-6.0 b/.openshift/action_hooks/pre_build_jbosseap-6.0 new file mode 100644 index 00000000..1f70dc32 --- /dev/null +++ b/.openshift/action_hooks/pre_build_jbosseap-6.0 @@ -0,0 +1,5 @@ +#!/bin/bash +# This is a simple bash script and will be sourced prior to building +# your application. This script can be used to modify the Maven build +# arguments for non-CI/Jenkins builds by exporting MAVEN_ARGS. The default +# is "clean package -Popenshift -DskipTests" diff --git a/.openshift/action_hooks/pre_start_jbosseap-6.0 b/.openshift/action_hooks/pre_start_jbosseap-6.0 new file mode 100644 index 00000000..ff0debda --- /dev/null +++ b/.openshift/action_hooks/pre_start_jbosseap-6.0 @@ -0,0 +1,14 @@ +#!/bin/bash + +# The pre_start_cartridge and pre_stop_cartridge hooks are *SOURCED* +# immediately before (re)starting or stopping the specified cartridge. +# They are able to make any desired environment variable changes as +# well as other adjustments to the application environment. + +# The post_start_cartridge and post_stop_cartridge hooks are executed +# immediately after (re)starting or stopping the specified cartridge. + +# Exercise caution when adding commands to these hooks. They can +# prevent your application from stopping cleanly or starting at all. +# Application start and stop is subject to different timeouts +# throughout the system. diff --git a/.openshift/action_hooks/pre_stop_jbosseap-6.0 b/.openshift/action_hooks/pre_stop_jbosseap-6.0 new file mode 100644 index 00000000..ff0debda --- /dev/null +++ b/.openshift/action_hooks/pre_stop_jbosseap-6.0 @@ -0,0 +1,14 @@ +#!/bin/bash + +# The pre_start_cartridge and pre_stop_cartridge hooks are *SOURCED* +# immediately before (re)starting or stopping the specified cartridge. +# They are able to make any desired environment variable changes as +# well as other adjustments to the application environment. + +# The post_start_cartridge and post_stop_cartridge hooks are executed +# immediately after (re)starting or stopping the specified cartridge. + +# Exercise caution when adding commands to these hooks. They can +# prevent your application from stopping cleanly or starting at all. +# Application start and stop is subject to different timeouts +# throughout the system. diff --git a/.openshift/config/modules/README b/.openshift/config/modules/README new file mode 100644 index 00000000..cb69cf94 --- /dev/null +++ b/.openshift/config/modules/README @@ -0,0 +1,3 @@ +Place your jboss-as7 modules in this directory. This directory is added to the +module path of the jboss-as7 server associated with your application. It has the +same structure as the jboss-as7/modules directory. diff --git a/.openshift/config/standalone.xml b/.openshift/config/standalone.xml new file mode 100644 index 00000000..b2796d4b --- /dev/null +++ b/.openshift/config/standalone.xml @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:postgresql://${env.OPENSHIFT_POSTGRESQL_DB_HOST}:${env.OPENSHIFT_POSTGRESQL_DB_PORT}/${env.OPENSHIFT_APP_NAME} + + postgresql + + ${env.OPENSHIFT_POSTGRESQL_DB_USERNAME} + ${env.OPENSHIFT_POSTGRESQL_DB_PASSWORD} + + + SELECT 1 + true + + + IdleConnections + + + + + + org.postgresql.xa.PGXADataSource + + + + + + + + + + false + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${env.OPENSHIFT_GEAR_DNS} + ${env.OPENSHIFT_JBOSSEAP_CLUSTER_PROXY_PORT} + + 7600 + ${env.OPENSHIFT_INTERNAL_IP} + + + 3000 + ${env.OPENSHIFT_JBOSSEAP_CLUSTER} + 0 + 1 + + + + + + + + + + org.jgroups.auth.MD5Token + SHA + ${env.OPENSHIFT_APP_UUID} + + + + + + + + + + + + + + + + + + + + + + + + true + true + false + 102400 + 2 + + ${messaging.thread.pool.max.size} + ${messaging.scheduled.thread.pool.max.size} + + + + + + + + + + + + + + + + + + + + + jms.queue.DLQ + jms.queue.ExpiryQueue + 0 + 1000 + 10485760 + BLOCK + 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + ${env.OPENSHIFT_GEAR_DNS} + 80 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.openshift/cron/README.cron b/.openshift/cron/README.cron new file mode 100644 index 00000000..aad91380 --- /dev/null +++ b/.openshift/cron/README.cron @@ -0,0 +1,22 @@ +Run scripts or jobs on a periodic basis +======================================= +Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly +directories will be run on a scheduled basis (frequency is as indicated by the +name of the directory) using run-parts. + +run-parts ignores any files that are hidden or dotfiles (.*) or backup +files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} + +The presence of two specially named files jobs.deny and jobs.allow controls +how run-parts executes your scripts/jobs. + jobs.deny ===> Prevents specific scripts or jobs from being executed. + jobs.allow ===> Only execute the named scripts or jobs (all other/non-named + scripts that exist in this directory are ignored). + +The principles of jobs.deny and jobs.allow are the same as those of cron.deny +and cron.allow and are described in detail at: + http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access + +See: man crontab or above link for more details and see the the weekly/ + directory for an example. + diff --git a/.openshift/cron/daily/.gitignore b/.openshift/cron/daily/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/daily/log-cleanup.sh b/.openshift/cron/daily/log-cleanup.sh new file mode 100644 index 00000000..009f1e6f --- /dev/null +++ b/.openshift/cron/daily/log-cleanup.sh @@ -0,0 +1 @@ +rm -rf $OPENSHIFT_JBOSSAS_LOG_DIR\*.log.* \ No newline at end of file diff --git a/.openshift/cron/hourly/.gitignore b/.openshift/cron/hourly/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/minutely/.gitignore b/.openshift/cron/minutely/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/monthly/.gitignore b/.openshift/cron/monthly/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/weekly/README b/.openshift/cron/weekly/README new file mode 100644 index 00000000..7c3e659f --- /dev/null +++ b/.openshift/cron/weekly/README @@ -0,0 +1,16 @@ +Run scripts or jobs on a weekly basis +===================================== +Any scripts or jobs added to this directory will be run on a scheduled basis +(weekly) using run-parts. + +run-parts ignores any files that are hidden or dotfiles (.*) or backup +files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles +the files named jobs.deny and jobs.allow specially. + +In this specific example, the chronograph script is the only script or job file +executed on a weekly basis (due to white-listing it in jobs.allow). And the +README and chrono.dat file are ignored either as a result of being black-listed +in jobs.deny or because they are NOT white-listed in the jobs.allow file. + +For more details, please see ../README.cron file. + diff --git a/.openshift/cron/weekly/chrono.dat b/.openshift/cron/weekly/chrono.dat new file mode 100644 index 00000000..fc4abb87 --- /dev/null +++ b/.openshift/cron/weekly/chrono.dat @@ -0,0 +1 @@ +Time And Relative D...n In Execution (Open)Shift! diff --git a/.openshift/cron/weekly/chronograph b/.openshift/cron/weekly/chronograph new file mode 100644 index 00000000..61de949f --- /dev/null +++ b/.openshift/cron/weekly/chronograph @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "`date`: `cat $(dirname \"$0\")/chrono.dat`" diff --git a/.openshift/cron/weekly/jobs.allow b/.openshift/cron/weekly/jobs.allow new file mode 100644 index 00000000..8d32abc7 --- /dev/null +++ b/.openshift/cron/weekly/jobs.allow @@ -0,0 +1,12 @@ +# +# Script or job files listed in here (one entry per line) will be +# executed on a weekly-basis. +# +# Example: The chronograph script will be executed weekly but the README +# and chrono.dat files in this directory will be ignored. +# +# The README file is actually ignored due to the entry in the +# jobs.deny which is checked before jobs.allow (this file). +# +chronograph + diff --git a/.openshift/cron/weekly/jobs.deny b/.openshift/cron/weekly/jobs.deny new file mode 100644 index 00000000..73c94500 --- /dev/null +++ b/.openshift/cron/weekly/jobs.deny @@ -0,0 +1,7 @@ +# +# Any script or job files listed in here (one entry per line) will NOT be +# executed (read as ignored by run-parts). +# + +README + diff --git a/.openshift/markers/README b/.openshift/markers/README new file mode 100644 index 00000000..154c7895 --- /dev/null +++ b/.openshift/markers/README @@ -0,0 +1,22 @@ +Markers +=========== + +Adding marker files to this directory will have the following effects: + +enable_jpda - Will enable the JPDA socket based transport on the java virtual + machine running the JBoss AS 7 application server. This enables + you to remotely debug code running inside the JBoss AS 7 + application server. + +skip_maven_build - Maven build step will be skipped + +force_clean_build - Will start the build process by removing all non +essential Maven dependencies. Any current dependencies specified in +your pom.xml file will then be re-downloaded. + +hot_deploy - Will prevent a JBoss container restart during build/deployment. + Newly build archives will be re-deployed automatically by the + JBoss HDScanner component. + +java7 - Will run JBoss AS7 with Java7 if present. If no marker is present then the + baseline Java version will be used (currently Java6) diff --git a/.openshift/markers/java7 b/.openshift/markers/java7 new file mode 100644 index 00000000..e69de29b diff --git a/README.md b/README.md new file mode 100644 index 00000000..410699f4 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +CommaFeed +========= +Google Reader inspired self-hosted RSS reader. + +Deploy on any JavaEE6 container or better yet on OpenShift. \ No newline at end of file diff --git a/deployments/.gitkeep b/deployments/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..4526eb30 --- /dev/null +++ b/pom.xml @@ -0,0 +1,225 @@ + + 4.0.0 + + com.commafeed + commafeed + 0.0.1-SNAPSHOT + war + CommaFeed + + + UTF-8 + + + + + + src/main/resources + + + src/main/java + + **/* + + + **/*.java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.6 + 1.6 + + + + maven-war-plugin + 2.1.1 + + false + + + + org.zeroturnaround + jrebel-maven-plugin + 1.1.3 + + + generate-rebel-xml + process-resources + + generate + + + + + + + + + + org.jboss.spec + jboss-javaee-6.0 + 1.0.0.Final + pom + provided + + + uaihebert.com + EasyCriteria + 2.1.0 + + + + + org.slf4j + slf4j-log4j12 + 1.7.2 + + + log4j + log4j + 1.2.17 + + + + com.google.guava + guava + 14.0.1 + + + commons-beanutils + commons-beanutils + 1.8.3 + + + commons-codec + commons-codec + 1.7 + + + commons-collections + commons-collections + 3.2.1 + + + commons-io + commons-io + 2.4 + + + commons-lang + commons-lang + 2.6 + + + + net.java.dev.rome + rome + 1.0.0 + + + org.apache.httpcomponents + httpclient + 4.2.3 + + + joda-time + joda-time + 2.2 + + + com.googlecode.lambdaj + lambdaj + 2.3.3 + + + + org.apache.wicket + wicket-core + 6.6.0 + + + org.apache.wicket + wicket-auth-roles + 6.6.0 + + + org.apache.wicket + wicket-extensions + 6.6.0 + + + org.apache.wicket + wicket-datetime + 6.6.0 + + + org.odlabs.wiquery + wiquery-jquery-ui + 6.6.0 + + + org.apache.wicket + wicket-cdi + 6.6.0 + + + de.agilecoders.wicket + wicket-bootstrap-core + 0.8.1 + + + de.agilecoders.wicket + wicket-bootstrap-extensions + 0.8.1 + + + de.agilecoders.wicket + wicket-bootstrap-themes + 0.8.1 + + + com.vaynberg.wicket.select2 + wicket-select2 + 2.1 + + + de.agilecoders.wicket.webjars + wicket-webjars + 0.2.0 + + + + + + openshift + + commafeed + + + maven-surefire-plugin + 2.12 + + true + + + + maven-war-plugin + 2.1.1 + + deployments + ROOT + + + + + + + diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/main/java/com/commafeed/backend/StartupBean.java b/src/main/java/com/commafeed/backend/StartupBean.java new file mode 100644 index 00000000..e17ef44b --- /dev/null +++ b/src/main/java/com/commafeed/backend/StartupBean.java @@ -0,0 +1,74 @@ +package com.commafeed.backend; + +import javax.annotation.PostConstruct; +import javax.ejb.Singleton; +import javax.ejb.Startup; +import javax.inject.Inject; + +import com.commafeed.backend.dao.FeedCategoryService; +import com.commafeed.backend.dao.FeedService; +import com.commafeed.backend.dao.FeedSubscriptionService; +import com.commafeed.backend.dao.UserService; +import com.commafeed.backend.security.PasswordEncryptionService; +import com.commafeed.model.Feed; +import com.commafeed.model.FeedCategory; +import com.commafeed.model.FeedSubscription; +import com.commafeed.model.User; + +@Startup +@Singleton +public class StartupBean { + + @Inject + FeedService feedService; + + @Inject + FeedCategoryService feedCategoryService; + + @Inject + FeedSubscriptionService feedSubscriptionService; + + @Inject + UserService userService; + + @Inject + PasswordEncryptionService encryptionService; + + @PostConstruct + private void init() { + + if (userService.getCount() == 0) { + User user = new User(); + byte[] salt = encryptionService.generateSalt(); + user.setName("admin"); + user.setSalt(salt); + user.setPassword(encryptionService.getEncryptedPassword("admin", + salt)); + userService.save(user); + + Feed feed = new Feed("http://feed.dilbert.com/dilbert/daily_strip"); + feedService.save(feed); + + FeedCategory newsCategory = new FeedCategory(); + newsCategory.setName("News"); + newsCategory.setUser(user); + feedCategoryService.save(newsCategory); + + FeedCategory comicsCategory = new FeedCategory(); + comicsCategory.setName("Comics"); + comicsCategory.setUser(user); + comicsCategory.setParent(newsCategory); + feedCategoryService.save(comicsCategory); + + FeedSubscription sub = new FeedSubscription(); + sub.setCategory(comicsCategory); + sub.setFeed(feed); + sub.setTitle("Dilbert - Strips"); + sub.setUser(user); + feedSubscriptionService.save(sub); + + } + + } + +} diff --git a/src/main/java/com/commafeed/backend/dao/FeedCategoryService.java b/src/main/java/com/commafeed/backend/dao/FeedCategoryService.java new file mode 100644 index 00000000..671b6217 --- /dev/null +++ b/src/main/java/com/commafeed/backend/dao/FeedCategoryService.java @@ -0,0 +1,17 @@ +package com.commafeed.backend.dao; + +import java.util.List; + +import javax.ejb.Stateless; + +import com.commafeed.frontend.utils.ModelFactory.MF; +import com.commafeed.model.FeedCategory; +import com.commafeed.model.User; + +@Stateless +public class FeedCategoryService extends GenericDAO { + + public List findAll(User user) { + return findByField(MF.i(MF.p(FeedCategory.class).getUser()), user); + } +} diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryService.java b/src/main/java/com/commafeed/backend/dao/FeedEntryService.java new file mode 100644 index 00000000..cdca7254 --- /dev/null +++ b/src/main/java/com/commafeed/backend/dao/FeedEntryService.java @@ -0,0 +1,31 @@ +package com.commafeed.backend.dao; + +import java.util.Calendar; +import java.util.Collection; + +import javax.ejb.Stateless; +import javax.inject.Inject; + +import com.commafeed.model.Feed; +import com.commafeed.model.FeedEntry; + +@Stateless +public class FeedEntryService extends GenericDAO { + + @Inject + FeedService feedService; + + public void updateEntries(String url, Collection entries) { + Feed feed = feedService.findById(url); + for (FeedEntry entry : entries) { + FeedEntry existing = findById(entry.getGuid()); + if (existing == null) { + entry.setFeed(feed); + save(entry); + } + } + feed.setLastUpdated(Calendar.getInstance().getTime()); + em.merge(feed); + } + +} diff --git a/src/main/java/com/commafeed/backend/dao/FeedService.java b/src/main/java/com/commafeed/backend/dao/FeedService.java new file mode 100644 index 00000000..578189b7 --- /dev/null +++ b/src/main/java/com/commafeed/backend/dao/FeedService.java @@ -0,0 +1,10 @@ +package com.commafeed.backend.dao; + +import javax.ejb.Stateless; + +import com.commafeed.model.Feed; + +@Stateless +public class FeedService extends GenericDAO { + +} diff --git a/src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java b/src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java new file mode 100644 index 00000000..2151ee80 --- /dev/null +++ b/src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java @@ -0,0 +1,18 @@ +package com.commafeed.backend.dao; + +import java.util.List; + +import javax.ejb.Stateless; + +import com.commafeed.frontend.utils.ModelFactory.MF; +import com.commafeed.model.FeedCategory; +import com.commafeed.model.FeedSubscription; +import com.commafeed.model.User; + +@Stateless +public class FeedSubscriptionService extends GenericDAO { + + public List findAll(User user) { + return findByField(MF.i(MF.p(FeedCategory.class).getUser()), user); + } +} diff --git a/src/main/java/com/commafeed/backend/dao/GenericDAO.java b/src/main/java/com/commafeed/backend/dao/GenericDAO.java new file mode 100644 index 00000000..f08fa34e --- /dev/null +++ b/src/main/java/com/commafeed/backend/dao/GenericDAO.java @@ -0,0 +1,89 @@ +package com.commafeed.backend.dao; + +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import com.google.common.reflect.TypeToken; +import com.uaihebert.factory.EasyCriteriaFactory; +import com.uaihebert.model.EasyCriteria; + +public abstract class GenericDAO { + + private TypeToken type = new TypeToken(getClass()) { + }; + + @PersistenceContext + protected EntityManager em; + + protected CriteriaBuilder builder; + + @PostConstruct + public void init() { + builder = em.getCriteriaBuilder(); + } + + public void save(T object) { + em.persist(object); + } + + public void update(T... objects) { + for (Object object : objects) { + em.merge(object); + } + } + + public void delete(T object) { + object = em.merge(object); + em.remove(object); + } + + public void deleteById(Object id) { + Object ref = em.getReference(getType(), id); + em.remove(ref); + } + + public T findById(K id) { + T t = em.find(getType(), id); + return t; + } + + public List findAll() { + return EasyCriteriaFactory.createQueryCriteria(em, getType()) + .getResultList(); + } + + public List findAll(int startIndex, int count) { + EasyCriteria criteria = EasyCriteriaFactory.createQueryCriteria(em, + getType()); + criteria.setMaxResults(count); + criteria.setFirstResult(startIndex); + return criteria.getResultList(); + } + + public long getCount() { + CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaQuery query = builder.createQuery(Long.class); + Root root = query.from(getType()); + query.select(builder.count(root)); + return em.createQuery(query).getSingleResult(); + } + + public List findByField(String field, Object value) { + EasyCriteria criteria = EasyCriteriaFactory.createQueryCriteria(em, + getType()); + criteria.andEquals(field, value); + return criteria.getResultList(); + } + + @SuppressWarnings("unchecked") + protected Class getType() { + return (Class) type.getRawType(); + } + +} diff --git a/src/main/java/com/commafeed/backend/dao/UserService.java b/src/main/java/com/commafeed/backend/dao/UserService.java new file mode 100644 index 00000000..2769f282 --- /dev/null +++ b/src/main/java/com/commafeed/backend/dao/UserService.java @@ -0,0 +1,30 @@ +package com.commafeed.backend.dao; + +import java.util.List; + +import javax.inject.Inject; + +import com.commafeed.backend.security.PasswordEncryptionService; +import com.commafeed.frontend.utils.ModelFactory.MF; +import com.commafeed.model.User; +import com.google.common.collect.Iterables; + +public class UserService extends GenericDAO { + + @Inject + PasswordEncryptionService encryptionService; + + public User login(String name, String password) { + List users = findByField(MF.i(MF.p(User.class).getName()), name); + User user = Iterables.getFirst(users, null); + if (user != null) { + boolean authenticated = encryptionService.authenticate(password, + user.getPassword(), user.getSalt()); + if (authenticated) { + return user; + } + } + + return null; + } +} diff --git a/src/main/java/com/commafeed/backend/feeds/FeedFetcher.java b/src/main/java/com/commafeed/backend/feeds/FeedFetcher.java new file mode 100644 index 00000000..99a2b0e8 --- /dev/null +++ b/src/main/java/com/commafeed/backend/feeds/FeedFetcher.java @@ -0,0 +1,53 @@ +package com.commafeed.backend.feeds; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.ejb.AccessTimeout; +import javax.ejb.AsyncResult; +import javax.ejb.Asynchronous; +import javax.ejb.Lock; +import javax.ejb.LockType; +import javax.ejb.Singleton; +import javax.inject.Inject; + +import org.apache.http.client.HttpClient; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.DefaultHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.commafeed.model.Feed; + +@Singleton +public class FeedFetcher { + + private static Logger log = LoggerFactory.getLogger(FeedFetcher.class); + + @Inject + FeedParser parser; + + @Asynchronous + @Lock(LockType.READ) + @AccessTimeout(value = 15, unit = TimeUnit.SECONDS) + public Future fetch(String feedUrl) { + log.debug("Fetching feed {}", feedUrl); + Feed feed = null; + + HttpClient httpclient = new DefaultHttpClient(); + try { + HttpGet httpget = new HttpGet(feedUrl); + ResponseHandler responseHandler = new BasicResponseHandler(); + String responseBody = httpclient.execute(httpget, responseHandler); + feed = parser.parse(feedUrl, responseBody); + } catch (Exception e) { + e.printStackTrace(); + } finally { + httpclient.getConnectionManager().shutdown(); + } + return new AsyncResult(feed); + } + +} diff --git a/src/main/java/com/commafeed/backend/feeds/FeedParser.java b/src/main/java/com/commafeed/backend/feeds/FeedParser.java new file mode 100644 index 00000000..ea78a507 --- /dev/null +++ b/src/main/java/com/commafeed/backend/feeds/FeedParser.java @@ -0,0 +1,49 @@ +package com.commafeed.backend.feeds; + +import java.io.StringReader; +import java.util.Calendar; +import java.util.List; + +import javax.ejb.Stateless; + +import com.commafeed.model.Feed; +import com.commafeed.model.FeedEntry; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.SyndFeedInput; + +@Stateless +public class FeedParser { + + @SuppressWarnings("unchecked") + public Feed parse(String feedUrl, String xml) throws FeedException { + + Feed feed = new Feed(); + feed.setUrl(feedUrl); + feed.setLastUpdated(Calendar.getInstance().getTime()); + + try { + SyndFeed rss = new SyndFeedInput().build(new StringReader(xml)); + + List items = rss.getEntries(); + for (SyndEntry item : items) { + FeedEntry entry = new FeedEntry(); + entry.setGuid(item.getUri()); + entry.setTitle(item.getTitle()); + entry.setContent(item.getDescription() == null ? null : item + .getDescription().getValue()); + entry.setUrl(item.getLink()); + entry.setUpdated(item.getUpdatedDate() != null ? item + .getUpdatedDate() : item.getPublishedDate()); + + feed.getEntries().add(entry); + } + } catch (Exception e) { + throw new FeedException("Could not parse feed : " + e.getMessage(), + e); + } + return feed; + } + +} diff --git a/src/main/java/com/commafeed/backend/feeds/FeedTimer.java b/src/main/java/com/commafeed/backend/feeds/FeedTimer.java new file mode 100644 index 00000000..222b7049 --- /dev/null +++ b/src/main/java/com/commafeed/backend/feeds/FeedTimer.java @@ -0,0 +1,48 @@ +package com.commafeed.backend.feeds; + +import java.util.List; +import java.util.concurrent.Future; + +import javax.ejb.Schedule; +import javax.ejb.Singleton; +import javax.inject.Inject; + +import com.commafeed.backend.dao.FeedEntryService; +import com.commafeed.backend.dao.FeedService; +import com.commafeed.model.Feed; +import com.google.common.collect.Lists; + +@Singleton +public class FeedTimer { + + @Inject + FeedService feedService; + + @Inject + FeedEntryService feedEntryService; + + @Inject + FeedFetcher fetcher; + + @Schedule(hour = "*", minute = "*", persistent = false) + private void timeout() { + List feeds = feedService.findAll(); + + List> futures = Lists.newArrayList(); + for (Feed feed : feeds) { + Future future = fetcher.fetch(feed.getUrl()); + futures.add(future); + } + + for (Future future : futures) { + try { + Feed feed = future.get(); + feedEntryService + .updateEntries(feed.getUrl(), feed.getEntries()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/main/java/com/commafeed/backend/security/PasswordEncryptionService.java b/src/main/java/com/commafeed/backend/security/PasswordEncryptionService.java new file mode 100644 index 00000000..dcde2c11 --- /dev/null +++ b/src/main/java/com/commafeed/backend/security/PasswordEncryptionService.java @@ -0,0 +1,89 @@ +package com.commafeed.backend.security; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.KeySpec; +import java.util.Arrays; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.ejb.Singleton; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.commafeed.backend.dao.UserService; + +// http://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html +@Singleton +public class PasswordEncryptionService { + + private static final Logger log = LoggerFactory + .getLogger(UserService.class); + + public boolean authenticate(String attemptedPassword, + byte[] encryptedPassword, byte[] salt) { + // Encrypt the clear-text password using the same salt that was used to + // encrypt the original password + byte[] encryptedAttemptedPassword = null; + try { + encryptedAttemptedPassword = getEncryptedPassword( + attemptedPassword, salt); + } catch (Exception e) { + // should never happen + log.error(e.getMessage(), e); + } + + // Authentication succeeds if encrypted password that the user entered + // is equal to the stored hash + return Arrays.equals(encryptedPassword, encryptedAttemptedPassword); + } + + public byte[] getEncryptedPassword(String password, byte[] salt) { + // PBKDF2 with SHA-1 as the hashing algorithm. Note that the NIST + // specifically names SHA-1 as an acceptable hashing algorithm for + // PBKDF2 + String algorithm = "PBKDF2WithHmacSHA1"; + // SHA-1 generates 160 bit hashes, so that's what makes sense here + int derivedKeyLength = 160; + // Pick an iteration count that works for you. The NIST recommends at + // least 1,000 iterations: + // http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf + // iOS 4.x reportedly uses 10,000: + // http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/ + int iterations = 20000; + + KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, + derivedKeyLength); + + SecretKey key = null; + try { + SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm); + key = f.generateSecret(spec); + } catch (Exception e) { + // should never happen + log.error(e.getMessage(), e); + } + + return key.getEncoded(); + } + + public byte[] generateSalt() { + // VERY important to use SecureRandom instead of just Random + SecureRandom random = null; + try { + random = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + // should never happen + log.error(e.getMessage(), e); + } + + // Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5 + byte[] salt = new byte[8]; + random.nextBytes(salt); + + return salt; + } + +} diff --git a/src/main/java/com/commafeed/frontend/CommaFeedApplication.java b/src/main/java/com/commafeed/frontend/CommaFeedApplication.java new file mode 100644 index 00000000..e2c17021 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/CommaFeedApplication.java @@ -0,0 +1,116 @@ +package com.commafeed.frontend; + +import javax.enterprise.inject.spi.BeanManager; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.apache.wicket.Application; +import org.apache.wicket.Page; +import org.apache.wicket.Session; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession; +import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication; +import org.apache.wicket.authroles.authorization.strategies.role.IRoleCheckingStrategy; +import org.apache.wicket.authroles.authorization.strategies.role.Roles; +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AnnotationsRoleAuthorizationStrategy; +import org.apache.wicket.cdi.CdiConfiguration; +import org.apache.wicket.cdi.ConversationPropagation; +import org.apache.wicket.core.request.handler.PageProvider; +import org.apache.wicket.core.request.handler.RenderPageRequestHandler; +import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.request.IRequestHandler; +import org.apache.wicket.request.Request; +import org.apache.wicket.request.Response; +import org.apache.wicket.request.cycle.AbstractRequestCycleListener; +import org.apache.wicket.request.cycle.RequestCycle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.commafeed.frontend.components.auth.LoginPage; +import com.commafeed.frontend.pages.feed.FeedViewPage; +import com.commafeed.frontend.utils.exception.DisplayExceptionPage; + +import de.agilecoders.wicket.Bootstrap; +import de.agilecoders.wicket.settings.BootstrapSettings; +import de.agilecoders.wicket.webjars.util.WicketWebjars; + +public class CommaFeedApplication extends AuthenticatedWebApplication { + + private Logger log = LoggerFactory.getLogger(CommaFeedApplication.class); + + @Override + protected void init() { + super.init(); + + mountPage("login", LoginPage.class); + mountPage("feeds", FeedViewPage.class); + + setupInjection(); + + getMarkupSettings().setStripWicketTags(true); + getMarkupSettings().setCompressWhitespace(true); + getMarkupSettings().setDefaultMarkupEncoding("UTF-8"); + + getSecuritySettings().setAuthorizationStrategy( + new AnnotationsRoleAuthorizationStrategy( + new IRoleCheckingStrategy() { + @Override + public boolean hasAnyRole(Roles roles) { + return CommaFeedSession.get().getRoles() + .hasAnyRole(roles); + } + })); + + getRequestCycleListeners().add(new AbstractRequestCycleListener() { + @Override + public IRequestHandler onException(RequestCycle cycle, Exception ex) { + AjaxRequestTarget target = cycle.find(AjaxRequestTarget.class); + // redirect to the error page if ajax request, render error on + // current page otherwise + RedirectPolicy policy = target == null ? RedirectPolicy.NEVER_REDIRECT + : RedirectPolicy.AUTO_REDIRECT; + return new RenderPageRequestHandler(new PageProvider( + new DisplayExceptionPage(ex)), policy); + } + }); + mountPage("/error", DisplayExceptionPage.class); + + BootstrapSettings settings = new BootstrapSettings(); + Bootstrap.install(Application.get(), settings); + + WicketWebjars.install(this); + } + + @Override + public Class getHomePage() { + return FeedViewPage.class; + } + + protected void setupInjection() { + try { + BeanManager beanManager = (BeanManager) new InitialContext() + .lookup("java:comp/BeanManager"); + new CdiConfiguration(beanManager).setPropagation( + ConversationPropagation.NONE).configure(this); + } catch (NamingException e) { + log.warn("Could not locate bean manager. CDI is disabled."); + } + } + + @Override + public Session newSession(Request request, Response response) { + return new CommaFeedSession(request); + } + + @Override + protected Class getSignInPageClass() { + return LoginPage.class; + } + + @Override + protected Class getWebSessionClass() { + return CommaFeedSession.class; + } + +} diff --git a/src/main/java/com/commafeed/frontend/CommaFeedSession.java b/src/main/java/com/commafeed/frontend/CommaFeedSession.java new file mode 100644 index 00000000..c27f5d47 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/CommaFeedSession.java @@ -0,0 +1,51 @@ +package com.commafeed.frontend; + +import javax.inject.Inject; + +import org.apache.wicket.Session; +import org.apache.wicket.authroles.authentication.AuthenticatedWebSession; +import org.apache.wicket.authroles.authorization.strategies.role.Roles; +import org.apache.wicket.request.Request; + +import com.commafeed.backend.dao.UserService; +import com.commafeed.frontend.components.auth.Role; +import com.commafeed.model.User; + +public class CommaFeedSession extends AuthenticatedWebSession { + + @Inject + UserService userService; + + private User user; + + public CommaFeedSession(Request request) { + super(request); + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public static CommaFeedSession get() { + return (CommaFeedSession) Session.get(); + } + + @Override + public Roles getRoles() { + // TODO change this + return isSignedIn() ? new Roles(new String[] { Role.USER, Role.ADMIN }) + : new Roles(); + } + + @Override + public boolean authenticate(String userName, String password) { + User user = userService.login(userName, password); + setUser(user); + return user != null; + } + +} diff --git a/src/main/java/com/commafeed/frontend/components/CssTreeView.html b/src/main/java/com/commafeed/frontend/components/CssTreeView.html new file mode 100644 index 00000000..7fe5b39c --- /dev/null +++ b/src/main/java/com/commafeed/frontend/components/CssTreeView.html @@ -0,0 +1,24 @@ + + + + +
+
    +
  • +
+
+ + + +
    +
  • +
+
+ + + +
+ + diff --git a/src/main/java/com/commafeed/frontend/components/CssTreeView.java b/src/main/java/com/commafeed/frontend/components/CssTreeView.java new file mode 100644 index 00000000..7ab99a92 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/components/CssTreeView.java @@ -0,0 +1,82 @@ +package com.commafeed.frontend.components; + +import java.util.Collection; + +import org.apache.wicket.AttributeModifier; +import org.apache.wicket.Component; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.CheckBox; +import org.apache.wicket.markup.html.form.FormComponentLabel; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.wicket.model.IDetachable; +import org.apache.wicket.model.IModel; + +import com.commafeed.frontend.references.csstree.CssTreeViewReference; + +public abstract class CssTreeView extends Panel { + + private ITreeProvider provider; + + public CssTreeView(String id, final ITreeProvider provider) { + super(id); + setRenderBodyOnly(true); + this.provider = provider; + + RepeatingView view = new RepeatingView("tree"); + addNode(null, view); + add(view); + } + + private void addNode(T node, RepeatingView view) { + for (T child : provider.getChildren(node)) { + Fragment fragment = new Fragment(view.newChildId(), "node", + CssTreeView.this); + CheckBox checkBox = new CheckBox("checkbox"); + checkBox.add(new AttributeModifier("checked", "checked")); + fragment.add(checkBox); + fragment.add(new FormComponentLabel("label", checkBox) + .add(new Label("content", provider.getChildLabel(child)) + .setRenderBodyOnly(true))); + + RepeatingView viewChild = new RepeatingView("node"); + addNode(child, viewChild); + fragment.add(viewChild); + view.add(fragment); + } + for (V leaf : provider.getLeaves(node)) { + Fragment fragment = new Fragment(view.newChildId(), "leaf", + CssTreeView.this); + fragment.add(newLink("link", provider.model(leaf))); + view.add(fragment); + } + } + + @Override + protected void onDetach() { + super.onDetach(); + provider.detach(); + } + + protected abstract Component newLink(String markupId, IModel model); + + @Override + public void renderHead(IHeaderResponse response) { + super.renderHead(response); + CssTreeViewReference.render(response); + } + + public static interface ITreeProvider extends IDetachable { + + Collection getChildren(T node); + + IModel getChildLabel(T node); + + Collection getLeaves(T node); + + IModel model(V object); + } + +} diff --git a/src/main/java/com/commafeed/frontend/components/auth/LoginPage.html b/src/main/java/com/commafeed/frontend/components/auth/LoginPage.html new file mode 100644 index 00000000..10e89550 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/components/auth/LoginPage.html @@ -0,0 +1,16 @@ + + + + + + +
+ +
+ +
+
+ + diff --git a/src/main/java/com/commafeed/frontend/components/auth/LoginPage.java b/src/main/java/com/commafeed/frontend/components/auth/LoginPage.java new file mode 100644 index 00000000..0670d275 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/components/auth/LoginPage.java @@ -0,0 +1,21 @@ +package com.commafeed.frontend.components.auth; + +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.html.WebPage; + +import de.agilecoders.wicket.Bootstrap; + +@SuppressWarnings("serial") +public class LoginPage extends WebPage { + + public LoginPage() { + add(new LoginPanel("login")); + } + + @Override + public void renderHead(IHeaderResponse response) { + super.renderHead(response); + Bootstrap.renderHead(response); + } + +} diff --git a/src/main/java/com/commafeed/frontend/components/auth/LoginPanel.html b/src/main/java/com/commafeed/frontend/components/auth/LoginPanel.html new file mode 100644 index 00000000..02601053 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/components/auth/LoginPanel.html @@ -0,0 +1,28 @@ + + + + + +
+
+ +
+ +
+
+
+ +
+ +
+
+

+ Remember me +

+
+ +
+
+
+ + diff --git a/src/main/java/com/commafeed/frontend/components/auth/LoginPanel.java b/src/main/java/com/commafeed/frontend/components/auth/LoginPanel.java new file mode 100644 index 00000000..f01c2abb --- /dev/null +++ b/src/main/java/com/commafeed/frontend/components/auth/LoginPanel.java @@ -0,0 +1,12 @@ +package com.commafeed.frontend.components.auth; + +import org.apache.wicket.authroles.authentication.panel.SignInPanel; + +@SuppressWarnings("serial") +public class LoginPanel extends SignInPanel { + + public LoginPanel(String id) { + super(id); + } + +} diff --git a/src/main/java/com/commafeed/frontend/components/auth/Role.java b/src/main/java/com/commafeed/frontend/components/auth/Role.java new file mode 100644 index 00000000..cda8d20b --- /dev/null +++ b/src/main/java/com/commafeed/frontend/components/auth/Role.java @@ -0,0 +1,6 @@ +package com.commafeed.frontend.components.auth; + +public class Role { + public static final String USER = "user"; + public static final String ADMIN = "admin"; +} diff --git a/src/main/java/com/commafeed/frontend/pages/BasePage.html b/src/main/java/com/commafeed/frontend/pages/BasePage.html new file mode 100644 index 00000000..113ad7a9 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/pages/BasePage.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/main/java/com/commafeed/frontend/pages/BasePage.java b/src/main/java/com/commafeed/frontend/pages/BasePage.java new file mode 100644 index 00000000..2648f8f5 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/pages/BasePage.java @@ -0,0 +1,19 @@ +package com.commafeed.frontend.pages; + +import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.html.WebPage; + +import com.commafeed.frontend.components.auth.Role; + +import de.agilecoders.wicket.Bootstrap; + +@AuthorizeInstantiation(Role.USER) +public abstract class BasePage extends WebPage { + + @Override + public void renderHead(IHeaderResponse response) { + super.renderHead(response); + Bootstrap.renderHead(response); + } +} diff --git a/src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.html b/src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.html new file mode 100644 index 00000000..ba51c8af --- /dev/null +++ b/src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.html @@ -0,0 +1,17 @@ + + + + +
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.java b/src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.java new file mode 100644 index 00000000..907c03a1 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/pages/feed/FeedViewPage.java @@ -0,0 +1,115 @@ +package com.commafeed.frontend.pages.feed; + +import java.util.Collection; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; + +import com.commafeed.backend.dao.FeedCategoryService; +import com.commafeed.backend.dao.FeedSubscriptionService; +import com.commafeed.frontend.CommaFeedSession; +import com.commafeed.frontend.components.CssTreeView; +import com.commafeed.frontend.components.CssTreeView.ITreeProvider; +import com.commafeed.frontend.pages.BasePage; +import com.commafeed.frontend.utils.ModelFactory.MF; +import com.commafeed.frontend.utils.stateless.StatelessAjaxLink; +import com.commafeed.model.FeedCategory; +import com.commafeed.model.FeedSubscription; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; + +public class FeedViewPage extends BasePage { + + @Inject + FeedSubscriptionService feedSubscriptionService; + + @Inject + FeedCategoryService feedCategoryService; + + public FeedViewPage() { + add(newTree("tree")); + add(new Label("entries", Model.of(""))); + } + + private Component newTree(String markupId) { + ITreeProvider provider = new ITreeProvider() { + + private List cats; + private List subsWithoutCategory; + + private void init() { + if (cats == null) { + cats = feedCategoryService.findAll(CommaFeedSession.get() + .getUser()); + } + if (subsWithoutCategory == null) { + subsWithoutCategory = feedSubscriptionService.findByField( + MF.i(MF.p(FeedSubscription.class).getCategory()), + null); + } + + } + + @Override + public Collection getChildren(final FeedCategory node) { + init(); + return Lists.newArrayList(Collections2.filter(cats, + new Predicate() { + @Override + public boolean apply(FeedCategory cat) { + return (node == null && cat.getParent() == null) + || (cat.getParent() != null + && node != null && cat + .getParent().getId() == node + .getId()); + } + })); + } + + @Override + public Collection getLeaves(FeedCategory node) { + init(); + if (node == null) { + return subsWithoutCategory; + } + return node.getSubscriptions(); + } + + @Override + public IModel getChildLabel(FeedCategory node) { + return Model.of(node.getName()); + } + + @Override + public IModel model(FeedSubscription object) { + return Model.of(object); + } + + @Override + public void detach() { + cats = null; + } + + }; + return new CssTreeView(markupId, + provider) { + @Override + protected Component newLink(String markupId, + final IModel model) { + return new StatelessAjaxLink(markupId) { + @Override + public void onClick(AjaxRequestTarget target) { + System.out.println(model.getObject().getId()); + } + }.setBody(Model.of(model.getObject().getTitle())); + } + }; + } +} diff --git a/src/main/java/com/commafeed/frontend/pages/home/HomePage.java b/src/main/java/com/commafeed/frontend/pages/home/HomePage.java new file mode 100644 index 00000000..01f4a3ac --- /dev/null +++ b/src/main/java/com/commafeed/frontend/pages/home/HomePage.java @@ -0,0 +1,7 @@ +package com.commafeed.frontend.pages.home; + +import com.commafeed.frontend.pages.BasePage; + +public class HomePage extends BasePage { + +} diff --git a/src/main/java/com/commafeed/frontend/references/csstree/CssTreeViewReference.java b/src/main/java/com/commafeed/frontend/references/csstree/CssTreeViewReference.java new file mode 100644 index 00000000..1d1089b3 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/references/csstree/CssTreeViewReference.java @@ -0,0 +1,25 @@ +package com.commafeed.frontend.references.csstree; + +import org.apache.wicket.markup.head.CssHeaderItem; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.request.resource.CssResourceReference; + +/** + * http://experiments.wemakesites.net/css3-treeview.html + * + */ +public class CssTreeViewReference extends CssResourceReference { + private static CssTreeViewReference instance = new CssTreeViewReference(); + + public CssTreeViewReference() { + super(CssTreeViewReference.class, "css3-treeview.css"); + } + + public static void render(IHeaderResponse response) { + response.render(CssHeaderItem.forReference(instance)); + } + + public static CssTreeViewReference get() { + return instance; + } +} diff --git a/src/main/java/com/commafeed/frontend/references/csstree/css3-treeview.css b/src/main/java/com/commafeed/frontend/references/csstree/css3-treeview.css new file mode 100644 index 00000000..17fbaa2c --- /dev/null +++ b/src/main/java/com/commafeed/frontend/references/csstree/css3-treeview.css @@ -0,0 +1,115 @@ +.css-treeview ul, + .css-treeview li + { + padding: 0; + margin: 0; + list-style: none; + } + + .css-treeview input + { + position: absolute; + opacity: 0; + } + + .css-treeview + { + font: normal 11px "Segoe UI", Arial, Sans-serif; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + } + + .css-treeview a + { + color: #00f; + text-decoration: none; + } + + .css-treeview a:hover + { + text-decoration: underline; + } + + .css-treeview input + label + ul + { + margin: 0 0 0 22px; + } + + .css-treeview input ~ ul + { + display: none; + } + + .css-treeview label, + .css-treeview label::before + { + cursor: pointer; + } + + .css-treeview input:disabled + label + { + cursor: default; + opacity: .6; + } + + .css-treeview input:checked:not(:disabled) ~ ul + { + display: block; + } + + .css-treeview label, + .css-treeview label::before + { + background: url("icons.png") no-repeat; + } + + .css-treeview label, + .css-treeview a, + .css-treeview label::before + { + display: inline-block; + height: 16px; + line-height: 16px;, + vertical-align: middle; + } + + .css-treeview label + { + background-position: 18px 0; + } + + .css-treeview label::before + { + content: ""; + width: 16px; + margin: 0 22px 0 0; + vertical-align: middle; + background-position: 0 -32px; + } + + .css-treeview input:checked + label::before + { + background-position: 0 -16px; + } + + /* webkit adjacent element selector bugfix */ + @media screen and (-webkit-min-device-pixel-ratio:0) + { + .css-treeview + { + -webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s; + } + + @-webkit-keyframes webkit-adjacent-element-selector-bugfix + { + from + { + padding: 0; + } + to + { + padding: 0; + } + } + } diff --git a/src/main/java/com/commafeed/frontend/references/csstree/icons.png b/src/main/java/com/commafeed/frontend/references/csstree/icons.png new file mode 100644 index 0000000000000000000000000000000000000000..924cd5b317d821cc00d70d5594d570de0c2801d7 GIT binary patch literal 762 zcmeAS@N?(olHy`uVBq!ia0vp^0zkZggAGWsTD}nhQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?|dGx;TbZ+PPxnVi+b$FOpg1@al-~pWVC9^iO}${0FMnO#eU|jaoQZq+CO=P4$V#(g{h-mHuP?8kSZ*nKnZaR( zfRInT#yi#_$IMr zXKGHu!#7+Trr(k{B=KbFD|>rx7KvZK72b#Z`} extends + LoadableDetachableModel>> { + + private static final long serialVersionUID = 1L; + + private IModel> model; + + public MapToListModel(Map map) { + this.model = Model.ofMap(map); + } + + public MapToListModel(IModel> model) { + this.model = model; + } + + @Override + protected List> load() { + Map map = model.getObject(); + return map == null ? null : Lists.newArrayList(map.entrySet()); + } + + @Override + public void detach() { + super.detach(); + model.detach(); + } + +} diff --git a/src/main/java/com/commafeed/frontend/utils/ModelFactory.java b/src/main/java/com/commafeed/frontend/utils/ModelFactory.java new file mode 100644 index 00000000..07a12612 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/ModelFactory.java @@ -0,0 +1,58 @@ +package com.commafeed.frontend.utils; + +import org.apache.wicket.model.PropertyModel; + +import ch.lambdaj.Lambda; +import ch.lambdaj.function.argument.Argument; +import ch.lambdaj.function.argument.ArgumentsFactory; + +/** + * Utility class to generate PropertyModels in a type-safe way + * + */ +public class ModelFactory { + + public static String invokedProperty(T proxiedValue) { + Argument a = ArgumentsFactory.actualArgument(proxiedValue); + return a.getInkvokedPropertyName(); + } + + public static PropertyModel model(Object value, T proxiedValue) { + String invokedPN = invokedProperty(proxiedValue); + PropertyModel m = new PropertyModel(value, invokedPN); + return m; + } + + @SuppressWarnings("unchecked") + public static T proxy(T t) { + Object object = Lambda.on(t.getClass()); + return (T) object; + } + + public static T proxy(Class clazz) { + return Lambda.on(clazz); + } + + /** + * shortcuts to ModelFactory + * + */ + public static class MF { + + public static String i(T proxiedValue) { + return ModelFactory.invokedProperty(proxiedValue); + } + + public static PropertyModel m(Object value, T proxiedValue) { + return ModelFactory.model(value, proxiedValue); + } + + public static T p(T t) { + return ModelFactory.proxy(t); + } + + public static T p(Class clazz) { + return ModelFactory.proxy(clazz); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/commafeed/frontend/utils/WicketUtils.java b/src/main/java/com/commafeed/frontend/utils/WicketUtils.java new file mode 100644 index 00000000..c76486c4 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/WicketUtils.java @@ -0,0 +1,135 @@ +package com.commafeed.frontend.utils; + +import java.security.Principal; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.wicket.ajax.WicketEventJQueryResourceReference; +import org.apache.wicket.markup.head.CssHeaderItem; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.head.JavaScriptHeaderItem; +import org.apache.wicket.markup.head.OnDomReadyHeaderItem; +import org.apache.wicket.protocol.http.servlet.ServletWebRequest; +import org.apache.wicket.request.cycle.RequestCycle; +import org.apache.wicket.request.http.WebResponse; +import org.apache.wicket.request.resource.CssResourceReference; +import org.apache.wicket.request.resource.JavaScriptResourceReference; +import org.apache.wicket.util.io.IOUtils; +import org.apache.wicket.util.template.PackageTextTemplate; + +import de.agilecoders.wicket.webjars.request.resource.WebjarsCssResourceReference; +import de.agilecoders.wicket.webjars.request.resource.WebjarsJavaScriptResourceReference; + +public class WicketUtils { + + public static void loadJQuery(IHeaderResponse response) { + response.render(JavaScriptHeaderItem + .forReference(WicketEventJQueryResourceReference.get())); + } + + public static JavaScriptHeaderItem buildJavaScriptHeaderItem(Class klass) { + return JavaScriptHeaderItem + .forReference(new JavaScriptResourceReference(klass, klass + .getSimpleName() + ".js")); + } + + public static JavaScriptHeaderItem buildJavaScriptWebJarHeaderItem( + String name) { + return JavaScriptHeaderItem + .forReference(new WebjarsJavaScriptResourceReference(name)); + } + + public static void loadJS(IHeaderResponse response, Class klass) { + response.render(buildJavaScriptHeaderItem(klass)); + } + + public static void loadJS(IHeaderResponse response, Class klass, + Map variables) { + OnDomReadyHeaderItem result = null; + PackageTextTemplate template = null; + try { + template = new PackageTextTemplate(klass, klass.getSimpleName() + + ".js"); + String script = template.asString(variables); + result = OnDomReadyHeaderItem.forScript(script); + } finally { + IOUtils.closeQuietly(template); + } + response.render(result); + } + + public static void loadWebJarJS(IHeaderResponse response, String name) { + response.render(buildJavaScriptWebJarHeaderItem(name)); + } + + public static CssHeaderItem buildCssHeaderItem(Class klass) { + return CssHeaderItem.forReference(new CssResourceReference(klass, klass + .getSimpleName() + ".css")); + } + + public static CssHeaderItem buildCssWebJarHeaderItem(String name) { + return CssHeaderItem + .forReference(new WebjarsCssResourceReference(name)); + } + + public static void loadCSS(IHeaderResponse response, Class klass) { + response.render(buildCssHeaderItem(klass)); + } + + public static void loadCSS(IHeaderResponse response, Class klass, + Map variables) { + CssHeaderItem result = null; + PackageTextTemplate template = null; + try { + template = new PackageTextTemplate(klass, klass.getSimpleName() + + ".js"); + String css = template.asString(variables); + result = CssHeaderItem.forCSS(css, null); + } finally { + IOUtils.closeQuietly(template); + } + response.render(result); + } + + public static void loadWebJarCSS(IHeaderResponse response, String name) { + response.render(buildCssWebJarHeaderItem(name)); + } + + public static HttpServletRequest getHttpServletRequest() { + ServletWebRequest servletWebRequest = (ServletWebRequest) RequestCycle + .get().getRequest(); + return servletWebRequest.getContainerRequest(); + } + + public static HttpServletResponse getHttpServletResponse() { + WebResponse webResponse = (WebResponse) RequestCycle.get() + .getResponse(); + return (HttpServletResponse) webResponse.getContainerResponse(); + } + + public static Principal getPrincipal() { + return getHttpServletRequest().getUserPrincipal(); + } + + public static String getPrincipalName() { + Principal principal = getPrincipal(); + return principal == null ? null : principal.toString(); + } + + public static boolean isUserInRole(String role) { + return getHttpServletRequest().isUserInRole(role); + } + + public static boolean isUserInRoles(String... roles) { + boolean inRoles = true; + for (String role : roles) { + if (!isUserInRole(role)) { + inRoles = false; + break; + } + } + return inRoles; + } +} diff --git a/src/main/java/com/commafeed/frontend/utils/exception/DisplayException.java b/src/main/java/com/commafeed/frontend/utils/exception/DisplayException.java new file mode 100644 index 00000000..1c3aa481 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/exception/DisplayException.java @@ -0,0 +1,23 @@ +package com.commafeed.frontend.utils.exception; + +public class DisplayException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private DisplayException() { + + } + + public DisplayException(String message) { + super(message, new DisplayException()); + } + + public DisplayException(Throwable t) { + super(t.getMessage(), t); + } + + public DisplayException(String message, Throwable t) { + super(message, t); + } + +} diff --git a/src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.html b/src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.html new file mode 100644 index 00000000..2e00e432 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.html @@ -0,0 +1,31 @@ + + + + +Error + + + +
+ + +
+
    +
  • + +
  • +
+
+ + Go back to the previous page or to the home page. + +
+

+		
+
+ + diff --git a/src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.java b/src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.java new file mode 100644 index 00000000..35e9df33 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/exception/DisplayExceptionPage.java @@ -0,0 +1,40 @@ +package com.commafeed.frontend.utils.exception; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; + +import com.commafeed.frontend.pages.BasePage; + +public class DisplayExceptionPage extends BasePage { + + private static final long serialVersionUID = 1L; + + public DisplayExceptionPage(Throwable t) { + Throwable de = findDisplayException(t); + if (de != null) { + t = de; + } + + add(new Label("message", t.getMessage())); + + add(new BookmarkablePageLink("homepage", getApplication() + .getHomePage())); + + StringWriter stringWriter = new StringWriter(); + t.printStackTrace(new PrintWriter(stringWriter)); + t.printStackTrace(); + add(new Label("stacktrace", stringWriter.toString())); + + } + + private Throwable findDisplayException(Throwable t) { + while (t != null && !(t instanceof DisplayException)) { + t = t.getCause(); + } + return t; + } + +} diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxButton.java b/src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxButton.java new file mode 100644 index 00000000..e210f046 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxButton.java @@ -0,0 +1,93 @@ +package com.commafeed.frontend.utils.stateless; + +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; +import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +import de.agilecoders.wicket.markup.html.bootstrap.button.BootstrapAjaxButton; +import de.agilecoders.wicket.markup.html.bootstrap.button.Buttons; + +public abstract class BootstrapStatelessAjaxButton extends BootstrapAjaxButton { + + private static final long serialVersionUID = 1L; + + private PageParameters parameters; + + public BootstrapStatelessAjaxButton(final String componentId, + final Buttons.Type buttonType) { + super(componentId, buttonType); + } + + public BootstrapStatelessAjaxButton(final String componentId, + final IModel model, final Buttons.Type buttonType) { + super(componentId, model, buttonType); + } + + public BootstrapStatelessAjaxButton(final String componentId, + final IModel model, final Buttons.Type buttonType, + PageParameters parameters) { + super(componentId, model, buttonType); + this.parameters = parameters; + } + + public BootstrapStatelessAjaxButton(String id, Form form, + Buttons.Type buttonType) { + super(id, form, buttonType); + } + + public BootstrapStatelessAjaxButton(String id, IModel model, + Form form, Buttons.Type buttonType) { + super(id, model, form, buttonType); + + } + + public BootstrapStatelessAjaxButton(String id, IModel model, + Form form, Buttons.Type buttonType, PageParameters parameters) { + super(id, model, form, buttonType); + this.parameters = parameters; + } + + @Override + protected AjaxFormSubmitBehavior newAjaxFormSubmitBehavior(String event) { + return new StatelessAjaxFormSubmitBehavior(getForm(), event) { + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit(AjaxRequestTarget target) { + BootstrapStatelessAjaxButton.this.onSubmit(target, + BootstrapStatelessAjaxButton.this.getForm()); + } + + @Override + protected void onAfterSubmit(AjaxRequestTarget target) { + BootstrapStatelessAjaxButton.this.onAfterSubmit(target, + BootstrapStatelessAjaxButton.this.getForm()); + } + + @Override + protected void onError(AjaxRequestTarget target) { + BootstrapStatelessAjaxButton.this.onError(target, + BootstrapStatelessAjaxButton.this.getForm()); + } + + @Override + protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { + super.updateAjaxAttributes(attributes); + BootstrapStatelessAjaxButton.this.updateAjaxAttributes(attributes); + } + + @Override + public boolean getDefaultProcessing() { + return BootstrapStatelessAjaxButton.this.getDefaultFormProcessing(); + } + + @Override + protected PageParameters getPageParameters() { + return parameters; + } + }; + } +} diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxLink.java b/src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxLink.java new file mode 100644 index 00000000..ccce5b2d --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/BootstrapStatelessAjaxLink.java @@ -0,0 +1,55 @@ +package com.commafeed.frontend.utils.stateless; + +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +import de.agilecoders.wicket.markup.html.bootstrap.button.BootstrapAjaxLink; +import de.agilecoders.wicket.markup.html.bootstrap.button.Buttons; + +public abstract class BootstrapStatelessAjaxLink extends BootstrapAjaxLink { + + private static final long serialVersionUID = 1L; + + private PageParameters parameters; + + public BootstrapStatelessAjaxLink(final String id, final Buttons.Type buttonType) { + super(id, buttonType); + } + + public BootstrapStatelessAjaxLink(String id, IModel model, + Buttons.Type buttonType) { + super(id, model, buttonType); + } + + public BootstrapStatelessAjaxLink(String id, IModel model, + Buttons.Type buttonType, PageParameters parameters) { + super(id, model, buttonType); + this.parameters = parameters; + } + + @Override + protected AjaxEventBehavior newAjaxEventBehavior(String event) { + return new StatelessAjaxEventBehavior(event) { + private static final long serialVersionUID = 1L; + + @Override + protected void onEvent(AjaxRequestTarget target) { + BootstrapStatelessAjaxLink.this.onClick(target); + } + + @Override + protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { + super.updateAjaxAttributes(attributes); + BootstrapStatelessAjaxLink.this.updateAjaxAttributes(attributes); + } + + @Override + protected PageParameters getPageParameters() { + return parameters; + } + }; + } +} diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxEventBehavior.java b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxEventBehavior.java new file mode 100644 index 00000000..07af61ff --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxEventBehavior.java @@ -0,0 +1,36 @@ +package com.commafeed.frontend.utils.stateless; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.request.Url; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +public abstract class StatelessAjaxEventBehavior extends AjaxEventBehavior { + private static final long serialVersionUID = 1L; + + public StatelessAjaxEventBehavior(final String event) { + super(event); + } + + @Override + public CharSequence getCallbackUrl() { + final Url url = Url.parse(super.getCallbackUrl().toString()); + final PageParameters params = getPageParameters(); + return StatelessEncoder.mergeParameters(url, params).toString(); + } + + @Override + public boolean getStatelessHint(final Component component) { + return true; + } + + /** + * Override this to pass the context of the current page to the behavior, + * allowing it to recreate the context for the ajax request. + * + */ + protected PageParameters getPageParameters() { + return null; + } + +} \ No newline at end of file diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormComponentUpdatingBehavior.java b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormComponentUpdatingBehavior.java new file mode 100644 index 00000000..a14eaa9e --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormComponentUpdatingBehavior.java @@ -0,0 +1,37 @@ +package com.commafeed.frontend.utils.stateless; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.request.Url; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +public abstract class StatelessAjaxFormComponentUpdatingBehavior extends + AjaxFormComponentUpdatingBehavior { + + private static final long serialVersionUID = -286307141298283926L; + + public StatelessAjaxFormComponentUpdatingBehavior(final String event) { + super(event); + } + + @Override + public CharSequence getCallbackUrl() { + final Url url = Url.parse(super.getCallbackUrl().toString()); + final PageParameters params = getPageParameters(); + return StatelessEncoder.mergeParameters(url, params).toString(); + } + + @Override + public boolean getStatelessHint(final Component component) { + return true; + } + + /** + * Override this to pass the context of the current page to the behavior, + * allowing it to recreate the context for the ajax request. + * + */ + protected PageParameters getPageParameters() { + return null; + } +} diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormSubmitBehavior.java b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormSubmitBehavior.java new file mode 100644 index 00000000..a0093920 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxFormSubmitBehavior.java @@ -0,0 +1,43 @@ +package com.commafeed.frontend.utils.stateless; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.request.Url; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +public abstract class StatelessAjaxFormSubmitBehavior extends + AjaxFormSubmitBehavior { + + private static final long serialVersionUID = 1L; + + public StatelessAjaxFormSubmitBehavior(final String event) { + super(event); + } + + public StatelessAjaxFormSubmitBehavior(Form form, String event) { + super(form, event); + } + + @Override + public CharSequence getCallbackUrl() { + final Url url = Url.parse(super.getCallbackUrl().toString()); + final PageParameters params = getPageParameters(); + return StatelessEncoder.mergeParameters(url, params).toString(); + } + + @Override + public boolean getStatelessHint(final Component component) { + return true; + } + + /** + * Override this to pass the context of the current page to the behavior, + * allowing it to recreate the context for the ajax request. + * + */ + protected PageParameters getPageParameters() { + return null; + } + +} diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxLink.java b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxLink.java new file mode 100644 index 00000000..b00c77c8 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessAjaxLink.java @@ -0,0 +1,70 @@ +package com.commafeed.frontend.utils.stateless; + +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; +import org.apache.wicket.ajax.markup.html.IAjaxLink; +import org.apache.wicket.markup.ComponentTag; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +public abstract class StatelessAjaxLink extends StatelessLink + implements IAjaxLink { + + private static final long serialVersionUID = -133600842398684777L; + + public StatelessAjaxLink(final String id) { + this(id, null, null); + } + + public StatelessAjaxLink(final String id, + final PageParameters params) { + this(id, null, params); + } + + public StatelessAjaxLink(final String id, final IModel model) { + this(id, model, null); + } + + public StatelessAjaxLink(final String id, final IModel model, + final PageParameters params) { + super(id, model, params); + + add(new StatelessAjaxEventBehavior("click") { + private static final long serialVersionUID = -8445395501430605953L; + + @Override + protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { + super.updateAjaxAttributes(attributes); + StatelessAjaxLink.this.updateAjaxAttributes(attributes); + } + + @Override + protected PageParameters getPageParameters() { + return StatelessAjaxLink.this.getPageParameters(); + } + + @Override + protected void onComponentTag(final ComponentTag tag) { + if (isLinkEnabled()) { + super.onComponentTag(tag); + } + } + + @Override + protected void onEvent(final AjaxRequestTarget target) { + onClick(target); + target.add(StatelessAjaxLink.this); + } + }); + } + + protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { + } + + @Override + public final void onClick() { + onClick(null); + } + + public abstract void onClick(final AjaxRequestTarget target); +} diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/StatelessEncoder.java b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessEncoder.java new file mode 100644 index 00000000..bd2cae3c --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessEncoder.java @@ -0,0 +1,42 @@ +package com.commafeed.frontend.utils.stateless; + +import java.nio.charset.Charset; +import java.util.HashSet; +import java.util.Set; + +import org.apache.wicket.request.Url; +import org.apache.wicket.request.mapper.parameter.INamedParameters; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.util.encoding.UrlEncoder; + +final class StatelessEncoder { + + static Url mergeParameters(final Url url, final PageParameters params) { + if (params == null) { + return url; + } + + Charset charset = url.getCharset(); + Url mergedUrl = Url.parse(url.toString(), charset); + UrlEncoder urlEncoder = UrlEncoder.QUERY_INSTANCE; + Set setParameters = new HashSet(); + + for (INamedParameters.NamedPair pair : params.getAllNamed()) { + String key = urlEncoder.encode(pair.getKey(), charset); + String value = urlEncoder.encode(pair.getValue(), charset); + + if (setParameters.contains(key)) { + mergedUrl.addQueryParameter(key, value); + } else { + mergedUrl.setQueryParameter(key, value); + setParameters.add(key); + } + } + + return mergedUrl; + } + + private StatelessEncoder() { + + } +} diff --git a/src/main/java/com/commafeed/frontend/utils/stateless/StatelessLink.java b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessLink.java new file mode 100644 index 00000000..bbb7594c --- /dev/null +++ b/src/main/java/com/commafeed/frontend/utils/stateless/StatelessLink.java @@ -0,0 +1,43 @@ +package com.commafeed.frontend.utils.stateless; + +import org.apache.wicket.markup.html.link.Link; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.Url; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +public abstract class StatelessLink extends Link { + private static final long serialVersionUID = 1L; + + private final PageParameters parameters; + + public StatelessLink(final String id) { + this(id, null, null); + } + + public StatelessLink(final String id, final IModel model) { + this(id, model, null); + } + + public StatelessLink(final String id, final IModel model, + final PageParameters params) { + super(id, model); + setMarkupId(id); + this.parameters = params; + } + + protected final PageParameters getPageParameters() { + return parameters; + } + + @Override + protected boolean getStatelessHint() { + return true; + } + + @Override + protected CharSequence getURL() { + final Url url = Url.parse(super.getURL().toString()); + Url mergedUrl = StatelessEncoder.mergeParameters(url, parameters); + return mergedUrl.toString(); + } +} diff --git a/src/main/java/com/commafeed/model/Feed.java b/src/main/java/com/commafeed/model/Feed.java new file mode 100644 index 00000000..00cfd6a5 --- /dev/null +++ b/src/main/java/com/commafeed/model/Feed.java @@ -0,0 +1,64 @@ +package com.commafeed.model; + +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import com.google.common.collect.Sets; + +@Entity +@Table(name = "FEEDS") +public class Feed implements Serializable { + + @Id + @Column(length = 2048) + private String url; + + @Temporal(TemporalType.TIMESTAMP) + private Date lastUpdated; + + @OneToMany(mappedBy = "feed", fetch = FetchType.EAGER) + private Set entries = Sets.newHashSet(); + + public Feed() { + + } + + public Feed(String url) { + this.url = url; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Date getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public Set getEntries() { + return entries; + } + + public void setEntries(Set entries) { + this.entries = entries; + } + +} diff --git a/src/main/java/com/commafeed/model/FeedCategory.java b/src/main/java/com/commafeed/model/FeedCategory.java new file mode 100644 index 00000000..2ffe9375 --- /dev/null +++ b/src/main/java/com/commafeed/model/FeedCategory.java @@ -0,0 +1,78 @@ +package com.commafeed.model; + +import java.io.Serializable; +import java.util.Set; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import com.google.common.collect.Sets; + +@Entity +@Table(name = "FEEDCATEGORIES") +public class FeedCategory implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column(length = 128) + private String name; + + @ManyToOne + private User user; + + @ManyToOne + private FeedCategory parent; + + @OneToMany(mappedBy = "category", fetch = FetchType.EAGER) + private Set subscriptions = Sets.newHashSet(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public FeedCategory getParent() { + return parent; + } + + public void setParent(FeedCategory parent) { + this.parent = parent; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Set getSubscriptions() { + return subscriptions; + } + + public void setSubscriptions(Set subscriptions) { + this.subscriptions = subscriptions; + } + +} diff --git a/src/main/java/com/commafeed/model/FeedEntry.java b/src/main/java/com/commafeed/model/FeedEntry.java new file mode 100644 index 00000000..9847c6a7 --- /dev/null +++ b/src/main/java/com/commafeed/model/FeedEntry.java @@ -0,0 +1,86 @@ +package com.commafeed.model; + +import java.io.Serializable; +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +@Entity +@Table(name = "FEEDENTRIES") +public class FeedEntry implements Serializable { + + @Id + @Column(length = 2048) + private String guid; + + @ManyToOne + private Feed feed; + + @Column(length = 256) + private String title; + + @Lob + private String content; + + @Column(length = 2048) + private String url; + + @Temporal(TemporalType.TIMESTAMP) + private Date updated; + + public String getGuid() { + return guid; + } + + public void setGuid(String guid) { + this.guid = guid; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Date getUpdated() { + return updated; + } + + public void setUpdated(Date updated) { + this.updated = updated; + } + + public Feed getFeed() { + return feed; + } + + public void setFeed(Feed feed) { + this.feed = feed; + } + +} diff --git a/src/main/java/com/commafeed/model/FeedEntryStatus.java b/src/main/java/com/commafeed/model/FeedEntryStatus.java new file mode 100644 index 00000000..c8b23953 --- /dev/null +++ b/src/main/java/com/commafeed/model/FeedEntryStatus.java @@ -0,0 +1,71 @@ +package com.commafeed.model; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "FEEDENTRYSTATUSES") +public class FeedEntryStatus implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @ManyToOne + private User user; + + @ManyToOne + private FeedEntry entry; + + @Column(name = "read_status") + private boolean read; + private boolean starred; + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public FeedEntry getEntry() { + return entry; + } + + public void setEntry(FeedEntry entry) { + this.entry = entry; + } + + public boolean isRead() { + return read; + } + + public void setRead(boolean read) { + this.read = read; + } + + public boolean isStarred() { + return starred; + } + + public void setStarred(boolean starred) { + this.starred = starred; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + +} diff --git a/src/main/java/com/commafeed/model/FeedSubscription.java b/src/main/java/com/commafeed/model/FeedSubscription.java new file mode 100644 index 00000000..da34af51 --- /dev/null +++ b/src/main/java/com/commafeed/model/FeedSubscription.java @@ -0,0 +1,73 @@ +package com.commafeed.model; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "FEEDSUBSCRIPTIONS") +public class FeedSubscription implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @ManyToOne + private User user; + + @ManyToOne + private Feed feed; + + @Column(length = 128) + private String title; + + @ManyToOne + private FeedCategory category; + + public Feed getFeed() { + return feed; + } + + public void setFeed(Feed feed) { + this.feed = feed; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public FeedCategory getCategory() { + return category; + } + + public void setCategory(FeedCategory category) { + this.category = category; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + +} diff --git a/src/main/java/com/commafeed/model/User.java b/src/main/java/com/commafeed/model/User.java new file mode 100644 index 00000000..200d0eee --- /dev/null +++ b/src/main/java/com/commafeed/model/User.java @@ -0,0 +1,61 @@ +package com.commafeed.model; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "USERS") +public class User implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column(length = 32) + private String name; + + @Column(length = 256) + private byte[] password; + + @Column(length = 8) + private byte[] salt; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte[] getPassword() { + return password; + } + + public void setPassword(byte[] password) { + this.password = password; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public byte[] getSalt() { + return salt; + } + + public void setSalt(byte[] salt) { + this.salt = salt; + } + +} diff --git a/src/main/resources/.gitkeep b/src/main/resources/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml new file mode 100644 index 00000000..000a7083 --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,18 @@ + + + + java:/jdbc/commafeedDS + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 00000000..64a13528 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,16 @@ +log4j.logger.com.commafeed=DEBUG, CONSOLE, FILE +log4j.logger.org=WARN, CONSOLE +log4j.logger.java=WARN, CONSOLE +log4j.logger.de=WARN, CONSOLE + +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%-5p %d{ISO8601} [%c{1}\:%L] %m%n + +log4j.appender.FILE=org.apache.log4j.RollingFileAppender +log4j.appender.FILE.File=${env.OPENSHIFT_LOG_DIR}commafeed.log +log4j.appender.FILE.layout=org.apache.log4j.PatternLayout +log4j.appender.FILE.layout.ConversionPattern=%-5p %d{ISO8601} [%c{1}\:%L/%t] %m%n +log4j.appender.FILE.MaxFileSize=100KB +log4j.appender.FILE.MaxBackupIndex=5 +log4j.appender.FILE.Append=false \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/beans.xml b/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000..70d8902d --- /dev/null +++ b/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..f44626dd --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + + Wicket + org.apache.wicket.protocol.http.WicketFilter + + applicationClassName + com.commafeed.frontend.CommaFeedApplication + + + configuration + deployment + + + + Wicket + /* + +