diff --git a/.bowerrc b/.bowerrc
new file mode 100644
index 00000000..b1283deb
--- /dev/null
+++ b/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "src/main/app/lib"
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f53e9dfe..755a3061 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,19 +1,18 @@
-#runtime files
-commafeed.log
-derby.log
-data/
-java_pid*
-
-# Maven build directory
+# build directory
target
-deployments/ROOT.war
+
+# node
+node
+node_modules
+
+# bower
+src/main/app/lib
# Eclipse files
.project
.classpath
.settings
.factorypath
-/target
# IntelliJ Idea files
.idea
diff --git a/.openshift/action_hooks/README.md b/.openshift/action_hooks/README.md
deleted file mode 100644
index 86ac3ec5..00000000
--- a/.openshift/action_hooks/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-For information about which action hooks are supported, consult the OpenShift documentation:
-
-https://github.com/openshift/origin-server/blob/master/node/README.writing_applications.md
diff --git a/.openshift/action_hooks/build b/.openshift/action_hooks/build
deleted file mode 100755
index f0861010..00000000
--- a/.openshift/action_hooks/build
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/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
deleted file mode 100755
index ed5eb993..00000000
--- a/.openshift/action_hooks/deploy
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/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
deleted file mode 100755
index a57d1f58..00000000
--- a/.openshift/action_hooks/post_deploy
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/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
deleted file mode 100755
index ff0debda..00000000
--- a/.openshift/action_hooks/post_start_jbosseap-6.0
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/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
deleted file mode 100755
index ff0debda..00000000
--- a/.openshift/action_hooks/post_stop_jbosseap-6.0
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/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
deleted file mode 100755
index 10cd5446..00000000
--- a/.openshift/action_hooks/pre_build
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/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
deleted file mode 100755
index 557aa544..00000000
--- a/.openshift/action_hooks/pre_build_jbosseap-6.0
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/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"
-export MAVEN_ARGS="clean package -Popenshift -Pprod -DskipTests=true"
-export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=128m -Dmaven.artifact.threads=20"
\ No newline at end of file
diff --git a/.openshift/action_hooks/pre_start_jbosseap-6.0 b/.openshift/action_hooks/pre_start_jbosseap-6.0
deleted file mode 100755
index ff0debda..00000000
--- a/.openshift/action_hooks/pre_start_jbosseap-6.0
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/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
deleted file mode 100755
index ff0debda..00000000
--- a/.openshift/action_hooks/pre_stop_jbosseap-6.0
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/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
deleted file mode 100644
index cb69cf94..00000000
--- a/.openshift/config/modules/README
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644
index 12d7f66c..00000000
--- a/.openshift/config/standalone.xml
+++ /dev/null
@@ -1,517 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- jdbc:mysql://${env.OPENSHIFT_MYSQL_DB_HOST}:${env.OPENSHIFT_MYSQL_DB_PORT}/${env.OPENSHIFT_APP_NAME}?useUnicode=true&characterEncoding=UTF-8
-
- mysql
-
- ${env.OPENSHIFT_MYSQL_DB_USERNAME}
- ${env.OPENSHIFT_MYSQL_DB_PASSWORD}
-
-
-
-
- com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
-
-
-
-
-
-
-
-
- false
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${env.OPENSHIFT_GEAR_DNS}
- ${env.OPENSHIFT_JBOSSEAP_CLUSTER_PROXY_PORT}
-
- 7600
- ${env.OPENSHIFT_JBOSSEAP_IP}
-
-
- 3000
- ${env.OPENSHIFT_JBOSSEAP_CLUSTER}
- 0
- 1
-
-
-
-
-
-
-
-
-
- org.jgroups.auth.MD5Token
- SHA
- ${env.OPENSHIFT_APP_UUID}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- false
- false
- 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
deleted file mode 100644
index aad91380..00000000
--- a/.openshift/cron/README.cron
+++ /dev/null
@@ -1,22 +0,0 @@
-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
deleted file mode 100644
index e69de29b..00000000
diff --git a/.openshift/cron/daily/log-cleanup.sh b/.openshift/cron/daily/log-cleanup.sh
deleted file mode 100755
index ce79496f..00000000
--- a/.openshift/cron/daily/log-cleanup.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-if [ $OPENSHIFT_JBOSSAS_LOG_DIR ]; then
- rm -rf $OPENSHIFT_JBOSSAS_LOG_DIR/*.log.*
-fi
-
-if [ $OPENSHIFT_JBOSSEAP_LOG_DIR ]; then
- rm -rf $OPENSHIFT_JBOSSEAP_LOG_DIR/*.log.*
-fi
\ No newline at end of file
diff --git a/.openshift/cron/hourly/.gitignore b/.openshift/cron/hourly/.gitignore
deleted file mode 100644
index e69de29b..00000000
diff --git a/.openshift/cron/minutely/.gitignore b/.openshift/cron/minutely/.gitignore
deleted file mode 100644
index e69de29b..00000000
diff --git a/.openshift/cron/monthly/.gitignore b/.openshift/cron/monthly/.gitignore
deleted file mode 100644
index e69de29b..00000000
diff --git a/.openshift/cron/weekly/README b/.openshift/cron/weekly/README
deleted file mode 100644
index 7c3e659f..00000000
--- a/.openshift/cron/weekly/README
+++ /dev/null
@@ -1,16 +0,0 @@
-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
deleted file mode 100644
index fc4abb87..00000000
--- a/.openshift/cron/weekly/chrono.dat
+++ /dev/null
@@ -1 +0,0 @@
-Time And Relative D...n In Execution (Open)Shift!
diff --git a/.openshift/cron/weekly/chronograph b/.openshift/cron/weekly/chronograph
deleted file mode 100755
index 61de949f..00000000
--- a/.openshift/cron/weekly/chronograph
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-echo "`date`: `cat $(dirname \"$0\")/chrono.dat`"
diff --git a/.openshift/cron/weekly/jobs.allow b/.openshift/cron/weekly/jobs.allow
deleted file mode 100644
index 8d32abc7..00000000
--- a/.openshift/cron/weekly/jobs.allow
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# 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
deleted file mode 100644
index 73c94500..00000000
--- a/.openshift/cron/weekly/jobs.deny
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# 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
deleted file mode 100644
index 154c7895..00000000
--- a/.openshift/markers/README
+++ /dev/null
@@ -1,22 +0,0 @@
-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/LICENSE b/LICENSE
deleted file mode 100644
index 014a5538..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,31 +0,0 @@
-Apache License, Version 2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-1. Definitions.
-"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
-"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
-"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
-"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
-"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
-"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
-"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
-"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
-"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
-2. Grant of Copyright License.
-Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
-3. Grant of Patent License.
-Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
-4. Redistribution.
-You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
-You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
-5. Submission of Contributions.
-Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
-6. Trademarks.
-This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
-7. Disclaimer of Warranty.
-Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
-8. Limitation of Liability.
-In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
-9. Accepting Warranty or Additional Liability.
-While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
-END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 100644
index a5e20b87..00000000
--- a/README.md
+++ /dev/null
@@ -1,132 +0,0 @@
-CommaFeed [](https://buildhive.cloudbees.com/job/Athou/job/commafeed/)
-=========
-Sources for [CommaFeed.com](http://www.commafeed.com/).
-
-Google Reader inspired self-hosted RSS reader, based on JAX-RS, Wicket and AngularJS.
-
-Deploy on your own server (using TomEE, a lightweight JavaEE6 container based on Tomcat) or even in the cloud for free on OpenShift.
-
-Related open-source projects
-----------------------------
-
-Android apps: [News+ extension](https://github.com/Athou/commafeed-newsplus) - [Android app](https://github.com/doomrobo/CommaFeed-Android-Reader)
-
-Browser extensions: [Chrome](https://github.com/Athou/commafeed-chrome) - [Firefox](https://github.com/Athou/commafeed-firefox) - [Opera](https://github.com/Athou/commafeed-opera) - [Safari](https://github.com/Athou/commafeed-safari)
-
-Deployment on OpenShift
------------------------
-
-Hosting an application on OpenShift is free.
-At the moment those instructions are not working because the application takes too long to build on OpenShift and causes a timeout.
-See [here](http://jasonwryan.com/blog/2013/05/25/greader/) for an alternative method.
-
-* Create an account on [OpenShift](http://www.openshift.com/).
-* Add an application, select `JBoss Enterprise Application Platform 6.0`.
-* For the `Public URL` set the name you want (e.g. `commafeed`).
-* For the `Source Code` option, click `Change` and set this repository (`https://github.com/Athou/commafeed.git`).
-* Click `Create Application`.
-* Click `Add cartridge` and select `MySQL`.
-* Wait a couple of minutes and access your application.
-* The default user is `admin` and the password is `admin`.
-
-Deployment on your own server
------------------------------
-
-For storage, you can either use an embedded HSQLDB database or an external MySQL, PostgreSQL or SQLServer database.
-You also need Maven 3.x (and a Java 1.7+ JDK) installed in order to build the application.
-
-To install maven and openjdk on Ubuntu, issue the following commands
-
- sudo add-apt-repository ppa:natecarlson/maven3
- sudo apt-get update
- sudo apt-get install openjdk-7-jdk maven3
-
- # Not required but if you don't, use 'mvn3' instead of 'mvn' for the rest of the instructions.
- sudo ln -s /usr/bin/mvn3 /usr/bin/mvn
-
-On Windows and other operating systems, just download maven 3.x from the [official site](http://maven.apache.org/), extract it somewhere and add the `bin` directory to your `PATH` environment variable.
-
-Download the sources (it doesn't matter where, you can delete the directory when you're done).
-If you don't have git you can download the sources as a zip file from [here](https://github.com/Athou/commafeed/archive/master.zip)
-
- git clone https://github.com/Athou/commafeed.git
- cd commafeed
-
-Now build the application
-
- # Embedded HSQL database:
- mvn clean package tomee:build -Pprod
-
- # External MySQL database:
- mvn clean package tomee:build -Pprod -Pmysql
-
- # External PostgreSQL database:
- mvn clean package tomee:build -Pprod -Ppgsql
-
- # External Microsoft SQL Server database:
- mvn clean package tomee:build -Pprod -Pmssql
-
-It will generate a zip file at `target/commafeed.zip` with everything you need to run the application.
-
-* Create a directory somewhere (e.g. `/opt/commafeed/`) and extract the generated zip inside this directory.
-* Create a directory called `logs` (e.g. `/opt/commafeed/logs`)
-* Copy the file `conf/setenv.sh` (Linux) or `conf/setenv.bat` (Windows) to `bin/`
-* If you don't use the embedded database, create a database in your external database instance, then uncomment the `Resource` element corresponding to the database engine you use from `conf/tomee.xml` and edit the default credentials.
-* If you'd like to change the default port (8082), edit `conf/server.xml` and look for ``).
-This will generate the file `target/commafeed.war`. Copy this file to your tomee `webapps/` directory.
-* The application is online at [http://localhost:8082/commafeed](http://localhost:8082/commafeed). Don't forget to set the public URL in the admin settings.
-* The default user is `admin` and the password is `admin`.
-
-You can use nginx or apache as a proxy http server. Note that when using apache, the `ProxyPreserveHost on` option should be set in your config file.
-
-Local development
------------------
-
-Checkout the code and use maven to build and start a local TomEE instance.
-
- `mvn clean package tomee:run`
-
-The application is online at [http://localhost:8082/commafeed](http://localhost:8082/commafeed). Any change to the source code will be applied immediatly.
-The default user is `admin` and the password is `admin`.
-
-Translate CommaFeed into your language
---------------------------------------
-
-Files for internationalization are located [here](https://github.com/Athou/commafeed/tree/master/src/main/resources/i18n).
-
-To add a new language, create a new file in that directory.
-The name of the file should be the two-letters [ISO-639-1 language code](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
-The language has to be referenced in the `languages.properties` file to be picked up.
-
-When adding new translations, add them in en.properties then run `mvn -e groovy:execute -Pi18n`. It will parse the english file and add placeholders in the other translation files.
-
-Themes
----------------------
-
-To create a theme, create a new file `src/main/webapp/sass/themes/_.scss`. Your styles should be wrapped in a `#theme-` element and use the [SCSS format](http://sass-lang.com/) which is a superset of CSS.
-
-Don't forget to reference your theme in `src/main/webapp/sass/app.scss` and in `src/main/webapp/js/controllers.js` (look for `$scope.themes`).
-
-See [_test.scss](https://github.com/Athou/commafeed/blob/master/src/main/webapp/sass/themes/_test.scss) for an example.
-
-
-Copyright and license
----------------------
-
-Copyright 2013 CommaFeed.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this work except in compliance with the License.
-You may obtain a copy of the License in the LICENSE file, or at:
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/bower.json b/bower.json
new file mode 100644
index 00000000..811c83fd
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,30 @@
+{
+ "name": "commafeed",
+ "version": "2.0.0",
+ "dependencies": {
+ "jquery": "1.11.0",
+ "jquery-ui": "1.11",
+ "jquery-mousewheel": "3.1.12",
+ "lodash": "2.4.1",
+ "bootstrap": "3.1.1",
+ "font-awesome": "3.2.1",
+ "angular": "1.2.16",
+ "angular-resource": "1.2.16",
+ "angular-route": "1.2.16",
+ "angular-sanitize": "1.2.16",
+ "angular-touch": "1.2.16",
+ "angular-animate": "1.2.16",
+ "angular-ui-router": "0.2.8",
+ "angular-ui-utils": "0.1.0",
+ "angular-ui-select2": "0.0.5",
+ "angular-bootstrap": "0.2.0",
+ "angular-loading-bar": "0.4.0",
+ "ngInfiniteScroll": "1.0.0",
+ "ng-grid": "2.0.6",
+ "mousetrap": "1.4.6",
+ "momentjs": "2.6.0",
+ "device.js": "matthewhudson/device.js#2ae5c775e35ccc837589e5af34e292c54936778c",
+ "readabilicons": "arc90/readability-readabilicons#34c55561c5b8ec6e90714b50237c06b13cb9d59c",
+ "zocial": "samcollins/css-social-buttons#1f59ecacde475e563fb6771667597493ec4eecb6"
+ }
+}
diff --git a/conf/setenv.bat b/conf/setenv.bat
deleted file mode 100644
index d48bf725..00000000
--- a/conf/setenv.bat
+++ /dev/null
@@ -1 +0,0 @@
-set JAVA_OPTS=-Djava.net.preferIPv4Stack=true -Xmx1024m -XX:MaxPermSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -Djsse.enableSNIExtension=false
\ No newline at end of file
diff --git a/conf/setenv.sh b/conf/setenv.sh
deleted file mode 100644
index 7ad8e3ad..00000000
--- a/conf/setenv.sh
+++ /dev/null
@@ -1 +0,0 @@
-export JAVA_OPTS="-Djava.net.preferIPv4Stack=true -Xmx1024m -XX:MaxPermSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -Djsse.enableSNIExtension=false"
\ No newline at end of file
diff --git a/config.yml b/config.yml
new file mode 100644
index 00000000..316e53fa
--- /dev/null
+++ b/config.yml
@@ -0,0 +1,50 @@
+app:
+ publicUrl: http://localhost:8083/
+ allowRegistrations: false
+ googleAnalyticsTrackingCode:
+ googleClientId:
+ googleClientSecret:
+ backgroundThreads: 3
+ databaseUpdateThreads: 1
+ smtpHost:
+ smtpPort:
+ smtpTls: false
+ smtpUserName:
+ smtpPassword:
+ heavyLoad: false
+ pubsubhubbub: false
+ imageProxyEnabled: false
+ queryTimeout: 0
+ crawlingPaused: false
+ keepStatusDays: 0
+ refreshIntervalMinutes: 5
+ announcement:
+
+authenticationCachePolicy: maximumSize=10000, expireAfterAccess=10m
+database:
+ driverClass: org.h2.Driver
+ user: sa
+ password: sa
+ url: jdbc:h2:./target/example
+ properties:
+ charSet: UTF-8
+ # hibernate.dialect: org.hibernate.dialect.PostgreSQLDialect
+ maxWaitForConnection: 1s
+ validationQuery: "/* MyApplication Health Check */ SELECT 1"
+ minSize: 1
+ maxSize: 8
+ checkConnectionWhileIdle: true
+
+server:
+ applicationConnectors:
+ - type: http
+ port: 8082
+
+logging:
+ level: WARN
+ loggers:
+ com.commafeed: DEBUG
+ liquibase: INFO
+ org.hibernate.SQL: ALL
+ appenders:
+ - type: console
\ No newline at end of file
diff --git a/gulp b/gulp
new file mode 100644
index 00000000..f02507dc
--- /dev/null
+++ b/gulp
@@ -0,0 +1,2 @@
+#!/bin/sh
+"node/node" "node_modules/gulp/bin/gulp.js" "$@"
\ No newline at end of file
diff --git a/gulp.cmd b/gulp.cmd
new file mode 100644
index 00000000..3cfe9dad
--- /dev/null
+++ b/gulp.cmd
@@ -0,0 +1,3 @@
+@echo off
+%~dp0node/node node_modules/gulp/bin/gulp.js %*
+@echo on
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 00000000..61038ca6
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,73 @@
+var gulp = require('gulp');
+var minifyCSS = require('gulp-minify-css');
+var uglify = require('gulp-uglify');
+var filter = require('gulp-filter');
+var bower = require('gulp-bower');
+var connect = require('gulp-connect');
+var modRewrite = require('connect-modrewrite');
+var sass = require('gulp-sass');
+var useref = require('gulp-useref');
+var templateCache = require('gulp-angular-templatecache');
+
+var SRC_DIR = 'src/main/app/';
+var TEMP_DIR = 'target/gulp/'
+var BUILD_DIR = 'target/classes/assets/';
+
+gulp.task('bower', function() {
+ return bower();
+});
+
+gulp.task('images', function() {
+ return gulp.src(SRC_DIR + 'images/**/*').pipe(gulp.dest(BUILD_DIR + 'images'));
+});
+
+gulp.task('sass', function() {
+ return gulp.src(SRC_DIR + 'sass/app.scss').pipe(sass()).pipe(gulp.dest(TEMP_DIR + 'css'));
+});
+
+gulp.task('fonts', function() {
+ gulp.src(SRC_DIR + 'lib/font-awesome/font/fontawesome-webfont.*').pipe(gulp.dest(BUILD_DIR + 'font'));
+ gulp.src(SRC_DIR + 'lib/readabilicons/webfont/fonts/readabilicons-*').pipe(gulp.dest(BUILD_DIR + 'font'));
+ return gulp.src(SRC_DIR + 'lib/zocial/css/zocial-regular-*').pipe(gulp.dest(BUILD_DIR + 'font'));
+});
+
+gulp.task('template-cache', function() {
+ var options = {
+ module : 'commafeed.services',
+ root : 'templates/'
+ };
+ return gulp.src(SRC_DIR + 'templates/**/*.html').pipe(templateCache(options)).pipe(gulp.dest(TEMP_DIR + 'js'));
+});
+
+gulp.task('build', ['images', 'sass', 'fonts', 'template-cache'], function() {
+ var assets = useref.assets({
+ searchPath : [SRC_DIR, TEMP_DIR]
+ });
+ var jsFilter = filter("**/*.js");
+ var cssFilter = filter("**/*.css");
+ return gulp.src([SRC_DIR + 'index.html', TEMP_DIR + 'app.css']).pipe(assets)
+
+ .pipe(cssFilter).pipe(minifyCSS()).pipe(cssFilter.restore())
+
+ .pipe(jsFilter).pipe(uglify()).pipe(jsFilter.restore())
+
+ .pipe(assets.restore()).pipe(useref()).pipe(gulp.dest(BUILD_DIR));
+});
+
+gulp.task('watch', function() {
+ gulp.watch(SRC_DIR + 'sass/**/*.scss', ['build']);
+ gulp.watch(SRC_DIR + 'js/**/*.js', ['build']);
+});
+
+gulp.task('serve', function() {
+ connect.server({
+ root : BUILD_DIR,
+ port : 8083,
+ middleware : function() {
+ return [modRewrite(['^/rest/(.*)$ http://localhost:8082/rest/$1 [P]'])];
+ }
+ });
+});
+
+gulp.task('dev', ['build', 'watch', 'serve']);
+gulp.task('default', ['build']);
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..20b74d83
--- /dev/null
+++ b/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "commafeed",
+ "version": "2.0.0",
+ "main": "main.js",
+ "private": true,
+ "devDependencies": {
+ "gulp": "3.8.7",
+ "gulp-minify-css": "0.3.7",
+ "gulp-uglify": "0.3.1",
+ "gulp-filter": "1.0.0",
+ "gulp-bower": "0.0.6",
+ "gulp-connect": "2.0.6",
+ "connect-modrewrite": "0.7.7",
+ "gulp-sass": "0.7.2",
+ "gulp-useref": "0.6.0",
+ "gulp-angular-templatecache": "1.3.0"
+ }
+}
diff --git a/pom.xml b/pom.xml
index aad12378..45f4b8bc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,11 +1,11 @@
- 4.0.0
+ 4.0.0com.commafeedcommafeed
- 1.5.0-SNAPSHOT
- war
+ 2.0.0
+ jarCommaFeed
@@ -14,163 +14,26 @@
UTF-8
- false
- false
- java:openejb/Resource/My DataSource
- false
- utf8mb4
- com.commafeed.backend.cache.NoopCacheService
+ 0.7.1
- commafeedsrc/main/resourcestrue
-
- src/main/java
-
- **/*
-
-
- **/*.java
-
-
-
org.apache.maven.pluginsmaven-compiler-plugin3.1
- 1.6
- 1.6
+ 1.7
+ 1.7
-
- maven-war-plugin
- 2.4
-
- false
-
-
- ${basedir}/src/main/webapp/WEB-INF
- WEB-INF
- true
-
- **/beans.xml
-
-
-
- target/generated-sources/api-docs/
- api/api-docs
-
- **/*
-
-
-
-
-
-
- org.apache.openejb.maven
- tomee-maven-plugin
- 1.5.2
-
- 1.6.0
- plus
- 8082
- -Xmx1024m -XX:MaxPermSize=512m -XX:+CMSClassUnloadingEnabled
- ${project.basedir}/src/main/tomee/conf
- true
-
- 1
-
- .class
-
-
- .properties
- .html
- .js
- .css
- .scss
-
-
-
- org.hibernate:hibernate-entitymanager:4.1.11.Final
- org.hibernate:hibernate-core:4.1.11.Final
- org.hibernate.common:hibernate-commons-annotations:4.0.1.Final
- org.hibernate:hibernate-validator:4.3.1.Final
- org.jboss.logging:jboss-logging:3.1.3.GA
- org.javassist:javassist:3.15.0-GA
-
- org.apache.openejb:openejb-bonecp:4.6.0
- com.jolbox:bonecp:0.8.0.RELEASE
- com.google.guava:guava:14.0.1
-
- dom4j:dom4j:1.6.1
- antlr:antlr:2.7.7
- remove:openjpa-
- remove:hsqldb
- org.hsqldb:hsqldb:2.3.0
- mysql:mysql-connector-java:5.1.26
- postgresql:postgresql:9.1-901.jdbc4
- net.sourceforge.jtds:jtds:1.3.1
-
- org.infinispan:infinispan-core:5.1.4.FINAL
- org.hibernate:hibernate-infinispan:4.1.11.Final
- org.jgroups:jgroups:3.0.9.Final
- org.jboss.marshalling:jboss-marshalling-river:1.3.11.GA
- org.jboss.marshalling:jboss-marshalling:1.3.11.GA
- org.codehaus.woodstox:woodstox-core-asl:4.1.1
- org.codehaus.woodstox:stax2-api:3.1.1
- org.rhq.helpers:rhq-pluginAnnotations:3.0.4
- org.jboss.logmanager:jboss-logmanager:1.2.2.GA
-
-
-
-
- org.bsc.maven
- maven-processor-plugin
- 2.2.3
-
-
- process
-
- process
-
- generate-sources
-
-
- org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor
-
- target/generated-sources/metamodel
-
-
-
- doc
- process-classes
-
- process
-
-
-
- com.commafeed.frontend.APIGenerator
-
- target/generated-sources/api-docs
-
-
-
-
-
- org.hibernate
- hibernate-jpamodelgen
- 1.3.0.Final
-
-
- pl.project13.mavengit-commit-id-plugin
@@ -187,6 +50,72 @@
false
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 1.6
+
+ true
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+ package
+
+ shade
+
+
+
+
+
+ com.commafeed.CommaFeedApplication
+
+
+
+
+
+
+
+ com.github.eirslett
+ frontend-maven-plugin
+ 0.0.15
+
+
+ install node and npm
+
+ install-node-and-npm
+
+ generate-resources
+
+ v0.10.30
+ 1.3.8
+
+
+
+ npm install
+
+ npm
+
+ generate-resources
+
+
+ gulp build
+
+ gulp
+
+ generate-resources
+
+
+
@@ -194,58 +123,71 @@
org.projectlomboklombok
- 1.12.6
+ 1.14.4provided
- org.jboss.spec
- jboss-javaee-6.0
- 1.0.0.Final
- pom
- provided
+ org.slf4j
+ slf4j-api
+ 1.7.7
+
+
+
+ io.dropwizard
+ dropwizard-core
+ ${dropwizard.version}
- org.hibernate
- hibernate-entitymanager
- 4.1.11.Final
- provided
+ io.dropwizard
+ dropwizard-auth
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-hibernate
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-client
+ ${dropwizard.version}
+
+
+ io.dropwizard
+ dropwizard-migrations
+ ${dropwizard.version}
+
+
+ io.federecio
+ dropwizard-swagger
+ 0.5.1
- dom4j
- dom4j
+ jsr311-api
+ javax.ws.rs
+
+
+ javassist
+ javassist
- redis.clients
- jedis
- 2.2.1
+ com.mysema.querydsl
+ querydsl-apt
+ 3.4.2
+ provided
+ hibernate
- org.liquibase
- liquibase-core
- 3.1.1
-
-
-
- com.google.guava
- guava
- 16.0.1
+ com.mysema.querydsl
+ querydsl-jpa
+ 3.4.2
- commons-beanutils
- commons-beanutils
- 1.9.1
-
-
- commons-codec
- commons-codec
- 1.9
-
-
- commons-collections
- commons-collections
- 3.2.1
+ com.sun.jersey.contribs
+ jersey-multipart
+ 1.18.1commons-io
@@ -253,9 +195,14 @@
2.4
- commons-lang
- commons-lang
- 2.6
+ commons-collections
+ commons-collections
+ 3.2.1
+
+
+ commons-codec
+ commons-codec
+ 1.9org.apache.commons
@@ -263,11 +210,15 @@
2.2
- commons-fileupload
- commons-fileupload
- 1.3.1
+ redis.clients
+ jedis
+ 2.2.1
+
+
+ com.sun.mail
+ javax.mail
+ 1.5.2
-
net.java.dev.romerome
@@ -295,6 +246,11 @@
jdom1.1.3
+
+ org.jsoup
+ jsoup
+ 1.7.3
+ com.googlecode.juniversalchardetjuniversalchardet
@@ -303,160 +259,33 @@
com.google.gwtgwt-servlet
- 2.6.0
+ 2.6.1net.sourceforge.cssparsercssparser
- 0.9.13
+ 0.9.14
- org.apache.httpcomponents
- httpclient
- 4.3.3
+ com.h2database
+ h2
+ 1.4.181
- org.jsoup
- jsoup
- 1.7.3
-
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.3.3
+ mysql
+ mysql-connector-java
+ 5.1.31
- org.slf4j
- slf4j-log4j12
- 1.7.7
+ postgresql
+ postgresql
+ 9.1-901-1.jdbc4
- log4j
- log4j
- 1.2.17
-
-
-
- org.apache.wicket
- wicket-core
- 6.14.0
-
-
-
- org.apache.wicket
- wicket-auth-roles
- 6.14.0
-
-
- org.apache.wicket
- wicket-extensions
- 6.14.0
-
-
- org.apache.wicket
- wicket-cdi
- 6.14.0
-
-
- ro.isdc.wro4j
- wro4j-extensions
- 1.7.5
-
-
-
- com.wordnik
- swagger-annotations_2.9.1
- 1.2.5
-
-
- com.wordnik
- swagger-jaxrs_2.9.1
- 1.2.5
- provided
-
-
-
- com.codahale.metrics
- metrics-core
- 3.0.2
-
-
- com.codahale.metrics
- metrics-json
- 3.0.2
-
-
-
- org.webjars
- lodash
- 2.4.1-3
-
-
- org.webjars
- jquery
- 1.11.0
-
-
- org.webjars
- bootstrap
- 3.1.1
-
-
- org.webjars
- jquery-mousewheel
- 3.1.9
-
-
- org.webjars
- angularjs
- 1.2.16
-
-
- org.webjars
- angular-ui-router
- 0.2.8-2
-
-
- org.webjars
- angular-ui-utils
- 0.1.0
-
-
- org.webjars
- ui-select2
- 0.0.5
-
-
- org.webjars
- angular-ui-bootstrap
- 0.2.0
-
-
- org.webjars
- mousetrap
- 1.4.6
-
-
- org.webjars
- momentjs
- 2.6.0
-
-
- org.webjars
- ng-grid
- 2.0.7
-
-
- org.webjars
- device.js
- 139f208
-
-
- org.webjars
- ngInfiniteScroll
- 1.0.0
+ net.sourceforge.jtds
+ jtds
+ 1.3.1
@@ -466,228 +295,4 @@
test
-
-
-
- default
-
- true
-
-
-
-
- ro.isdc.wro4j
- wro4j-maven-plugin
- 1.7.5
-
-
- js
- test
-
- jshint
-
-
- app
- devel,noarg,quotmark,laxcomma,laxbreak
-
-
-
- css
- test
-
- csslint
-
-
- app
- display-property-grouping,duplicate-properties,compatible-vendor-prefixes,vendor-prefix
-
-
-
-
-
-
-
-
- openshift
-
- java:jboss/datasources/MysqlDS
- utf8
-
-
- commafeed
-
-
- maven-surefire-plugin
- 2.14.1
-
- true
-
-
-
- maven-war-plugin
- 2.4
-
- deployments
- ROOT
-
-
-
-
-
-
-
- cache
-
- true
-
-
-
- redis
-
- com.commafeed.backend.cache.RedisCacheService
-
-
-
- mysql
-
- java:openejb/Resource/MySQL
-
-
-
- pgsql
-
- java:openejb/Resource/PostgreSQL
-
-
-
- mssql
-
- java:openejb/Resource/MSSQL
-
-
-
- prod
-
-
- skipTests
-
-
-
- ${maven.build.timestamp}
- true
- false
-
-
-
-
- org.codehaus.gmaven
- gmaven-plugin
- 1.5
-
-
- commons-io
- commons-io
- 2.4
-
-
-
-
- process-classes
-
- execute
-
-
-
- ${basedir}/src/main/webapp/templates
- templates/
- ${basedir}/target/generated-sources/angularjs/all-templates.html
- ${basedir}/src/main/resources/i18n/
-
-
- ${basedir}/src/main/script
-
-
- def source = project.properties['source'];
- def prefix =
- project.properties['prefix'];
- def dest =
- project.properties['destination'];
- def i18n =
- project.properties['i18nPath'];
- new
- HTMLConcat().concat(source,
- prefix, dest, i18n);
-
-
-
-
-
-
- ro.isdc.wro4j
- wro4j-maven-plugin
- 1.7.5
-
-
-
- run
-
-
-
-
- all
- ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory
- ${project.build.directory}/${project.build.finalName}/static/
-
-
-
- maven-war-plugin
- 2.4
-
-
-
- target/generated-sources/angularjs/
- templates
-
- **/*.html
-
-
-
-
-
-
-
-
-
- i18n
-
-
-
- org.codehaus.gmaven
- gmaven-plugin
- 1.5
-
-
- commons-io
- commons-io
- 2.4
-
-
-
-
- ${basedir}/src/main/resources/i18n/
-
-
- ${basedir}/src/main/script
-
-
- def dir = project.properties['dir'];
- new
- I18nGenerator().generate(dir);
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/src/main/webapp/app-icon-114.png b/src/main/app/app-icon-114.png
similarity index 100%
rename from src/main/webapp/app-icon-114.png
rename to src/main/app/app-icon-114.png
diff --git a/src/main/webapp/app-icon-128.png b/src/main/app/app-icon-128.png
similarity index 100%
rename from src/main/webapp/app-icon-128.png
rename to src/main/app/app-icon-128.png
diff --git a/src/main/webapp/app-icon-144.png b/src/main/app/app-icon-144.png
similarity index 100%
rename from src/main/webapp/app-icon-144.png
rename to src/main/app/app-icon-144.png
diff --git a/src/main/webapp/app-icon-16.png b/src/main/app/app-icon-16.png
similarity index 100%
rename from src/main/webapp/app-icon-16.png
rename to src/main/app/app-icon-16.png
diff --git a/src/main/webapp/app-icon-195.png b/src/main/app/app-icon-195.png
similarity index 100%
rename from src/main/webapp/app-icon-195.png
rename to src/main/app/app-icon-195.png
diff --git a/src/main/webapp/app-icon-256.png b/src/main/app/app-icon-256.png
similarity index 100%
rename from src/main/webapp/app-icon-256.png
rename to src/main/app/app-icon-256.png
diff --git a/src/main/webapp/app-icon-32.png b/src/main/app/app-icon-32.png
similarity index 100%
rename from src/main/webapp/app-icon-32.png
rename to src/main/app/app-icon-32.png
diff --git a/src/main/webapp/app-icon-512.png b/src/main/app/app-icon-512.png
similarity index 100%
rename from src/main/webapp/app-icon-512.png
rename to src/main/app/app-icon-512.png
diff --git a/src/main/webapp/app-icon-57.png b/src/main/app/app-icon-57.png
similarity index 100%
rename from src/main/webapp/app-icon-57.png
rename to src/main/app/app-icon-57.png
diff --git a/src/main/webapp/app-icon-64.png b/src/main/app/app-icon-64.png
similarity index 100%
rename from src/main/webapp/app-icon-64.png
rename to src/main/app/app-icon-64.png
diff --git a/src/main/webapp/app-icon-72.png b/src/main/app/app-icon-72.png
similarity index 100%
rename from src/main/webapp/app-icon-72.png
rename to src/main/app/app-icon-72.png
diff --git a/src/main/webapp/app-icon.svg b/src/main/app/app-icon.svg
similarity index 100%
rename from src/main/webapp/app-icon.svg
rename to src/main/app/app-icon.svg
diff --git a/src/main/webapp/favicon.ico b/src/main/app/favicon.ico
similarity index 100%
rename from src/main/webapp/favicon.ico
rename to src/main/app/favicon.ico
diff --git a/src/main/webapp/images/default_favicon.gif b/src/main/app/images/default_favicon.gif
similarity index 100%
rename from src/main/webapp/images/default_favicon.gif
rename to src/main/app/images/default_favicon.gif
diff --git a/src/main/webapp/images/google_reader_icon.png b/src/main/app/images/google_reader_icon.png
similarity index 100%
rename from src/main/webapp/images/google_reader_icon.png
rename to src/main/app/images/google_reader_icon.png
diff --git a/src/main/webapp/images/logo.png b/src/main/app/images/logo.png
similarity index 100%
rename from src/main/webapp/images/logo.png
rename to src/main/app/images/logo.png
diff --git a/src/main/webapp/images/logo_2.png b/src/main/app/images/logo_2.png
similarity index 100%
rename from src/main/webapp/images/logo_2.png
rename to src/main/app/images/logo_2.png
diff --git a/src/main/webapp/images/preview.jpg b/src/main/app/images/preview.jpg
similarity index 100%
rename from src/main/webapp/images/preview.jpg
rename to src/main/app/images/preview.jpg
diff --git a/src/main/app/index.html b/src/main/app/index.html
new file mode 100644
index 00000000..0632ead8
--- /dev/null
+++ b/src/main/app/index.html
@@ -0,0 +1,73 @@
+
+
+
+CommaFeed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/webapp/js/controllers.js b/src/main/app/js/controllers.js
similarity index 96%
rename from src/main/webapp/js/controllers.js
rename to src/main/app/js/controllers.js
index 01d7e4e9..f7224f44 100644
--- a/src/main/webapp/js/controllers.js
+++ b/src/main/app/js/controllers.js
@@ -866,7 +866,6 @@ module.controller('FeedListCtrl', [
});
EntryService.mark({
id : entry.id,
- feedId : entry.feedId,
read : read
});
}
@@ -892,7 +891,6 @@ module.controller('FeedListCtrl', [
if (!e.read) {
entries.push({
id : e.id,
- feedId : e.feedId,
read : true
});
e.read = true;
diff --git a/src/main/webapp/js/directives.js b/src/main/app/js/directives.js
similarity index 100%
rename from src/main/webapp/js/directives.js
rename to src/main/app/js/directives.js
diff --git a/src/main/webapp/js/filters.js b/src/main/app/js/filters.js
similarity index 100%
rename from src/main/webapp/js/filters.js
rename to src/main/app/js/filters.js
diff --git a/src/main/webapp/js/main.js b/src/main/app/js/main.js
similarity index 100%
rename from src/main/webapp/js/main.js
rename to src/main/app/js/main.js
diff --git a/src/main/webapp/js/services.js b/src/main/app/js/services.js
similarity index 100%
rename from src/main/webapp/js/services.js
rename to src/main/app/js/services.js
diff --git a/src/main/webapp/js/welcome.js b/src/main/app/js/welcome.js
similarity index 100%
rename from src/main/webapp/js/welcome.js
rename to src/main/app/js/welcome.js
diff --git a/src/main/webapp/metro-icon-150.png b/src/main/app/metro-icon-150.png
similarity index 100%
rename from src/main/webapp/metro-icon-150.png
rename to src/main/app/metro-icon-150.png
diff --git a/src/main/webapp/metro-icon-70.png b/src/main/app/metro-icon-70.png
similarity index 100%
rename from src/main/webapp/metro-icon-70.png
rename to src/main/app/metro-icon-70.png
diff --git a/src/main/webapp/sass/app.scss b/src/main/app/sass/app.scss
similarity index 87%
rename from src/main/webapp/sass/app.scss
rename to src/main/app/sass/app.scss
index f4dec7b6..aaa20831 100644
--- a/src/main/webapp/sass/app.scss
+++ b/src/main/app/sass/app.scss
@@ -8,6 +8,9 @@
@import "components/help";
@import "components/loading-bar";
+@import "components/readabilicons";
+@import "components/zocial";
+
@import "mobile/mobile";
@import "themes/test";
diff --git a/deployments/.gitkeep b/src/main/app/sass/base/.gitkeep
similarity index 100%
rename from deployments/.gitkeep
rename to src/main/app/sass/base/.gitkeep
diff --git a/src/main/webapp/sass/components/_admin-panel.scss b/src/main/app/sass/components/_admin-panel.scss
similarity index 100%
rename from src/main/webapp/sass/components/_admin-panel.scss
rename to src/main/app/sass/components/_admin-panel.scss
diff --git a/src/main/webapp/sass/components/_entry-list.scss b/src/main/app/sass/components/_entry-list.scss
similarity index 100%
rename from src/main/webapp/sass/components/_entry-list.scss
rename to src/main/app/sass/components/_entry-list.scss
diff --git a/src/main/webapp/sass/components/_help.scss b/src/main/app/sass/components/_help.scss
similarity index 100%
rename from src/main/webapp/sass/components/_help.scss
rename to src/main/app/sass/components/_help.scss
diff --git a/src/main/webapp/sass/components/_loading-bar.scss b/src/main/app/sass/components/_loading-bar.scss
similarity index 100%
rename from src/main/webapp/sass/components/_loading-bar.scss
rename to src/main/app/sass/components/_loading-bar.scss
diff --git a/src/main/webapp/sass/components/_subscription-list.scss b/src/main/app/sass/components/_subscription-list.scss
similarity index 100%
rename from src/main/webapp/sass/components/_subscription-list.scss
rename to src/main/app/sass/components/_subscription-list.scss
diff --git a/src/main/webapp/sass/components/_toolbar.scss b/src/main/app/sass/components/_toolbar.scss
similarity index 100%
rename from src/main/webapp/sass/components/_toolbar.scss
rename to src/main/app/sass/components/_toolbar.scss
diff --git a/src/main/app/sass/components/readabilicons.scss b/src/main/app/sass/components/readabilicons.scss
new file mode 100644
index 00000000..5e65e7f6
--- /dev/null
+++ b/src/main/app/sass/components/readabilicons.scss
@@ -0,0 +1,20 @@
+@font-face {
+ font-family: 'readabilicons';
+ src: url('../font/readabilicons-regular.eot'); /* IE9 Compat Modes */
+ src: url('../font/readabilicons-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
+ url('../font/readabilicons-regular.woff') format('woff'), /* Modern Browsers */
+ url('../font/readabilicons-regular.ttf') format('truetype'), /* Safari, Android, iOS */
+ url('../font/readabilicons-regular.svg#readabiliconsregular') format('svg'); /* Legacy iOS */
+ font-style: normal;
+ font-weight: 400;
+}
+
+.icon-couch::before {
+ content: "\e018";
+ font-family: "readabilicons";
+ -webkit-font-smoothing: antialiased;
+ font-size: 21px;
+ top: 5px;
+ position: relative;
+ line-height: 0px;
+}
\ No newline at end of file
diff --git a/src/main/webapp/vendor/zocial/zocial.css b/src/main/app/sass/components/zocial.scss
similarity index 79%
rename from src/main/webapp/vendor/zocial/zocial.css
rename to src/main/app/sass/components/zocial.scss
index 724b2657..1583c85d 100644
--- a/src/main/webapp/vendor/zocial/zocial.css
+++ b/src/main/app/sass/components/zocial.scss
@@ -14,9 +14,9 @@
*/
@font-face {
font-family: 'zocial';
- src: url('zocial-regular-webfont.eot'),
- url('zocial-regular-webfont.woff'), url('zocial-regular-webfont.ttf')
- format('truetype'), url('zocial-regular-webfont.svg#zocialregular')
+ src: url('../font/zocial-regular-webfont.eot'),
+ url('../font/zocial-regular-webfont.woff'), url('../font/zocial-regular-webfont.ttf')
+ format('truetype'), url('../font/zocial-regular-webfont.svg#zocialregular')
format('svg');
font-weight: normal;
font-style: normal;
diff --git a/src/main/webapp/sass/generic/_misc.scss b/src/main/app/sass/generic/_misc.scss
similarity index 100%
rename from src/main/webapp/sass/generic/_misc.scss
rename to src/main/app/sass/generic/_misc.scss
diff --git a/src/main/webapp/sass/generic/_scrollbar.scss b/src/main/app/sass/generic/_scrollbar.scss
similarity index 100%
rename from src/main/webapp/sass/generic/_scrollbar.scss
rename to src/main/app/sass/generic/_scrollbar.scss
diff --git a/src/main/webapp/sass/mobile/_mobile.scss b/src/main/app/sass/mobile/_mobile.scss
similarity index 100%
rename from src/main/webapp/sass/mobile/_mobile.scss
rename to src/main/app/sass/mobile/_mobile.scss
diff --git a/src/main/webapp/sass/themes/_MRACHINI.scss b/src/main/app/sass/themes/_MRACHINI.scss
similarity index 100%
rename from src/main/webapp/sass/themes/_MRACHINI.scss
rename to src/main/app/sass/themes/_MRACHINI.scss
diff --git a/src/main/webapp/sass/themes/_bootstrap.scss b/src/main/app/sass/themes/_bootstrap.scss
similarity index 100%
rename from src/main/webapp/sass/themes/_bootstrap.scss
rename to src/main/app/sass/themes/_bootstrap.scss
diff --git a/src/main/webapp/sass/themes/_dark.scss b/src/main/app/sass/themes/_dark.scss
similarity index 100%
rename from src/main/webapp/sass/themes/_dark.scss
rename to src/main/app/sass/themes/_dark.scss
diff --git a/src/main/webapp/sass/themes/_ebraminio.scss b/src/main/app/sass/themes/_ebraminio.scss
similarity index 100%
rename from src/main/webapp/sass/themes/_ebraminio.scss
rename to src/main/app/sass/themes/_ebraminio.scss
diff --git a/src/main/webapp/sass/themes/_svetla.scss b/src/main/app/sass/themes/_svetla.scss
similarity index 100%
rename from src/main/webapp/sass/themes/_svetla.scss
rename to src/main/app/sass/themes/_svetla.scss
diff --git a/src/main/webapp/sass/themes/_test.scss b/src/main/app/sass/themes/_test.scss
similarity index 100%
rename from src/main/webapp/sass/themes/_test.scss
rename to src/main/app/sass/themes/_test.scss
diff --git a/src/main/webapp/sass/themes/_third.scss b/src/main/app/sass/themes/_third.scss
similarity index 100%
rename from src/main/webapp/sass/themes/_third.scss
rename to src/main/app/sass/themes/_third.scss
diff --git a/src/main/webapp/templates/_category.html b/src/main/app/templates/_category.html
similarity index 100%
rename from src/main/webapp/templates/_category.html
rename to src/main/app/templates/_category.html
diff --git a/src/main/webapp/templates/_feedsearch.html b/src/main/app/templates/_feedsearch.html
similarity index 100%
rename from src/main/webapp/templates/_feedsearch.html
rename to src/main/app/templates/_feedsearch.html
diff --git a/src/main/webapp/templates/_footer.html b/src/main/app/templates/_footer.html
similarity index 100%
rename from src/main/webapp/templates/_footer.html
rename to src/main/app/templates/_footer.html
diff --git a/src/main/webapp/templates/_metrics.gauge.html b/src/main/app/templates/_metrics.gauge.html
similarity index 100%
rename from src/main/webapp/templates/_metrics.gauge.html
rename to src/main/app/templates/_metrics.gauge.html
diff --git a/src/main/webapp/templates/_metrics.meter.html b/src/main/app/templates/_metrics.meter.html
similarity index 100%
rename from src/main/webapp/templates/_metrics.meter.html
rename to src/main/app/templates/_metrics.meter.html
diff --git a/src/main/webapp/templates/_shortcuts.html b/src/main/app/templates/_shortcuts.html
similarity index 100%
rename from src/main/webapp/templates/_shortcuts.html
rename to src/main/app/templates/_shortcuts.html
diff --git a/src/main/webapp/templates/_tags.html b/src/main/app/templates/_tags.html
similarity index 100%
rename from src/main/webapp/templates/_tags.html
rename to src/main/app/templates/_tags.html
diff --git a/src/main/webapp/templates/_toolbar.html b/src/main/app/templates/_toolbar.html
similarity index 100%
rename from src/main/webapp/templates/_toolbar.html
rename to src/main/app/templates/_toolbar.html
diff --git a/src/main/webapp/templates/_tree.html b/src/main/app/templates/_tree.html
similarity index 100%
rename from src/main/webapp/templates/_tree.html
rename to src/main/app/templates/_tree.html
diff --git a/src/main/webapp/templates/admin.html b/src/main/app/templates/admin.html
similarity index 100%
rename from src/main/webapp/templates/admin.html
rename to src/main/app/templates/admin.html
diff --git a/src/main/webapp/templates/admin.metrics.html b/src/main/app/templates/admin.metrics.html
similarity index 100%
rename from src/main/webapp/templates/admin.metrics.html
rename to src/main/app/templates/admin.metrics.html
diff --git a/src/main/webapp/templates/admin.settings.html b/src/main/app/templates/admin.settings.html
similarity index 100%
rename from src/main/webapp/templates/admin.settings.html
rename to src/main/app/templates/admin.settings.html
diff --git a/src/main/webapp/templates/admin.useradd.html b/src/main/app/templates/admin.useradd.html
similarity index 100%
rename from src/main/webapp/templates/admin.useradd.html
rename to src/main/app/templates/admin.useradd.html
diff --git a/src/main/webapp/templates/admin.useredit.html b/src/main/app/templates/admin.useredit.html
similarity index 100%
rename from src/main/webapp/templates/admin.useredit.html
rename to src/main/app/templates/admin.useredit.html
diff --git a/src/main/webapp/templates/admin.userlist.html b/src/main/app/templates/admin.userlist.html
similarity index 100%
rename from src/main/webapp/templates/admin.userlist.html
rename to src/main/app/templates/admin.userlist.html
diff --git a/src/main/webapp/templates/feeds.category_details.html b/src/main/app/templates/feeds.category_details.html
similarity index 100%
rename from src/main/webapp/templates/feeds.category_details.html
rename to src/main/app/templates/feeds.category_details.html
diff --git a/src/main/webapp/templates/feeds.feed_details.html b/src/main/app/templates/feeds.feed_details.html
similarity index 100%
rename from src/main/webapp/templates/feeds.feed_details.html
rename to src/main/app/templates/feeds.feed_details.html
diff --git a/src/main/webapp/templates/feeds.help.html b/src/main/app/templates/feeds.help.html
similarity index 100%
rename from src/main/webapp/templates/feeds.help.html
rename to src/main/app/templates/feeds.help.html
diff --git a/src/main/webapp/templates/feeds.html b/src/main/app/templates/feeds.html
similarity index 100%
rename from src/main/webapp/templates/feeds.html
rename to src/main/app/templates/feeds.html
diff --git a/src/main/webapp/templates/feeds.import.html b/src/main/app/templates/feeds.import.html
similarity index 100%
rename from src/main/webapp/templates/feeds.import.html
rename to src/main/app/templates/feeds.import.html
diff --git a/src/main/webapp/templates/feeds.new_category.html b/src/main/app/templates/feeds.new_category.html
similarity index 100%
rename from src/main/webapp/templates/feeds.new_category.html
rename to src/main/app/templates/feeds.new_category.html
diff --git a/src/main/webapp/templates/feeds.subscribe.html b/src/main/app/templates/feeds.subscribe.html
similarity index 100%
rename from src/main/webapp/templates/feeds.subscribe.html
rename to src/main/app/templates/feeds.subscribe.html
diff --git a/src/main/webapp/templates/feeds.tag_details.html b/src/main/app/templates/feeds.tag_details.html
similarity index 100%
rename from src/main/webapp/templates/feeds.tag_details.html
rename to src/main/app/templates/feeds.tag_details.html
diff --git a/src/main/webapp/templates/feeds.view.html b/src/main/app/templates/feeds.view.html
similarity index 100%
rename from src/main/webapp/templates/feeds.view.html
rename to src/main/app/templates/feeds.view.html
diff --git a/src/main/webapp/templates/profile.html b/src/main/app/templates/profile.html
similarity index 100%
rename from src/main/webapp/templates/profile.html
rename to src/main/app/templates/profile.html
diff --git a/src/main/webapp/templates/settings.html b/src/main/app/templates/settings.html
similarity index 100%
rename from src/main/webapp/templates/settings.html
rename to src/main/app/templates/settings.html
diff --git a/src/main/java/com/commafeed/CommaFeedApplication.java b/src/main/java/com/commafeed/CommaFeedApplication.java
new file mode 100644
index 00000000..b4a965a6
--- /dev/null
+++ b/src/main/java/com/commafeed/CommaFeedApplication.java
@@ -0,0 +1,182 @@
+package com.commafeed;
+
+import io.dropwizard.Application;
+import io.dropwizard.assets.AssetsBundle;
+import io.dropwizard.auth.CachingAuthenticator;
+import io.dropwizard.auth.basic.BasicAuthProvider;
+import io.dropwizard.auth.basic.BasicCredentials;
+import io.dropwizard.db.DataSourceFactory;
+import io.dropwizard.hibernate.HibernateBundle;
+import io.dropwizard.migrations.MigrationsBundle;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+
+import java.util.Date;
+
+import org.hibernate.SessionFactory;
+
+import com.codahale.metrics.MetricRegistry;
+import com.commafeed.backend.HttpGetter;
+import com.commafeed.backend.cache.CacheService;
+import com.commafeed.backend.cache.NoopCacheService;
+import com.commafeed.backend.dao.FeedCategoryDAO;
+import com.commafeed.backend.dao.FeedDAO;
+import com.commafeed.backend.dao.FeedEntryContentDAO;
+import com.commafeed.backend.dao.FeedEntryDAO;
+import com.commafeed.backend.dao.FeedEntryStatusDAO;
+import com.commafeed.backend.dao.FeedEntryTagDAO;
+import com.commafeed.backend.dao.FeedSubscriptionDAO;
+import com.commafeed.backend.dao.UserDAO;
+import com.commafeed.backend.dao.UserRoleDAO;
+import com.commafeed.backend.dao.UserSettingsDAO;
+import com.commafeed.backend.feed.FaviconFetcher;
+import com.commafeed.backend.feed.FeedFetcher;
+import com.commafeed.backend.feed.FeedParser;
+import com.commafeed.backend.feed.FeedQueues;
+import com.commafeed.backend.feed.FeedRefreshTaskGiver;
+import com.commafeed.backend.feed.FeedRefreshUpdater;
+import com.commafeed.backend.feed.FeedRefreshWorker;
+import com.commafeed.backend.model.AbstractModel;
+import com.commafeed.backend.model.Feed;
+import com.commafeed.backend.model.FeedCategory;
+import com.commafeed.backend.model.FeedEntry;
+import com.commafeed.backend.model.FeedEntryContent;
+import com.commafeed.backend.model.FeedEntryStatus;
+import com.commafeed.backend.model.FeedEntryTag;
+import com.commafeed.backend.model.FeedSubscription;
+import com.commafeed.backend.model.User;
+import com.commafeed.backend.model.UserRole;
+import com.commafeed.backend.model.UserSettings;
+import com.commafeed.backend.opml.OPMLExporter;
+import com.commafeed.backend.opml.OPMLImporter;
+import com.commafeed.backend.service.ApplicationPropertiesService;
+import com.commafeed.backend.service.DatabaseCleaningService;
+import com.commafeed.backend.service.FeedEntryContentService;
+import com.commafeed.backend.service.FeedEntryService;
+import com.commafeed.backend.service.FeedEntryTagService;
+import com.commafeed.backend.service.FeedService;
+import com.commafeed.backend.service.FeedSubscriptionService;
+import com.commafeed.backend.service.FeedUpdateService;
+import com.commafeed.backend.service.PasswordEncryptionService;
+import com.commafeed.backend.service.PubSubService;
+import com.commafeed.backend.service.StartupService;
+import com.commafeed.backend.service.UserService;
+import com.commafeed.frontend.resource.AdminREST;
+import com.commafeed.frontend.resource.CategoryREST;
+import com.commafeed.frontend.resource.EntryREST;
+import com.commafeed.frontend.resource.FeedREST;
+import com.commafeed.frontend.resource.PubSubHubbubCallbackREST;
+import com.commafeed.frontend.resource.ServerREST;
+import com.commafeed.frontend.resource.UserREST;
+
+public class CommaFeedApplication extends Application {
+
+ public static final String USERNAME_ADMIN = "admin";
+ public static final String USERNAME_DEMO = "demo";
+
+ public static final Date STARTUP_TIME = new Date();
+
+ private HibernateBundle hibernateBundle;
+ private MigrationsBundle migrationsBundle;
+
+ @Override
+ public void initialize(Bootstrap bootstrap) {
+ hibernateBundle = new HibernateBundle(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class,
+ FeedEntryContent.class, FeedEntryStatus.class, FeedEntryTag.class, FeedSubscription.class, User.class, UserRole.class,
+ UserSettings.class) {
+ @Override
+ public DataSourceFactory getDataSourceFactory(CommaFeedConfiguration configuration) {
+ return configuration.getDatabase();
+ }
+ };
+ bootstrap.addBundle(hibernateBundle);
+
+ migrationsBundle = new MigrationsBundle() {
+ @Override
+ public DataSourceFactory getDataSourceFactory(CommaFeedConfiguration configuration) {
+ return configuration.getDatabase();
+ }
+ };
+ bootstrap.addBundle(migrationsBundle);
+
+ bootstrap.addBundle(new AssetsBundle("/assets/", "/", "index.html"));
+ }
+
+ @Override
+ public void run(CommaFeedConfiguration config, Environment environment) throws Exception {
+ MetricRegistry metrics = environment.metrics();
+ SessionFactory sessionFactory = hibernateBundle.getSessionFactory();
+
+ // TODO select cache service at runtime from config
+ CacheService cacheService = new NoopCacheService();
+
+ FeedCategoryDAO feedCategoryDAO = new FeedCategoryDAO(sessionFactory);
+ FeedDAO feedDAO = new FeedDAO(sessionFactory);
+ FeedEntryContentDAO feedEntryContentDAO = new FeedEntryContentDAO(sessionFactory);
+ FeedEntryDAO feedEntryDAO = new FeedEntryDAO(sessionFactory);
+ FeedEntryTagDAO feedEntryTagDAO = new FeedEntryTagDAO(sessionFactory);
+ FeedSubscriptionDAO feedSubscriptionDAO = new FeedSubscriptionDAO(sessionFactory);
+ UserDAO userDAO = new UserDAO(sessionFactory);
+ UserRoleDAO userRoleDAO = new UserRoleDAO(sessionFactory);
+ UserSettingsDAO userSettingsDAO = new UserSettingsDAO(sessionFactory);
+ FeedEntryStatusDAO feedEntryStatusDAO = new FeedEntryStatusDAO(sessionFactory, feedEntryDAO, feedEntryTagDAO, config);
+
+ FeedQueues queues = new FeedQueues(feedDAO, config, metrics);
+
+ ApplicationPropertiesService applicationPropertiesService = new ApplicationPropertiesService();
+ DatabaseCleaningService cleaningService = new DatabaseCleaningService(feedDAO, feedEntryDAO, feedEntryContentDAO,
+ feedEntryStatusDAO, feedSubscriptionDAO);
+ FeedEntryContentService feedEntryContentService = new FeedEntryContentService(feedEntryContentDAO);
+ FeedEntryService feedEntryService = new FeedEntryService(feedSubscriptionDAO, feedEntryDAO, feedEntryStatusDAO, cacheService);
+ FeedEntryTagService feedEntryTagService = new FeedEntryTagService(feedEntryDAO, feedEntryTagDAO);
+ FeedService feedService = new FeedService(feedDAO);
+ FeedSubscriptionService feedSubscriptionService = new FeedSubscriptionService(feedEntryStatusDAO, feedSubscriptionDAO, feedService,
+ queues, cacheService, config);
+ FeedUpdateService feedUpdateService = new FeedUpdateService(feedEntryDAO, feedEntryContentService);
+ PasswordEncryptionService encryptionService = new PasswordEncryptionService();
+ PubSubService pubSubService = new PubSubService(config, queues);
+ UserService userService = new UserService(feedCategoryDAO, userDAO, userSettingsDAO, feedSubscriptionService, encryptionService,
+ config);
+ StartupService startupService = new StartupService(sessionFactory, userDAO, userService);
+
+ OPMLImporter opmlImporter = new OPMLImporter(feedCategoryDAO, feedSubscriptionService, cacheService);
+ OPMLExporter opmlExporter = new OPMLExporter(feedCategoryDAO, feedSubscriptionDAO);
+
+ HttpGetter httpGetter = new HttpGetter();
+ FeedParser feedParser = new FeedParser();
+ FaviconFetcher faviconFetcher = new FaviconFetcher(httpGetter);
+
+ FeedFetcher feedFetcher = new FeedFetcher(feedParser, httpGetter);
+ FeedRefreshUpdater feedUpdater = new FeedRefreshUpdater(sessionFactory, feedUpdateService, pubSubService, queues, config, metrics,
+ feedSubscriptionDAO, cacheService);
+ FeedRefreshWorker feedWorker = new FeedRefreshWorker(feedUpdater, feedFetcher, queues, config, metrics);
+ FeedRefreshTaskGiver taskGiver = new FeedRefreshTaskGiver(sessionFactory, queues, feedDAO, feedWorker, config, metrics);
+
+ CachingAuthenticator cachingAuthenticator = new CachingAuthenticator(
+ environment.metrics(), new CommaFeedAuthenticator(userService), config.getAuthenticationCachePolicy());
+ environment.jersey().register(new BasicAuthProvider(cachingAuthenticator, "CommaFeed"));
+
+ environment.jersey().setUrlPattern("/rest/*");
+ environment.jersey()
+ .register(new AdminREST(userDAO, userRoleDAO, userService, encryptionService, cleaningService, config, metrics));
+ environment.jersey().register(
+ new CategoryREST(feedCategoryDAO, feedEntryStatusDAO, feedSubscriptionDAO, feedEntryService, feedSubscriptionService,
+ cacheService, config));
+ environment.jersey().register(new EntryREST(feedEntryTagDAO, feedEntryService, feedEntryTagService));
+ environment.jersey().register(
+ new FeedREST(feedSubscriptionDAO, feedCategoryDAO, feedEntryStatusDAO, faviconFetcher, feedFetcher, feedEntryService,
+ feedSubscriptionService, queues, opmlImporter, opmlExporter, cacheService, config));
+ environment.jersey().register(new PubSubHubbubCallbackREST(feedDAO, feedParser, queues, config, metrics));
+ environment.jersey().register(new ServerREST(httpGetter, config, applicationPropertiesService));
+ environment.jersey().register(new UserREST(userDAO, userRoleDAO, userSettingsDAO, userService, encryptionService));
+
+ environment.lifecycle().manage(startupService);
+ environment.lifecycle().manage(taskGiver);
+ environment.lifecycle().manage(feedWorker);
+ environment.lifecycle().manage(feedUpdater);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new CommaFeedApplication().run(args);
+ }
+}
diff --git a/src/main/java/com/commafeed/CommaFeedAuthenticator.java b/src/main/java/com/commafeed/CommaFeedAuthenticator.java
new file mode 100644
index 00000000..4c729e17
--- /dev/null
+++ b/src/main/java/com/commafeed/CommaFeedAuthenticator.java
@@ -0,0 +1,21 @@
+package com.commafeed;
+
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicCredentials;
+import lombok.RequiredArgsConstructor;
+
+import com.commafeed.backend.model.User;
+import com.commafeed.backend.service.UserService;
+import com.google.common.base.Optional;
+
+@RequiredArgsConstructor
+public class CommaFeedAuthenticator implements Authenticator {
+
+ private final UserService userService;
+
+ @Override
+ public Optional authenticate(final BasicCredentials credentials) throws AuthenticationException {
+ return Optional.fromNullable(userService.login(credentials.getUsername(), credentials.getPassword()));
+ }
+}
diff --git a/src/main/java/com/commafeed/CommaFeedConfiguration.java b/src/main/java/com/commafeed/CommaFeedConfiguration.java
new file mode 100644
index 00000000..c71394ea
--- /dev/null
+++ b/src/main/java/com/commafeed/CommaFeedConfiguration.java
@@ -0,0 +1,105 @@
+package com.commafeed;
+
+import io.dropwizard.Configuration;
+import io.dropwizard.db.DataSourceFactory;
+
+import java.util.Date;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+import lombok.Getter;
+
+import org.apache.commons.lang.time.DateUtils;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.cache.CacheBuilderSpec;
+
+@Getter
+public class CommaFeedConfiguration extends Configuration {
+
+ @Valid
+ @NotNull
+ @JsonProperty("database")
+ private DataSourceFactory database = new DataSourceFactory();
+
+ @Valid
+ @NotNull
+ @JsonProperty("authenticationCachePolicy")
+ private CacheBuilderSpec authenticationCachePolicy;
+
+ @Valid
+ @NotNull
+ @JsonProperty("app")
+ private ApplicationSettings applicationSettings;
+
+ @Getter
+ public static class ApplicationSettings {
+ @JsonProperty
+ private String publicUrl;
+
+ @JsonProperty
+ private boolean allowRegistrations;
+
+ @JsonProperty
+ private String googleAnalyticsTrackingCode;
+
+ @JsonProperty
+ private String googleClientId;
+
+ @JsonProperty
+ private String googleClientSecret;
+
+ @JsonProperty
+ private int backgroundThreads;
+
+ @JsonProperty
+ private int databaseUpdateThreads;
+
+ @JsonProperty
+ private String smtpHost;
+
+ @JsonProperty
+ private int smtpPort;
+
+ @JsonProperty
+ private boolean smtpTls;
+
+ @JsonProperty
+ private String smtpUserName;
+
+ @JsonProperty
+ private String smtpPassword;
+
+ @JsonProperty
+ private boolean heavyLoad;
+
+ @JsonProperty
+ private boolean pubsubhubbub;
+
+ @JsonProperty
+ private boolean imageProxyEnabled;
+
+ @JsonProperty
+ private int queryTimeout;
+
+ @JsonProperty
+ private boolean crawlingPaused;
+
+ @JsonProperty
+ private int keepStatusDays;
+
+ @JsonProperty
+ private int refreshIntervalMinutes;
+
+ @JsonProperty
+ private String announcement;
+
+ public Date getUnreadThreshold() {
+ int keepStatusDays = getKeepStatusDays();
+ return keepStatusDays > 0 ? DateUtils.addDays(new Date(), -1 * keepStatusDays) : null;
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/commafeed/backend/HttpGetter.java b/src/main/java/com/commafeed/backend/HttpGetter.java
index f28e5813..23627321 100644
--- a/src/main/java/com/commafeed/backend/HttpGetter.java
+++ b/src/main/java/com/commafeed/backend/HttpGetter.java
@@ -15,6 +15,7 @@ import javax.net.ssl.X509TrustManager;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
@@ -42,7 +43,6 @@ import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
-import org.apache.wicket.util.io.IOUtils;
/**
* Smart HTTP getter: handles gzip, ssl, last modified and etag headers
diff --git a/src/main/java/com/commafeed/backend/ScheduledTasks.java b/src/main/java/com/commafeed/backend/ScheduledTasks.java
deleted file mode 100644
index d784585b..00000000
--- a/src/main/java/com/commafeed/backend/ScheduledTasks.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.commafeed.backend;
-
-import java.util.Date;
-
-import javax.ejb.Schedule;
-import javax.ejb.Stateless;
-import javax.ejb.TransactionManagement;
-import javax.ejb.TransactionManagementType;
-import javax.inject.Inject;
-
-import com.commafeed.backend.services.ApplicationSettingsService;
-import com.commafeed.backend.services.DatabaseCleaningService;
-
-/**
- * Contains all scheduled tasks
- *
- */
-@Stateless
-@TransactionManagement(TransactionManagementType.BEAN)
-public class ScheduledTasks {
-
- @Inject
- ApplicationSettingsService applicationSettingsService;
-
- @Inject
- DatabaseCleaningService cleaner;
-
- /**
- * clean old read statuses
- */
- @Schedule(hour = "*", persistent = false)
- private void cleanupOldStatuses() {
- Date threshold = applicationSettingsService.getUnreadThreshold();
- if (threshold != null) {
- cleaner.cleanStatusesOlderThan(threshold);
- }
- }
-
- /**
- * clean feeds without subscriptions, then clean contents without entries
- */
- @Schedule(hour = "*", persistent = false)
- private void cleanFeedsAndContents() {
- cleaner.cleanEntriesWithoutSubscriptions();
- cleaner.cleanFeedsWithoutSubscriptions();
- cleaner.cleanContentsWithoutEntries();
- }
-}
diff --git a/src/main/java/com/commafeed/backend/cache/NoopCacheService.java b/src/main/java/com/commafeed/backend/cache/NoopCacheService.java
index e8755090..4741f5ec 100644
--- a/src/main/java/com/commafeed/backend/cache/NoopCacheService.java
+++ b/src/main/java/com/commafeed/backend/cache/NoopCacheService.java
@@ -3,17 +3,12 @@ package com.commafeed.backend.cache;
import java.util.Collections;
import java.util.List;
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.inject.Alternative;
-
import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.User;
import com.commafeed.frontend.model.Category;
import com.commafeed.frontend.model.UnreadCount;
-@Alternative
-@ApplicationScoped
public class NoopCacheService extends CacheService {
@Override
diff --git a/src/main/java/com/commafeed/backend/cache/RedisCacheService.java b/src/main/java/com/commafeed/backend/cache/RedisCacheService.java
index 348671a6..2a50a6b2 100644
--- a/src/main/java/com/commafeed/backend/cache/RedisCacheService.java
+++ b/src/main/java/com/commafeed/backend/cache/RedisCacheService.java
@@ -4,13 +4,10 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import javax.annotation.PostConstruct;
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.inject.Alternative;
+import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool.impl.GenericObjectPool;
-import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@@ -26,8 +23,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
-@Alternative
-@ApplicationScoped
@Slf4j
public class RedisCacheService extends CacheService {
@@ -35,8 +30,7 @@ public class RedisCacheService extends CacheService {
private JedisPool pool;
- @PostConstruct
- private void init() {
+ public RedisCacheService() {
JedisPoolConfig config = new JedisPoolConfig();
config.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW);
pool = new JedisPool(config, "localhost");
diff --git a/src/main/java/com/commafeed/backend/dao/ApplicationSettingsDAO.java b/src/main/java/com/commafeed/backend/dao/ApplicationSettingsDAO.java
deleted file mode 100644
index 97b69973..00000000
--- a/src/main/java/com/commafeed/backend/dao/ApplicationSettingsDAO.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.commafeed.backend.dao;
-
-import javax.ejb.Stateless;
-
-import com.commafeed.backend.model.ApplicationSettings;
-
-@Stateless
-public class ApplicationSettingsDAO extends GenericDAO {
-
-}
diff --git a/src/main/java/com/commafeed/backend/dao/FeedCategoryDAO.java b/src/main/java/com/commafeed/backend/dao/FeedCategoryDAO.java
index 62a2d8bf..7e26201c 100644
--- a/src/main/java/com/commafeed/backend/dao/FeedCategoryDAO.java
+++ b/src/main/java/com/commafeed/backend/dao/FeedCategoryDAO.java
@@ -2,91 +2,50 @@ package com.commafeed.backend.dao;
import java.util.List;
-import javax.ejb.Stateless;
-import javax.persistence.NoResultException;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Join;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-
import org.apache.commons.lang.ObjectUtils;
+import org.hibernate.SessionFactory;
import com.commafeed.backend.model.FeedCategory;
-import com.commafeed.backend.model.FeedCategory_;
+import com.commafeed.backend.model.QFeedCategory;
+import com.commafeed.backend.model.QUser;
import com.commafeed.backend.model.User;
-import com.commafeed.backend.model.User_;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import com.mysema.query.types.Predicate;
-@Stateless
public class FeedCategoryDAO extends GenericDAO {
- @SuppressWarnings("unchecked")
+ private QFeedCategory category = QFeedCategory.feedCategory;
+
+ public FeedCategoryDAO(SessionFactory sessionFactory) {
+ super(sessionFactory);
+ }
+
public List findAll(User user) {
-
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
- Join userJoin = (Join) root.fetch(FeedCategory_.user);
-
- query.where(builder.equal(userJoin.get(User_.id), user.getId()));
-
- return cache(em.createQuery(query)).getResultList();
+ return newQuery().from(category).where(category.user.eq(user)).join(category.user, QUser.user).fetch().list(category);
}
public FeedCategory findById(User user, Long id) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- Predicate p1 = builder.equal(root.get(FeedCategory_.user).get(User_.id), user.getId());
- Predicate p2 = builder.equal(root.get(FeedCategory_.id), id);
-
- query.where(p1, p2);
-
- return Iterables.getFirst(cache(em.createQuery(query)).getResultList(), null);
+ return newQuery().from(category).where(category.user.eq(user), category.id.eq(id)).uniqueResult(category);
}
public FeedCategory findByName(User user, String name, FeedCategory parent) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- List predicates = Lists.newArrayList();
-
- predicates.add(builder.equal(root.get(FeedCategory_.user), user));
- predicates.add(builder.equal(root.get(FeedCategory_.name), name));
-
+ Predicate parentPredicate = null;
if (parent == null) {
- predicates.add(builder.isNull(root.get(FeedCategory_.parent)));
+ parentPredicate = category.parent.isNull();
} else {
- predicates.add(builder.equal(root.get(FeedCategory_.parent), parent));
+ parentPredicate = category.parent.eq(parent);
}
-
- query.where(predicates.toArray(new Predicate[0]));
-
- FeedCategory category = null;
- try {
- category = em.createQuery(query).getSingleResult();
- } catch (NoResultException e) {
- category = null;
- }
- return category;
+ return newQuery().from(category).where(category.user.eq(user), category.name.eq(name), parentPredicate).uniqueResult(category);
}
public List findByParent(User user, FeedCategory parent) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- List predicates = Lists.newArrayList();
-
- predicates.add(builder.equal(root.get(FeedCategory_.user), user));
+ Predicate parentPredicate = null;
if (parent == null) {
- predicates.add(builder.isNull(root.get(FeedCategory_.parent)));
+ parentPredicate = category.parent.isNull();
} else {
- predicates.add(builder.equal(root.get(FeedCategory_.parent), parent));
+ parentPredicate = category.parent.eq(parent);
}
-
- query.where(predicates.toArray(new Predicate[0]));
-
- return em.createQuery(query).getResultList();
+ return newQuery().from(category).where(category.user.eq(user), parentPredicate).list(category);
}
public List findAllChildrenCategories(User user, FeedCategory parent) {
diff --git a/src/main/java/com/commafeed/backend/dao/FeedDAO.java b/src/main/java/com/commafeed/backend/dao/FeedDAO.java
index bf2d1254..1afe2b27 100644
--- a/src/main/java/com/commafeed/backend/dao/FeedDAO.java
+++ b/src/main/java/com/commafeed/backend/dao/FeedDAO.java
@@ -3,104 +3,75 @@ package com.commafeed.backend.dao;
import java.util.Date;
import java.util.List;
-import javax.ejb.Stateless;
-import javax.persistence.TypedQuery;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Join;
-import javax.persistence.criteria.JoinType;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.SetJoin;
-import javax.persistence.criteria.Subquery;
-
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
+import org.hibernate.SessionFactory;
-import com.commafeed.backend.feeds.FeedUtils;
import com.commafeed.backend.model.Feed;
-import com.commafeed.backend.model.FeedSubscription;
-import com.commafeed.backend.model.FeedSubscription_;
-import com.commafeed.backend.model.Feed_;
-import com.commafeed.backend.model.User;
-import com.commafeed.backend.model.User_;
+import com.commafeed.backend.model.QFeed;
+import com.commafeed.backend.model.QFeedSubscription;
+import com.commafeed.backend.model.QUser;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
+import com.mysema.query.BooleanBuilder;
+import com.mysema.query.jpa.hibernate.HibernateQuery;
+import com.mysema.query.jpa.hibernate.HibernateSubQuery;
-@Stateless
public class FeedDAO extends GenericDAO {
- private List getUpdatablePredicates(CriteriaQuery> query, Root root, Date lastLoginThreshold) {
+ private QFeed feed = QFeed.feed;
- List preds = Lists.newArrayList();
- Predicate isNull = builder.isNull(root.get(Feed_.disabledUntil));
- Predicate lessThan = builder.lessThan(root.get(Feed_.disabledUntil), new Date());
- preds.add(builder.or(isNull, lessThan));
-
- if (lastLoginThreshold != null) {
- Subquery subquery = query.subquery(Long.class);
- Root subroot = subquery.from(FeedSubscription.class);
- subquery.select(builder.count(subroot.get(FeedSubscription_.id)));
-
- Join userJoin = subroot.join(FeedSubscription_.user);
- Predicate p1 = builder.equal(subroot.get(FeedSubscription_.feed), root);
- Predicate p2 = builder.greaterThanOrEqualTo(userJoin.get(User_.lastLogin), lastLoginThreshold);
- subquery.where(p1, p2);
-
- preds.add(builder.exists(subquery));
- }
-
- return preds;
+ public FeedDAO(SessionFactory sessionFactory) {
+ super(sessionFactory);
}
public Long getUpdatableCount(Date lastLoginThreshold) {
- CriteriaQuery query = builder.createQuery(Long.class);
- Root root = query.from(getType());
+ BooleanBuilder disabledDatePredicate = new BooleanBuilder();
+ disabledDatePredicate.or(feed.disabledUntil.isNull());
+ disabledDatePredicate.or(feed.disabledUntil.lt(new Date()));
- query.select(builder.count(root));
- query.where(getUpdatablePredicates(query, root, lastLoginThreshold).toArray(new Predicate[0]));
-
- TypedQuery q = em.createQuery(query);
- return q.getSingleResult();
+ HibernateQuery query = newQuery().from(feed).where(disabledDatePredicate);
+ if (lastLoginThreshold != null) {
+ QFeedSubscription sub = QFeedSubscription.feedSubscription;
+ QUser user = QUser.user;
+ HibernateSubQuery subquery = new HibernateSubQuery();
+ subquery.from(sub).join(sub.user, user).where(sub.feed.eq(feed), user.lastLogin.gt(lastLoginThreshold));
+ query.where(subquery.exists());
+ }
+ return query.orderBy(feed.disabledUntil.asc()).count();
}
public List findNextUpdatable(int count, Date lastLoginThreshold) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
+ BooleanBuilder disabledDatePredicate = new BooleanBuilder();
+ disabledDatePredicate.or(feed.disabledUntil.isNull());
+ disabledDatePredicate.or(feed.disabledUntil.lt(new Date()));
- query.where(getUpdatablePredicates(query, root, lastLoginThreshold).toArray(new Predicate[0]));
- query.orderBy(builder.asc(root.get(Feed_.disabledUntil)));
-
- TypedQuery q = em.createQuery(query);
- q.setMaxResults(count);
-
- return q.getResultList();
- }
-
- public Feed findByUrl(String url) {
-
- String normalized = FeedUtils.normalizeURL(url);
- List feeds = findByField(Feed_.normalizedUrlHash, DigestUtils.sha1Hex(normalized));
- Feed feed = Iterables.getFirst(feeds, null);
- if (feed != null && StringUtils.equals(normalized, feed.getNormalizedUrl())) {
- return feed;
+ HibernateQuery query = newQuery().from(feed).where(disabledDatePredicate);
+ if (lastLoginThreshold != null) {
+ QFeedSubscription sub = QFeedSubscription.feedSubscription;
+ QUser user = QUser.user;
+ HibernateSubQuery subquery = new HibernateSubQuery();
+ subquery.from(sub).join(sub.user, user).where(sub.feed.eq(feed), user.lastLogin.gt(lastLoginThreshold));
+ query.where(subquery.exists());
}
+ return query.orderBy(feed.disabledUntil.asc()).limit(count).list(feed);
+ }
+
+ public Feed findByUrl(String normalizedUrl) {
+ List feeds = newQuery().from(feed).where(feed.normalizedUrlHash.eq(DigestUtils.sha1Hex(normalizedUrl))).list(feed);
+ Feed feed = Iterables.getFirst(feeds, null);
+ if (feed != null && StringUtils.equals(normalizedUrl, feed.getNormalizedUrl())) {
+ return feed;
+ }
return null;
}
public List findByTopic(String topic) {
- return findByField(Feed_.pushTopicHash, DigestUtils.sha1Hex(topic));
+ return newQuery().from(feed).where(feed.pushTopicHash.eq(DigestUtils.sha1Hex(topic))).list(feed);
}
-
+
public List findWithoutSubscriptions(int max) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- SetJoin join = root.join(Feed_.subscriptions, JoinType.LEFT);
- query.where(builder.isNull(join.get(FeedSubscription_.id)));
- TypedQuery q = em.createQuery(query);
- q.setMaxResults(max);
-
- return q.getResultList();
+ QFeedSubscription sub = QFeedSubscription.feedSubscription;
+ return newQuery().from(feed).leftJoin(feed.subscriptions, sub).where(sub.id.isNull()).limit(max).list(feed);
}
}
diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryContentDAO.java b/src/main/java/com/commafeed/backend/dao/FeedEntryContentDAO.java
index 99f46e60..07250ef8 100644
--- a/src/main/java/com/commafeed/backend/dao/FeedEntryContentDAO.java
+++ b/src/main/java/com/commafeed/backend/dao/FeedEntryContentDAO.java
@@ -2,52 +2,34 @@ package com.commafeed.backend.dao;
import java.util.List;
-import javax.ejb.Stateless;
-import javax.persistence.TypedQuery;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Join;
-import javax.persistence.criteria.JoinType;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
+import org.hibernate.SessionFactory;
-import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.FeedEntryContent;
-import com.commafeed.backend.model.FeedEntryContent_;
-import com.commafeed.backend.model.FeedEntry_;
+import com.commafeed.backend.model.QFeedEntry;
+import com.commafeed.backend.model.QFeedEntryContent;
import com.google.common.collect.Iterables;
+import com.mysema.query.types.ConstructorExpression;
-@Stateless
public class FeedEntryContentDAO extends GenericDAO {
+ private QFeedEntryContent content = QFeedEntryContent.feedEntryContent;
+
+ public FeedEntryContentDAO(SessionFactory sessionFactory) {
+ super(sessionFactory);
+ }
+
public Long findExisting(String contentHash, String titleHash) {
-
- CriteriaQuery query = builder.createQuery(Long.class);
- Root root = query.from(getType());
- query.select(root.get(FeedEntryContent_.id));
-
- Predicate p1 = builder.equal(root.get(FeedEntryContent_.contentHash), contentHash);
- Predicate p2 = builder.equal(root.get(FeedEntryContent_.titleHash), titleHash);
-
- query.where(p1, p2);
- TypedQuery q = em.createQuery(query);
- limit(q, 0, 1);
- return Iterables.getFirst(q.getResultList(), null);
-
+ List list = newQuery().from(content).where(content.contentHash.eq(contentHash), content.titleHash.eq(titleHash)).limit(1)
+ .list(ConstructorExpression.create(Long.class, content.id));
+ return Iterables.getFirst(list, null);
}
public int deleteWithoutEntries(int max) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- Join join = root.join(FeedEntryContent_.entries, JoinType.LEFT);
- query.where(builder.isNull(join.get(FeedEntry_.id)));
- TypedQuery q = em.createQuery(query);
- q.setMaxResults(max);
-
- List list = q.getResultList();
+ QFeedEntry entry = QFeedEntry.feedEntry;
+ List list = newQuery().from(content).leftJoin(content.entries, entry).where(entry.id.isNull()).limit(max)
+ .list(content);
int deleted = list.size();
delete(list);
return deleted;
-
}
}
diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java b/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java
index e457e962..8b98dc0b 100644
--- a/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java
+++ b/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java
@@ -3,82 +3,47 @@ package com.commafeed.backend.dao;
import java.util.Date;
import java.util.List;
-import javax.ejb.Stateless;
-import javax.persistence.TypedQuery;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Join;
-import javax.persistence.criteria.JoinType;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.SetJoin;
-
import org.apache.commons.codec.digest.DigestUtils;
+import org.hibernate.SessionFactory;
import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedEntry;
-import com.commafeed.backend.model.FeedEntry_;
-import com.commafeed.backend.model.FeedSubscription;
-import com.commafeed.backend.model.FeedSubscription_;
-import com.commafeed.backend.model.Feed_;
+import com.commafeed.backend.model.QFeed;
+import com.commafeed.backend.model.QFeedEntry;
+import com.commafeed.backend.model.QFeedSubscription;
import com.google.common.collect.Iterables;
+import com.mysema.query.types.ConstructorExpression;
-@Stateless
public class FeedEntryDAO extends GenericDAO {
- public Long findExisting(String guid, Long feedId) {
+ private QFeedEntry entry = QFeedEntry.feedEntry;
- CriteriaQuery query = builder.createQuery(Long.class);
- Root root = query.from(getType());
- query.select(root.get(FeedEntry_.id));
+ public FeedEntryDAO(SessionFactory sessionFactory) {
+ super(sessionFactory);
+ }
- Predicate p1 = builder.equal(root.get(FeedEntry_.guidHash), DigestUtils.sha1Hex(guid));
- Predicate p2 = builder.equal(root.get(FeedEntry_.feed).get(Feed_.id), feedId);
-
- query.where(p1, p2);
-
- TypedQuery q = em.createQuery(query);
- limit(q, 0, 1);
- List list = q.getResultList();
+ public Long findExisting(String guid, Feed feed) {
+ List list = newQuery().from(entry).where(entry.guidHash.eq(DigestUtils.sha1Hex(guid)), entry.feed.eq(feed)).limit(1)
+ .list(ConstructorExpression.create(Long.class, entry.id));
return Iterables.getFirst(list, null);
}
public List findWithoutSubscriptions(int max) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- Join feedJoin = root.join(FeedEntry_.feed);
- SetJoin subJoin = feedJoin.join(Feed_.subscriptions, JoinType.LEFT);
- query.where(builder.isNull(subJoin.get(FeedSubscription_.id)));
- TypedQuery q = em.createQuery(query);
- q.setMaxResults(max);
-
- return q.getResultList();
+ QFeed feed = QFeed.feed;
+ QFeedSubscription sub = QFeedSubscription.feedSubscription;
+ return newQuery().from(entry).join(entry.feed, feed).leftJoin(feed.subscriptions, sub).where(sub.id.isNull()).limit(max)
+ .list(entry);
}
public int delete(Feed feed, int max) {
-
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- query.where(builder.equal(root.get(FeedEntry_.feed), feed));
- TypedQuery q = em.createQuery(query);
- q.setMaxResults(max);
-
- List list = q.getResultList();
+ List list = newQuery().from(entry).where(entry.feed.eq(feed)).limit(max).list(entry);
int deleted = list.size();
delete(list);
return deleted;
}
public int delete(Date olderThan, int max) {
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
- query.where(builder.lessThan(root.get(FeedEntry_.inserted), olderThan));
-
- TypedQuery q = em.createQuery(query);
- q.setMaxResults(max);
- List list = q.getResultList();
-
+ List list = newQuery().from(entry).where(entry.inserted.lt(olderThan)).limit(max).list(entry);
int deleted = list.size();
delete(list);
return deleted;
diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java
index 12780b6f..3f7fc7ec 100644
--- a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java
+++ b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java
@@ -5,18 +5,10 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
-import javax.ejb.Stateless;
-import javax.inject.Inject;
-import javax.persistence.Query;
-import javax.persistence.TypedQuery;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Path;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-
import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.builder.CompareToBuilder;
+import org.apache.commons.lang.builder.CompareToBuilder;
import org.hibernate.Criteria;
+import org.hibernate.SessionFactory;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
@@ -27,33 +19,44 @@ import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.hibernate.transform.Transformers;
+import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.FixedSizeSortedSet;
import com.commafeed.backend.model.FeedEntry;
-import com.commafeed.backend.model.FeedEntryContent_;
import com.commafeed.backend.model.FeedEntryStatus;
-import com.commafeed.backend.model.FeedEntryStatus_;
import com.commafeed.backend.model.FeedEntryTag;
-import com.commafeed.backend.model.FeedEntryTag_;
-import com.commafeed.backend.model.FeedEntry_;
import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.Models;
+import com.commafeed.backend.model.QFeedEntry;
+import com.commafeed.backend.model.QFeedEntryContent;
+import com.commafeed.backend.model.QFeedEntryStatus;
+import com.commafeed.backend.model.QFeedEntryTag;
import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserSettings.ReadingOrder;
-import com.commafeed.backend.services.ApplicationSettingsService;
import com.commafeed.frontend.model.UnreadCount;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
+import com.mysema.query.jpa.hibernate.HibernateQuery;
-@Stateless
public class FeedEntryStatusDAO extends GenericDAO {
private static final String ALIAS_STATUS = "status";
private static final String ALIAS_ENTRY = "entry";
private static final String ALIAS_TAG = "tag";
- @Inject
- FeedEntryTagDAO feedEntryTagDAO;
+ private FeedEntryDAO feedEntryDAO;
+ private FeedEntryTagDAO feedEntryTagDAO;
+ private CommaFeedConfiguration config;
+
+ private QFeedEntryStatus status = QFeedEntryStatus.feedEntryStatus;
+
+ public FeedEntryStatusDAO(SessionFactory sessionFactory, FeedEntryDAO feedEntryDAO, FeedEntryTagDAO feedEntryTagDAO,
+ CommaFeedConfiguration config) {
+ super(sessionFactory);
+ this.feedEntryDAO = feedEntryDAO;
+ this.feedEntryTagDAO = feedEntryTagDAO;
+ this.config = config;
+ }
private static final Comparator STATUS_COMPARATOR_DESC = new Comparator() {
@Override
@@ -61,34 +64,21 @@ public class FeedEntryStatusDAO extends GenericDAO {
CompareToBuilder builder = new CompareToBuilder();
builder.append(o2.getEntryUpdated(), o1.getEntryUpdated());
builder.append(o2.getId(), o1.getId());
- return builder.build();
+ return builder.toComparison();
};
};
private static final Comparator STATUS_COMPARATOR_ASC = Ordering.from(STATUS_COMPARATOR_DESC).reverse();
- @Inject
- ApplicationSettingsService applicationSettingsService;
-
public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) {
-
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- Predicate p1 = builder.equal(root.get(FeedEntryStatus_.entry), entry);
- Predicate p2 = builder.equal(root.get(FeedEntryStatus_.subscription), sub);
-
- query.where(p1, p2);
-
- List statuses = em.createQuery(query).getResultList();
+ List statuses = newQuery().from(status).where(status.entry.eq(entry), status.subscription.eq(sub)).list(status);
FeedEntryStatus status = Iterables.getFirst(statuses, null);
-
return handleStatus(user, status, sub, entry);
}
private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) {
if (status == null) {
- Date unreadThreshold = applicationSettingsService.getUnreadThreshold();
+ Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
boolean read = unreadThreshold == null ? false : entry.getUpdated().before(unreadThreshold);
status = new FeedEntryStatus(user, sub, entry);
status.setRead(read);
@@ -106,27 +96,20 @@ public class FeedEntryStatusDAO extends GenericDAO {
}
public List findStarred(User user, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent) {
-
- CriteriaQuery query = builder.createQuery(getType());
- Root root = query.from(getType());
-
- List predicates = Lists.newArrayList();
-
- predicates.add(builder.equal(root.get(FeedEntryStatus_.user), user));
- predicates.add(builder.equal(root.get(FeedEntryStatus_.starred), true));
-
+ HibernateQuery query = newQuery().from(status).where(status.user.eq(user), status.starred.isTrue());
if (newerThan != null) {
- predicates.add(builder.greaterThanOrEqualTo(root.get(FeedEntryStatus_.entryInserted), newerThan));
+ query.where(status.entryInserted.gt(newerThan));
}
-
- query.where(predicates.toArray(new Predicate[0]));
- orderStatusesBy(query, root, order);
+ if (order == ReadingOrder.asc) {
+ query.orderBy(status.entryUpdated.asc(), status.id.asc());
+ } else {
+ query.orderBy(status.entryUpdated.desc(), status.id.desc());
+ }
- TypedQuery q = em.createQuery(query);
- limit(q, offset, limit);
- setTimeout(q);
- List statuses = q.getResultList();
+ query.offset(offset).limit(limit).setTimeout(config.getApplicationSettings().getQueryTimeout());
+
+ List statuses = query.list(status);
for (FeedEntryStatus status : statuses) {
status = handleStatus(user, status, status.getSubscription(), status.getEntry());
status = fetchTags(user, status);
@@ -134,62 +117,66 @@ public class FeedEntryStatusDAO extends GenericDAO {
return lazyLoadContent(includeContent, statuses);
}
- private Criteria buildSearchCriteria(User user, FeedSubscription sub, boolean unreadOnly, String keywords, Date newerThan, int offset, int limit,
- ReadingOrder order, Date last, String tag) {
- Criteria criteria = getSession().createCriteria(FeedEntry.class, ALIAS_ENTRY);
+ private Criteria buildSearchCriteria(User user, FeedSubscription sub, boolean unreadOnly, String keywords, Date newerThan, int offset,
+ int limit, ReadingOrder order, Date last, String tag) {
+ QFeedEntry entry = QFeedEntry.feedEntry;
+ QFeedEntryContent content = QFeedEntryContent.feedEntryContent;
+ QFeedEntryStatus status = QFeedEntryStatus.feedEntryStatus;
+ QFeedEntryTag entryTag = QFeedEntryTag.feedEntryTag;
- criteria.add(Restrictions.eq(FeedEntry_.feed.getName(), sub.getFeed()));
+ Criteria criteria = currentSession().createCriteria(FeedEntry.class, ALIAS_ENTRY);
+ criteria.add(Restrictions.eq(entry.feed.getMetadata().getName(), sub.getFeed()));
if (keywords != null) {
- Criteria contentJoin = criteria.createCriteria(FeedEntry_.content.getName(), "content", JoinType.INNER_JOIN);
+ Criteria contentJoin = criteria.createCriteria(entry.content.getMetadata().getName(), "content", JoinType.INNER_JOIN);
for (String keyword : StringUtils.split(keywords)) {
Disjunction or = Restrictions.disjunction();
- or.add(Restrictions.ilike(FeedEntryContent_.content.getName(), keyword, MatchMode.ANYWHERE));
- or.add(Restrictions.ilike(FeedEntryContent_.title.getName(), keyword, MatchMode.ANYWHERE));
+ or.add(Restrictions.ilike(content.content.getMetadata().getName(), keyword, MatchMode.ANYWHERE));
+ or.add(Restrictions.ilike(content.title.getMetadata().getName(), keyword, MatchMode.ANYWHERE));
contentJoin.add(or);
}
}
- Criteria statusJoin = criteria.createCriteria(FeedEntry_.statuses.getName(), ALIAS_STATUS, JoinType.LEFT_OUTER_JOIN,
- Restrictions.eq(FeedEntryStatus_.subscription.getName(), sub));
+ Criteria statusJoin = criteria.createCriteria(entry.statuses.getMetadata().getName(), ALIAS_STATUS, JoinType.LEFT_OUTER_JOIN,
+ Restrictions.eq(status.subscription.getMetadata().getName(), sub));
if (unreadOnly && tag == null) {
Disjunction or = Restrictions.disjunction();
- or.add(Restrictions.isNull(FeedEntryStatus_.read.getName()));
- or.add(Restrictions.eq(FeedEntryStatus_.read.getName(), false));
+ or.add(Restrictions.isNull(status.read.getMetadata().getName()));
+ or.add(Restrictions.eq(status.read.getMetadata().getName(), false));
statusJoin.add(or);
- Date unreadThreshold = applicationSettingsService.getUnreadThreshold();
+ Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
if (unreadThreshold != null) {
- criteria.add(Restrictions.ge(FeedEntry_.updated.getName(), unreadThreshold));
+ criteria.add(Restrictions.ge(entry.updated.getMetadata().getName(), unreadThreshold));
}
}
if (tag != null) {
Conjunction and = Restrictions.conjunction();
- and.add(Restrictions.eq(FeedEntryTag_.user.getName(), user));
- and.add(Restrictions.eq(FeedEntryTag_.name.getName(), tag));
- criteria.createCriteria(FeedEntry_.tags.getName(), ALIAS_TAG, JoinType.INNER_JOIN, and);
+ and.add(Restrictions.eq(entryTag.user.getMetadata().getName(), user));
+ and.add(Restrictions.eq(entryTag.name.getMetadata().getName(), tag));
+ criteria.createCriteria(entry.tags.getMetadata().getName(), ALIAS_TAG, JoinType.INNER_JOIN, and);
}
if (newerThan != null) {
- criteria.add(Restrictions.ge(FeedEntry_.inserted.getName(), newerThan));
+ criteria.add(Restrictions.ge(entry.inserted.getMetadata().getName(), newerThan));
}
if (last != null) {
if (order == ReadingOrder.desc) {
- criteria.add(Restrictions.gt(FeedEntry_.updated.getName(), last));
+ criteria.add(Restrictions.gt(entry.updated.getMetadata().getName(), last));
} else {
- criteria.add(Restrictions.lt(FeedEntry_.updated.getName(), last));
+ criteria.add(Restrictions.lt(entry.updated.getMetadata().getName(), last));
}
}
if (order != null) {
if (order == ReadingOrder.asc) {
- criteria.addOrder(Order.asc(FeedEntry_.updated.getName())).addOrder(Order.asc(FeedEntry_.id.getName()));
+ criteria.addOrder(Order.asc(entry.updated.getMetadata().getName())).addOrder(Order.asc(entry.id.getMetadata().getName()));
} else {
- criteria.addOrder(Order.desc(FeedEntry_.updated.getName())).addOrder(Order.desc(FeedEntry_.id.getName()));
+ criteria.addOrder(Order.desc(entry.updated.getMetadata().getName())).addOrder(Order.desc(entry.id.getMetadata().getName()));
}
}
if (offset > -1) {
@@ -198,7 +185,7 @@ public class FeedEntryStatusDAO extends GenericDAO {
if (limit > -1) {
criteria.setMaxResults(limit);
}
- int timeout = applicationSettingsService.get().getQueryTimeout();
+ int timeout = config.getApplicationSettings().getQueryTimeout();
if (timeout > 0) {
// hibernate timeout is in seconds, jpa timeout is in millis
criteria.setTimeout(timeout / 1000);
@@ -255,7 +242,7 @@ public class FeedEntryStatusDAO extends GenericDAO {
statuses = Lists.newArrayList();
for (FeedEntryStatus placeholder : placeholders) {
Long statusId = placeholder.getId();
- FeedEntry entry = em.find(FeedEntry.class, placeholder.getEntry().getId());
+ FeedEntry entry = feedEntryDAO.findById(placeholder.getEntry().getId());
FeedEntryStatus status = handleStatus(user, statusId == null ? null : findById(statusId), placeholder.getSubscription(),
entry);
status = fetchTags(user, status);
@@ -272,7 +259,7 @@ public class FeedEntryStatusDAO extends GenericDAO {
Criteria criteria = buildSearchCriteria(user, subscription, true, null, null, -1, -1, null, null, null);
ProjectionList projection = Projections.projectionList();
projection.add(Projections.rowCount(), "count");
- projection.add(Projections.max(FeedEntry_.updated.getName()), "updated");
+ projection.add(Projections.max(QFeedEntry.feedEntry.updated.getMetadata().getName()), "updated");
criteria.setProjection(projection);
criteria.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List