forked from Archives/Athou_commafeed
Compare commits
169 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
969da0f2a6 | ||
|
|
2061b68a2f | ||
|
|
443dea5055 | ||
|
|
a4c6365ede | ||
|
|
c9c044386e | ||
|
|
2744f8285c | ||
|
|
7bf5f20b06 | ||
|
|
b43aa84c2a | ||
|
|
dd27d88309 | ||
|
|
8dc36a72b2 | ||
|
|
d3ca301675 | ||
|
|
43e3469e63 | ||
|
|
cdc3dc6740 | ||
|
|
6fba8b61e7 | ||
|
|
b34594a1dc | ||
|
|
19964d253e | ||
|
|
165f3ed25a | ||
|
|
5058290103 | ||
|
|
358a6029a1 | ||
|
|
fa4bfa729d | ||
|
|
9c9e43cf46 | ||
|
|
b7e5bd0144 | ||
|
|
58dc6f5832 | ||
|
|
f409af1c37 | ||
|
|
9e0c94f1a4 | ||
|
|
3794d61a77 | ||
|
|
d22da54d53 | ||
|
|
8e34c44e0d | ||
|
|
b71434acf6 | ||
|
|
7e158ed9b9 | ||
|
|
2ec0d067f3 | ||
|
|
effc65b777 | ||
|
|
c48e248283 | ||
|
|
f9e9a4547c | ||
|
|
63e35aba6d | ||
|
|
8f852fb9ac | ||
|
|
bf6a13b43f | ||
|
|
12030f6ce9 | ||
|
|
07da878bba | ||
|
|
8d5c3bdec8 | ||
|
|
ce95772afa | ||
|
|
b9f27b2b00 | ||
|
|
0059cabebe | ||
|
|
326ee79c8c | ||
|
|
54cc265ee6 | ||
|
|
e38778b4d0 | ||
|
|
6152d3c14a | ||
|
|
8a172170ea | ||
|
|
64b5d64709 | ||
|
|
67d7315003 | ||
|
|
47da4a2a1a | ||
|
|
174be9c2d1 | ||
|
|
9b68539322 | ||
|
|
2a4660ffa6 | ||
|
|
dce0cf7ee4 | ||
|
|
d6c39d4aba | ||
|
|
fd7e183f40 | ||
|
|
bf78a80f29 | ||
|
|
0ff630b8bd | ||
|
|
49b9e3f278 | ||
|
|
a4cc65c6a4 | ||
|
|
0b46187ac5 | ||
|
|
14ef5af936 | ||
|
|
539d9c6d0e | ||
|
|
56bcc5ef5e | ||
|
|
d6b0324e24 | ||
|
|
ff044e2592 | ||
|
|
3c7747ab97 | ||
|
|
34d97221ed | ||
|
|
84e78d34cd | ||
|
|
ac73806aee | ||
|
|
2105e9a5c9 | ||
|
|
2a36cc4327 | ||
|
|
c3feaf9a15 | ||
|
|
d8537a98aa | ||
|
|
42a6001ba5 | ||
|
|
4d9eb35230 | ||
|
|
e4ac296a1f | ||
|
|
01b49e7864 | ||
|
|
bd0b85a8d2 | ||
|
|
3d59a4c516 | ||
|
|
08ceff0f03 | ||
|
|
d6ae88ac43 | ||
|
|
5c8f016dd6 | ||
|
|
17288017d8 | ||
|
|
1e2757b52f | ||
|
|
0dce2f057e | ||
|
|
e017c5c304 | ||
|
|
a3e828f90a | ||
|
|
74e5c24fdc | ||
|
|
76c0abaa22 | ||
|
|
a52b5fd711 | ||
|
|
ffa51406b6 | ||
|
|
0b3b267e63 | ||
|
|
fcdb9d8257 | ||
|
|
04943ca525 | ||
|
|
574d4a1223 | ||
|
|
7349814cb2 | ||
|
|
114c5eb356 | ||
|
|
191f861f6e | ||
|
|
fac1fcc3a6 | ||
|
|
d0490c5eb5 | ||
|
|
2673efa9fc | ||
|
|
d4bce7b0a1 | ||
|
|
ba4a7ce6ab | ||
|
|
58f10153ab | ||
|
|
e7b65e3f26 | ||
|
|
fe91473748 | ||
|
|
0140402ad4 | ||
|
|
f56cba59ae | ||
|
|
fed74f05fc | ||
|
|
0888f11257 | ||
|
|
7205d5bb9c | ||
|
|
17a5ef882f | ||
|
|
ea68dbc56f | ||
|
|
0cec8af074 | ||
|
|
f7d0fc5768 | ||
|
|
bcaab694c8 | ||
|
|
247a3d5ab3 | ||
|
|
8e262a1e10 | ||
|
|
f63695bdc7 | ||
|
|
b051613b62 | ||
|
|
b886379d34 | ||
|
|
2a780dd2bb | ||
|
|
9cf7b80110 | ||
|
|
8fee73f1d1 | ||
|
|
36edb9373b | ||
|
|
374c4b265a | ||
|
|
db0b685ae1 | ||
|
|
23d33b8402 | ||
|
|
8a57be3e63 | ||
|
|
823cb03f9b | ||
|
|
e96cbcb057 | ||
|
|
fa0e7bcb54 | ||
|
|
20292a7742 | ||
|
|
943bde7eed | ||
|
|
9701af0736 | ||
|
|
1456cc40e1 | ||
|
|
dc1f88c44c | ||
|
|
55c916956f | ||
|
|
51eda57618 | ||
|
|
d6a55e1ec0 | ||
|
|
b78210421c | ||
|
|
1324269f1d | ||
|
|
cda6cb5cc0 | ||
|
|
c1b8619b26 | ||
|
|
4203e25321 | ||
|
|
aa02c7b93a | ||
|
|
0ff477579b | ||
|
|
62a8e8c119 | ||
|
|
fa212e0911 | ||
|
|
c8ad902a60 | ||
|
|
f05515d7d6 | ||
|
|
95bbcce941 | ||
|
|
d6b98f1518 | ||
|
|
bd9b1b11c5 | ||
|
|
e4c4960972 | ||
|
|
2a26031261 | ||
|
|
1d6e212955 | ||
|
|
9fa3743d21 | ||
|
|
7b373c79d9 | ||
|
|
4e9266e2d5 | ||
|
|
ea957e297c | ||
|
|
9320b6beb8 | ||
|
|
1319bf4a8c | ||
|
|
78b1ec6e6a | ||
|
|
6d4cbb889d | ||
|
|
27d16265d6 | ||
|
|
9888e23cd9 |
3
.openshift/README.md
Normal file
3
.openshift/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
For information about .openshift directory, consult the documentation:
|
||||
|
||||
http://openshift.github.io/documentation/oo_user_guide.html#the-openshift-directory
|
||||
3
.openshift/action_hooks/README.md
Normal file
3
.openshift/action_hooks/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
For information about action hooks, consult the documentation:
|
||||
|
||||
http://openshift.github.io/documentation/oo_user_guide.html#action-hooks
|
||||
22
.openshift/action_hooks/build
Executable file
22
.openshift/action_hooks/build
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
cd $OPENSHIFT_REPO_DIR
|
||||
|
||||
rm -rf $OPENSHIFT_REPO_DIR/node
|
||||
rm -rf $OPENSHIFT_REPO_DIR/node_modules
|
||||
rm -rf $OPENSHIFT_TMP_DIR/npm
|
||||
rm -rf $OPENSHIFT_TMP_DIR/npmrc
|
||||
rm -rf $OPENSHIFT_TMP_DIR/m2
|
||||
rm -rf $OPENSHIFT_TMP_DIR/local
|
||||
|
||||
export NPM_CONFIG_PREFIX="$OPENSHIFT_TMP_DIR/npm"
|
||||
export NPM_CONFIG_USERCONFIG="$OPENSHIFT_TMP_DIR/npmrc"
|
||||
export NPM_CONFIG_CACHE="$OPENSHIFT_TMP_DIR/npm/cache"
|
||||
export MAVEN_OPTS="-Dmaven.repo.local=$OPENSHIFT_TMP_DIR/m2"
|
||||
export HOME="$OPENSHIFT_TMP_DIR/local"
|
||||
|
||||
export NPM_CONFIG_ARCH="x64"
|
||||
|
||||
npm install npm
|
||||
export PATH="$OPENSHIFT_REPO_DIR/node_modules/.bin:$PATH"
|
||||
|
||||
mvn clean package -DskipTests -Dos.arch=x64
|
||||
9
.openshift/action_hooks/deploy
Executable file
9
.openshift/action_hooks/deploy
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
cd $OPENSHIFT_REPO_DIR
|
||||
sed -i 's/@OPENSHIFT_DIY_IP@/'"$OPENSHIFT_DIY_IP"'/g' .openshift/config.mysql.yml
|
||||
sed -i 's/@OPENSHIFT_DIY_PORT@/'"$OPENSHIFT_DIY_PORT"'/g' .openshift/config.mysql.yml
|
||||
sed -i 's/@OPENSHIFT_APP_DNS@/'"$OPENSHIFT_APP_DNS"'/g' .openshift/config.mysql.yml
|
||||
sed -i 's/@OPENSHIFT_APP_NAME@/'"$OPENSHIFT_APP_NAME"'/g' .openshift/config.mysql.yml
|
||||
sed -i 's/@OPENSHIFT_MYSQL_DB_HOST@/'"$OPENSHIFT_MYSQL_DB_HOST"'/g' .openshift/config.mysql.yml
|
||||
sed -i 's/@OPENSHIFT_MYSQL_DB_USERNAME@/'"$OPENSHIFT_MYSQL_DB_USERNAME"'/g' .openshift/config.mysql.yml
|
||||
sed -i 's/@OPENSHIFT_MYSQL_DB_PASSWORD@/'"$OPENSHIFT_MYSQL_DB_PASSWORD"'/g' .openshift/config.mysql.yml
|
||||
3
.openshift/action_hooks/start
Executable file
3
.openshift/action_hooks/start
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd $OPENSHIFT_REPO_DIR
|
||||
nohup java -jar target/commafeed.jar server .openshift/config.mysql.yml > ${OPENSHIFT_DIY_LOG_DIR}/commafeed.log 2>&1 &
|
||||
8
.openshift/action_hooks/stop
Executable file
8
.openshift/action_hooks/stop
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
source $OPENSHIFT_CARTRIDGE_SDK_BASH
|
||||
if [ -z "$(ps -ef | grep commafeed.jar | grep -v grep)" ]
|
||||
then
|
||||
client_result "Application is already stopped"
|
||||
else
|
||||
kill `ps -ef | grep commafeed.jar | grep -v grep | awk '{ print $2 }'` > /dev/null 2>&1
|
||||
fi
|
||||
107
.openshift/config.mysql.yml
Normal file
107
.openshift/config.mysql.yml
Normal file
@@ -0,0 +1,107 @@
|
||||
# CommaFeed settings
|
||||
# ------------------
|
||||
app:
|
||||
# context path of the application
|
||||
contextPath: /
|
||||
|
||||
# url used to access commafeed
|
||||
publicUrl: https://@OPENSHIFT_APP_DNS@/
|
||||
|
||||
# wether to allow user registrations
|
||||
allowRegistrations: false
|
||||
|
||||
# put your google analytics tracking code here
|
||||
googleAnalyticsTrackingCode:
|
||||
|
||||
# number of http threads
|
||||
backgroundThreads: 3
|
||||
|
||||
# number of database updating threads
|
||||
databaseUpdateThreads: 1
|
||||
|
||||
# settings for sending emails (password recovery)
|
||||
smtpHost:
|
||||
smtpPort:
|
||||
smtpTls: false
|
||||
smtpUserName:
|
||||
smtpPassword:
|
||||
|
||||
# wether this commafeed instance has a lot of feeds to refresh
|
||||
# leave this to false in almost all cases
|
||||
heavyLoad: false
|
||||
|
||||
# minimum amount of time commafeed will wait before refreshing the same feed
|
||||
refreshIntervalMinutes: 15
|
||||
|
||||
# wether to enable pubsub
|
||||
# probably not needed if refreshIntervalMinutes is low
|
||||
pubsubhubbub: false
|
||||
|
||||
# if enabled, images in feed entries will be proxied through the server instead of accessed directly by the browser
|
||||
# useful if commafeed is usually accessed through a restricting proxy
|
||||
imageProxyEnabled: false
|
||||
|
||||
# database query timeout (in milliseconds), 0 to disable
|
||||
queryTimeout: 0
|
||||
|
||||
# time to keep unread statuses (in days), 0 to disable
|
||||
keepStatusDays: 0
|
||||
|
||||
# cache service to use, possible values are 'noop' and 'redis'
|
||||
cache: noop
|
||||
|
||||
# announcement string displayed on the main page
|
||||
announcement:
|
||||
|
||||
# Database connection
|
||||
# -------------------
|
||||
# for MySQL
|
||||
# driverClass is com.mysql.jdbc.Driver
|
||||
# url is jdbc:mysql://localhost/commafeed?autoReconnect=true&failOverReadOnly=false&maxReconnects=20&rewriteBatchedStatements=true
|
||||
#
|
||||
# for PostgreSQL
|
||||
# driverClass is org.postgresql.Driver
|
||||
# url is jdbc:postgresql://localhost:5432/commafeed
|
||||
#
|
||||
# for Microsoft SQL Server
|
||||
# driverClass is net.sourceforge.jtds.jdbc.Driver
|
||||
# url is jdbc:jtds:sqlserver://localhost:1433/commafeed;instance=<instanceName, remove if not needed>
|
||||
|
||||
database:
|
||||
driverClass: com.mysql.jdbc.Driver
|
||||
url: jdbc:mysql://@OPENSHIFT_MYSQL_DB_HOST@/@OPENSHIFT_APP_NAME@?autoReconnect=true&failOverReadOnly=false&maxReconnects=20&rewriteBatchedStatements=true
|
||||
user: @OPENSHIFT_MYSQL_DB_USERNAME@
|
||||
password: @OPENSHIFT_MYSQL_DB_PASSWORD@
|
||||
properties:
|
||||
charSet: UTF-8
|
||||
maxWaitForConnection: 1s
|
||||
validationQuery: "/* CommaFeed Health Check */ SELECT 1"
|
||||
minSize: 1
|
||||
maxSize: 50
|
||||
checkConnectionWhileIdle: true
|
||||
maxConnectionAge: 30m
|
||||
|
||||
server:
|
||||
applicationConnectors:
|
||||
- type: http
|
||||
port: @OPENSHIFT_DIY_PORT@
|
||||
bindHost: @OPENSHIFT_DIY_IP@
|
||||
adminConnectors:
|
||||
- type: http
|
||||
port: 15000
|
||||
bindHost: @OPENSHIFT_DIY_IP@
|
||||
logging:
|
||||
level: WARN
|
||||
loggers:
|
||||
com.commafeed: INFO
|
||||
liquibase: INFO
|
||||
io.dropwizard.server.ServerFactory: INFO
|
||||
appenders:
|
||||
- type: console
|
||||
- type: file
|
||||
currentLogFilename: log/commafeed.log
|
||||
threshold: ALL
|
||||
archive: true
|
||||
archivedLogFilenamePattern: log/commafeed-%d.log
|
||||
archivedFileCount: 5
|
||||
timeZone: UTC
|
||||
0
.openshift/cron/daily/.gitignore
vendored
Normal file
0
.openshift/cron/daily/.gitignore
vendored
Normal file
0
.openshift/cron/hourly/.gitignore
vendored
Normal file
0
.openshift/cron/hourly/.gitignore
vendored
Normal file
0
.openshift/cron/minutely/.gitignore
vendored
Normal file
0
.openshift/cron/minutely/.gitignore
vendored
Normal file
0
.openshift/cron/monthly/.gitignore
vendored
Normal file
0
.openshift/cron/monthly/.gitignore
vendored
Normal file
16
.openshift/cron/weekly/README
Normal file
16
.openshift/cron/weekly/README
Normal file
@@ -0,0 +1,16 @@
|
||||
Run scripts or jobs on a weekly basis
|
||||
=====================================
|
||||
Any scripts or jobs added to this directory will be run on a scheduled basis
|
||||
(weekly) using run-parts.
|
||||
|
||||
run-parts ignores any files that are hidden or dotfiles (.*) or backup
|
||||
files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles
|
||||
the files named jobs.deny and jobs.allow specially.
|
||||
|
||||
In this specific example, the chronograph script is the only script or job file
|
||||
executed on a weekly basis (due to white-listing it in jobs.allow). And the
|
||||
README and chrono.dat file are ignored either as a result of being black-listed
|
||||
in jobs.deny or because they are NOT white-listed in the jobs.allow file.
|
||||
|
||||
For more details, please see ../README.cron file.
|
||||
|
||||
1
.openshift/cron/weekly/chrono.dat
Normal file
1
.openshift/cron/weekly/chrono.dat
Normal file
@@ -0,0 +1 @@
|
||||
Time And Relative D...n In Execution (Open)Shift!
|
||||
3
.openshift/cron/weekly/chronograph
Executable file
3
.openshift/cron/weekly/chronograph
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "`date`: `cat $(dirname \"$0\")/chrono.dat`"
|
||||
12
.openshift/cron/weekly/jobs.allow
Normal file
12
.openshift/cron/weekly/jobs.allow
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# Script or job files listed in here (one entry per line) will be
|
||||
# executed on a weekly-basis.
|
||||
#
|
||||
# Example: The chronograph script will be executed weekly but the README
|
||||
# and chrono.dat files in this directory will be ignored.
|
||||
#
|
||||
# The README file is actually ignored due to the entry in the
|
||||
# jobs.deny which is checked before jobs.allow (this file).
|
||||
#
|
||||
chronograph
|
||||
|
||||
7
.openshift/cron/weekly/jobs.deny
Normal file
7
.openshift/cron/weekly/jobs.deny
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Any script or job files listed in here (one entry per line) will NOT be
|
||||
# executed (read as ignored by run-parts).
|
||||
#
|
||||
|
||||
README
|
||||
|
||||
3
.openshift/markers/README.md
Normal file
3
.openshift/markers/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
For information about markers, consult the documentation:
|
||||
|
||||
http://openshift.github.io/documentation/oo_user_guide.html#markers
|
||||
3
.openshift/settings.xml
Normal file
3
.openshift/settings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<settings>
|
||||
<localRepository>$OPENSHIFT_DATA_DIR</localRepository>
|
||||
</settings>
|
||||
5
.travis.yml
Normal file
5
.travis.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
language: java
|
||||
jdk:
|
||||
- openjdk7
|
||||
- oraclejdk7
|
||||
- oraclejdk8
|
||||
26
CHANGELOG
Normal file
26
CHANGELOG
Normal file
@@ -0,0 +1,26 @@
|
||||
v 2.0.3
|
||||
- internet explorer ajax cache workaround
|
||||
- categories are now deletable again
|
||||
- openshift support is back
|
||||
- youtube feeds now show user favicon instead of youtube favicon
|
||||
v 2.0.2
|
||||
- api using the api key is now working again
|
||||
- context path is now configurable in config.yml (see app.contextPath in config.yml.example)
|
||||
- fix login on firefox when fields are autofilled by the browser
|
||||
- fix scrolling of subscriptions list on mobile
|
||||
- user is now logged in after registration
|
||||
- fix link to documentation on home page and about page
|
||||
- fields autocomplete is disabled on the profile page
|
||||
- users are able to delete their account again
|
||||
- chinese and malaysian translation files are now correctly loaded
|
||||
- software version in user-agent when fetching feeds is no longer hardcoded
|
||||
- admin settings page is now read only, settings are configured in config.yml
|
||||
- added link to metrics on the admin settings page
|
||||
- Rome (rss library) upgrade to 1.5.0
|
||||
v 2.0.1
|
||||
- the redis pool no longer throws an exception when it is unable to aquire a new connection
|
||||
v2.0.0
|
||||
- The backend has been completely rewritten using Dropwizard instead of TomEE, resulting in a lot less memory consumption and better overall performances.
|
||||
See the README on how to build CommaFeed from now on.
|
||||
- CommaFeed should no longer fetch the same feed multiple times in a row
|
||||
- Users can use their username or email to log in
|
||||
208
README.md
208
README.md
@@ -1,90 +1,118 @@
|
||||
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 Dropwizard and AngularJS.
|
||||
|
||||
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 your own server
|
||||
-----------------------------
|
||||
|
||||
CommaFeed 2.0 has been rewritten to use Dropwizard and gulp instead of using tomee and wro4j. The latest version of the 1.x branch is available [here](https://github.com/Athou/commafeed/tree/1.x).
|
||||
|
||||
For storage, you can either use an embedded H2 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.
|
||||
|
||||
Clone this repository. 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
|
||||
|
||||
mvn clean package
|
||||
|
||||
Copy `config.yml.example` to `config.yml` then edit the file to your liking.
|
||||
Issue the following command to run the app, the server will listen by default on ``http://localhost:8082`. The default user is `admin` and the default password is `admin`.
|
||||
|
||||
java -jar target/commafeed.jar server config.yml
|
||||
|
||||
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
|
||||
-----------------
|
||||
|
||||
To start the dropwizard backend, use your IDE to run CommaFeedApplication as your main class, and pass `server config.dev.yml` as arguments to the program.
|
||||
To start the client-side webserver with watches on assets, run `gulp dev`. The server is now running on port 8082 and is proxying REST requests to dropwizard on port 8083.
|
||||
|
||||
|
||||
Translate CommaFeed into your language
|
||||
--------------------------------------
|
||||
|
||||
Files for internationalization are located [here](https://github.com/Athou/commafeed/tree/master/src/main/app/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 `src/main/app/js/i18n.js` file to be picked up.
|
||||
|
||||
Themes
|
||||
---------------------
|
||||
|
||||
To create a theme, create a new file `src/main/webapp/sass/themes/_<theme>.scss`. Your styles should be wrapped in a `#theme-<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-2014 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.
|
||||
CommaFeed [](https://travis-ci.org/Athou/commafeed)
|
||||
=========
|
||||
Sources for [CommaFeed.com](http://www.commafeed.com/).
|
||||
|
||||
Google Reader inspired self-hosted RSS reader, based on Dropwizard and AngularJS.
|
||||
|
||||
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 your own server
|
||||
-----------------------------
|
||||
|
||||
CommaFeed 2.0 has been rewritten to use Dropwizard and gulp instead of using tomee and wro4j. The latest version of the 1.x branch is available [here](https://github.com/Athou/commafeed/tree/1.x).
|
||||
|
||||
For storage, you can either use an embedded H2 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 apt-get install build-essential openjdk-7-jdk maven
|
||||
# Make sure java7 is the selected java version
|
||||
sudo update-alternatives --config java
|
||||
sudo update-alternatives --config javac
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Clone this repository. 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
|
||||
|
||||
mvn clean package
|
||||
|
||||
Copy `config.yml.example` to `config.yml` then edit the file to your liking.
|
||||
Issue the following command to run the app, the server will listen by default on `http://localhost:8082`. The default user is `admin` and the default password is `admin`.
|
||||
|
||||
java -jar target/commafeed.jar server config.yml
|
||||
|
||||
You can use a proxy http server such as nginx or apache.
|
||||
|
||||
Deployment on OpenShift
|
||||
-----------------------------
|
||||
|
||||
[OpenShift](https://openshift.redhat.com) is Red Hat's Platform-as-a-Service (PaaS) that allows developers to quickly develop, host, and scale applications in a cloud environment. CommaFeed runs perfectly on OpenShift and can even be used in the free tier. Follow the [Getting Started](https://developers.openshift.com/en/getting-started-overview.html) guide and after you sign up and install the Command Line Tools (RHC), do:
|
||||
|
||||
rhc create-app commafeed diy-0.1 mysql-5.5
|
||||
cd commafeed
|
||||
git remote add upstream -m master https://github.com/Athou/commafeed.git
|
||||
git pull -s recursive -X theirs upstream master
|
||||
git push
|
||||
|
||||
Translate CommaFeed into your language
|
||||
--------------------------------------
|
||||
|
||||
Files for internationalization are located [here](https://github.com/Athou/commafeed/tree/master/src/main/app/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 `src/main/app/js/i18n.js` file to be picked up.
|
||||
|
||||
Themes
|
||||
---------------------
|
||||
|
||||
To create a theme, create a new file `src/main/webapp/sass/themes/_<theme>.scss`. Your styles should be wrapped in a `#theme-<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.
|
||||
|
||||
|
||||
Local development
|
||||
-----------------
|
||||
|
||||
Steps to configuring a development environment for CommaFeed may include, but may not be limited to:
|
||||
|
||||
1. `git clone https://github.com/Athou/CommaFeed` into some folder to get the project files.
|
||||
2. Install Eclipse Luna (or latest) from http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/lunasr1 or your repo if available.
|
||||
3. In Eclipse, Window → Preferences → Maven → Annotation Processing. Check "Automatically configure JDT APT"
|
||||
* You may have to install the m2e-apt connector to have "Annotation Processing" as an option. Do so from Window → Preferences → Maven → Discovery → Open Catalog → type "m2e-apt" in the search box
|
||||
* If you have installed Eclipse EE instead of Luna, you may have trouble installing m2e-apt
|
||||
4. Install Lombok into Eclipse from http://projectlombok.org/download.html
|
||||
* You may have to run `java -jar lombok.jar` as an administrator if your eclipse installation is not in your home folder
|
||||
5. In Eclipse, File → Import → Maven → Existing Maven Projects. Navigate to where you cloned the CommaFeed files into, and select that as the root directory. Click Finish.
|
||||
* You may notice some errors along the lines of "Plugin execution not covered by lifecycle configuration". These are inconsequential.
|
||||
6. Find the file "CommaFeedApplication.java" under the navigation pane.
|
||||
7. Right click it to bring up the context menu → Debug as... → Debug Configurations
|
||||
8. Type `server config.dev.yml` under "Program arguments" in the "Arguments" tab for the Java Application setting "CommaFeedApplication"
|
||||
9. Apply and hit "Debug"
|
||||
10. The debugger is now working. To connect to it, open a terminal (or command prompt) and navigate to the directory where you cloned the CommaFeed files.
|
||||
11. Issue the command `gulp dev` on Unix based systems or `gulp.cmd dev` in Windows.
|
||||
12. The development server is now running at http://localhost:8082 and is proxying REST requests to dropwizard on port 8083.
|
||||
13. Connect to the server from your browser; you should have functional breakpoints and watches on assets.
|
||||
14. When you're done developing, create a fork at the top of https://github.com/Athou/CommaFeed page and commit your changes to it.
|
||||
15. If you'd like to contribute to CommaFeed, create a pull request from your repository to https://github.com/Athou/CommaFeed when your changes are ready. There's a button to do so at the top of https://github.com/Athou/CommaFeed.
|
||||
|
||||
Copyright and license
|
||||
---------------------
|
||||
|
||||
Copyright 2013-2014 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.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"jquery": "1.11.0",
|
||||
"jquery-ui": "1.11",
|
||||
"jquery-ui": "1.10.3",
|
||||
"jquery-mousewheel": "3.1.12",
|
||||
"lodash": "2.4.1",
|
||||
"bootstrap": "3.1.1",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# CommaFeed settings
|
||||
# ------------------
|
||||
app:
|
||||
# context path of the application
|
||||
contextPath: /
|
||||
|
||||
# url used to access commafeed
|
||||
publicUrl: http://localhost:8082/
|
||||
|
||||
@@ -76,6 +79,7 @@ database:
|
||||
minSize: 1
|
||||
maxSize: 50
|
||||
checkConnectionWhileIdle: true
|
||||
maxConnectionAge: 30m
|
||||
|
||||
server:
|
||||
applicationConnectors:
|
||||
@@ -84,6 +88,7 @@ server:
|
||||
adminConnectors:
|
||||
- type: http
|
||||
port: 8084
|
||||
|
||||
logging:
|
||||
level: INFO
|
||||
loggers:
|
||||
@@ -99,4 +104,16 @@ logging:
|
||||
archive: true
|
||||
archivedLogFilenamePattern: log/commafeed-%d.log
|
||||
archivedFileCount: 5
|
||||
timeZone: UTC
|
||||
timeZone: UTC
|
||||
|
||||
# Redis pool configuration
|
||||
# (only used if app.cache is 'redis')
|
||||
# -----------------------------------
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password:
|
||||
timeout: 2000
|
||||
database: 0
|
||||
maxTotal: 500
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# CommaFeed settings
|
||||
# ------------------
|
||||
app:
|
||||
# context path of the application
|
||||
contextPath: /
|
||||
|
||||
# url used to access commafeed
|
||||
publicUrl: http://localhost:8082/
|
||||
|
||||
@@ -66,7 +69,7 @@ app:
|
||||
|
||||
database:
|
||||
driverClass: org.h2.Driver
|
||||
url: jdbc:h2:./target/example
|
||||
url: jdbc:h2:/home/commafeed/db
|
||||
user: sa
|
||||
password: sa
|
||||
properties:
|
||||
@@ -76,6 +79,7 @@ database:
|
||||
minSize: 1
|
||||
maxSize: 50
|
||||
checkConnectionWhileIdle: true
|
||||
maxConnectionAge: 30m
|
||||
|
||||
server:
|
||||
applicationConnectors:
|
||||
@@ -84,6 +88,7 @@ server:
|
||||
adminConnectors:
|
||||
- type: http
|
||||
port: 8084
|
||||
|
||||
logging:
|
||||
level: WARN
|
||||
loggers:
|
||||
@@ -98,4 +103,16 @@ logging:
|
||||
archive: true
|
||||
archivedLogFilenamePattern: log/commafeed-%d.log
|
||||
archivedFileCount: 5
|
||||
timeZone: UTC
|
||||
timeZone: UTC
|
||||
|
||||
# Redis pool configuration
|
||||
# (only used if app.cache is 'redis')
|
||||
# -----------------------------------
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password:
|
||||
timeout: 2000
|
||||
database: 0
|
||||
maxTotal: 500
|
||||
|
||||
@@ -1,283 +1,295 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="12">
|
||||
<profile kind="CodeFormatterProfile" name="Eclipse [built-in] 140 chars" version="12">
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="140"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.5"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="140"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
154
pom.xml
154
pom.xml
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.3</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>CommaFeed</name>
|
||||
|
||||
@@ -15,8 +15,17 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<dropwizard.version>0.7.1</dropwizard.version>
|
||||
<guice.version>3.0</guice.version>
|
||||
<querydsl.version>3.5.0</querydsl.version>
|
||||
<rome.version>1.5.0</rome.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/Athou/commafeed.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/Athou/commafeed.git</developerConnection>
|
||||
<url>https://github.com/Athou/commafeed</url>
|
||||
</scm>
|
||||
|
||||
<build>
|
||||
<finalName>commafeed</finalName>
|
||||
<resources>
|
||||
@@ -29,7 +38,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
@@ -38,7 +47,7 @@
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
<version>2.1.7</version>
|
||||
<version>2.1.11</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -49,6 +58,7 @@
|
||||
<configuration>
|
||||
<generateGitPropertiesFile>false</generateGitPropertiesFile>
|
||||
<failOnNoGitDirectory>false</failOnNoGitDirectory>
|
||||
<failOnUnableToExtractRepoInfo>false</failOnUnableToExtractRepoInfo>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
@@ -88,7 +98,7 @@
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>0.0.15</version>
|
||||
<version>0.0.16</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>install node and npm</id>
|
||||
@@ -117,6 +127,41 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.jamierf.dropwizard</groupId>
|
||||
<artifactId>dropwizard-debpkg-maven-plugin</artifactId>
|
||||
<version>0.7</version>
|
||||
<configuration>
|
||||
<configTemplate>${basedir}/config.yml.example</configTemplate>
|
||||
<jvm>
|
||||
<packageName>openjdk-7-jdk</packageName>
|
||||
<server>true</server>
|
||||
</jvm>
|
||||
<unix>
|
||||
<user>commafeed</user>
|
||||
</unix>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>dwpackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -124,7 +169,7 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.14.4</version>
|
||||
<version>1.14.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -133,6 +178,17 @@
|
||||
<version>1.7.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>${guice.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-multibindings</artifactId>
|
||||
<version>${guice.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-core</artifactId>
|
||||
@@ -158,47 +214,47 @@
|
||||
<artifactId>dropwizard-assets</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-forms</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.wordnik</groupId>
|
||||
<artifactId>swagger-jaxrs_2.10</artifactId>
|
||||
<version>1.3.7</version>
|
||||
<version>1.3.10</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jsr311-api</artifactId>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>javassist</artifactId>
|
||||
<groupId>javassist</groupId>
|
||||
<artifactId>jsr311-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysema.querydsl</groupId>
|
||||
<artifactId>querydsl-apt</artifactId>
|
||||
<version>3.4.2</version>
|
||||
<version>${querydsl.version}</version>
|
||||
<scope>provided</scope>
|
||||
<classifier>hibernate</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysema.querydsl</groupId>
|
||||
<artifactId>querydsl-jpa</artifactId>
|
||||
<version>3.4.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-multipart</artifactId>
|
||||
<version>1.18.1</version>
|
||||
<version>${querydsl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
@@ -207,61 +263,41 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-math</artifactId>
|
||||
<version>2.2</version>
|
||||
<artifactId>commons-math3</artifactId>
|
||||
<version>3.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>2.5.2</version>
|
||||
<version>2.6.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.5.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.java.dev.rome</groupId>
|
||||
<groupId>com.rometools</groupId>
|
||||
<artifactId>rome</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>jdom</groupId>
|
||||
<artifactId>jdom</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<version>${rome.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.rometools</groupId>
|
||||
<groupId>com.rometools</groupId>
|
||||
<artifactId>rome-opml</artifactId>
|
||||
<version>1.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>rome</groupId>
|
||||
<artifactId>rome</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jdom</groupId>
|
||||
<artifactId>jdom</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<version>${rome.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.7.3</version>
|
||||
<version>1.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.juniversalchardet</groupId>
|
||||
<artifactId>juniversalchardet</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.gwt</groupId>
|
||||
<artifactId>gwt-servlet</artifactId>
|
||||
<version>2.6.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.cssparser</groupId>
|
||||
<artifactId>cssparser</artifactId>
|
||||
@@ -271,17 +307,17 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.181</version>
|
||||
<version>1.4.182</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.32</version>
|
||||
<version>5.1.33</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.1-901-1.jdbc4</version>
|
||||
<version>9.3-1102-jdbc41</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.jtds</groupId>
|
||||
@@ -295,5 +331,11 @@
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
@@ -26,7 +26,7 @@
|
||||
<link rel="stylesheet" href="lib/font-awesome/css/font-awesome.css" />
|
||||
<link rel="stylesheet" href="lib/select2/select2.css" />
|
||||
<link rel="stylesheet" href="lib/ng-grid/ng-grid.css" />
|
||||
<link rel="stylesheet" href="lib/jquery-ui/themes/smoothness/jquery-ui.css" />
|
||||
<link rel="stylesheet" href="lib/jquery-ui/themes/base/jquery-ui.css" />
|
||||
<link rel="stylesheet" href="lib/angular-loading-bar/build/loading-bar.css" />
|
||||
|
||||
<link rel="stylesheet" href="css/app.css" />
|
||||
@@ -41,7 +41,7 @@
|
||||
<!-- build:js js/app.js -->
|
||||
<script type="text/javascript" src="lib/lodash/dist/lodash.js"></script>
|
||||
<script type="text/javascript" src="lib/jquery/dist/jquery.js"></script>
|
||||
<script type="text/javascript" src="lib/jquery-ui/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="lib/jquery-ui/ui/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="lib/jquery-mousewheel/jquery.mousewheel.js"></script>
|
||||
<script type="text/javascript" src="lib/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="lib/angular/angular.js"></script>
|
||||
|
||||
@@ -1432,6 +1432,9 @@ module.controller('ManageSettingsCtrl', ['$scope', '$location', '$state', 'Admin
|
||||
$scope.toUsers = function() {
|
||||
$state.transitionTo('admin.userlist');
|
||||
};
|
||||
$scope.toMetrics = function() {
|
||||
$state.transitionTo('admin.metrics');
|
||||
};
|
||||
}]);
|
||||
|
||||
module.controller('HelpController', ['$scope', 'CategoryService', 'AnalyticsService', 'ServerService',
|
||||
@@ -1460,55 +1463,58 @@ module.controller('MetricsCtrl', ['$scope', 'AdminMetricsService', function($sco
|
||||
$scope.metrics = AdminMetricsService.get();
|
||||
}]);
|
||||
|
||||
module.controller('LoginCtrl', ['$scope', '$location', 'SessionService', 'ServerService', function($scope, $location, SessionService, ServerService) {
|
||||
$scope.model = {};
|
||||
$scope.recovery_model = {};
|
||||
$scope.recovery = false;
|
||||
$scope.recovery_enabled = false;
|
||||
|
||||
ServerService.get(function(data) {
|
||||
$scope.recovery_enabled = data.smtpEnabled;
|
||||
});
|
||||
|
||||
var login = function(model) {
|
||||
var success = function(data) {
|
||||
window.location.href = window.location.href.substring(0, window.location.href.lastIndexOf('#'));
|
||||
};
|
||||
var error = function(data) {
|
||||
$scope.message = data.data;
|
||||
};
|
||||
SessionService.login({
|
||||
name : model.name,
|
||||
password : model.password
|
||||
}, success, error);
|
||||
}
|
||||
$scope.demoLogin = function() {
|
||||
login({
|
||||
name : 'demo',
|
||||
password : 'demo'
|
||||
});
|
||||
};
|
||||
module.controller('LoginCtrl', ['$scope', '$location', '$timeout', 'SessionService', 'ServerService',
|
||||
function($scope, $location, $timeout, SessionService, ServerService) {
|
||||
$scope.model = {};
|
||||
$scope.recovery_model = {};
|
||||
$scope.recovery = false;
|
||||
$scope.recovery_enabled = false;
|
||||
|
||||
$scope.login = function() {
|
||||
login($scope.model);
|
||||
};
|
||||
|
||||
$scope.toggleRecovery = function() {
|
||||
$scope.recovery = !$scope.recovery;
|
||||
};
|
||||
|
||||
var recovery_success = function(data) {
|
||||
$scope.recovery_message = "Email has ben sent. Check your inbox.";
|
||||
};
|
||||
var recovery_error = function(data) {
|
||||
$scope.recovery_message = data.data;
|
||||
};
|
||||
$scope.recover = function() {
|
||||
SessionService.passwordReset({
|
||||
email : $scope.recovery_model.email
|
||||
}, recovery_success, recovery_error);
|
||||
}
|
||||
}]);
|
||||
ServerService.get(function(data) {
|
||||
$scope.recovery_enabled = data.smtpEnabled;
|
||||
});
|
||||
|
||||
var login = function(model) {
|
||||
var success = function(data) {
|
||||
window.location.href = window.location.href.substring(0, window.location.href.lastIndexOf('#'));
|
||||
};
|
||||
var error = function(data) {
|
||||
$scope.message = data.data;
|
||||
};
|
||||
SessionService.login({
|
||||
name : model.name,
|
||||
password : model.password
|
||||
}, success, error);
|
||||
}
|
||||
$scope.demoLogin = function() {
|
||||
login({
|
||||
name : 'demo',
|
||||
password : 'demo'
|
||||
});
|
||||
};
|
||||
|
||||
$scope.login = function() {
|
||||
// autofilled fields do not trigger model update, do it manually
|
||||
$('input[ng-model]').trigger('input');
|
||||
login($scope.model);
|
||||
};
|
||||
|
||||
$scope.toggleRecovery = function() {
|
||||
$scope.recovery = !$scope.recovery;
|
||||
};
|
||||
|
||||
var recovery_success = function(data) {
|
||||
$scope.recovery_message = "Email has ben sent. Check your inbox.";
|
||||
};
|
||||
var recovery_error = function(data) {
|
||||
$scope.recovery_message = data.data;
|
||||
};
|
||||
$scope.recover = function() {
|
||||
SessionService.passwordReset({
|
||||
email : $scope.recovery_model.email
|
||||
}, recovery_success, recovery_error);
|
||||
}
|
||||
}]);
|
||||
|
||||
module.controller('RegisterCtrl', ['$scope', '$location', 'SessionService', 'ServerService',
|
||||
function($scope, $location, SessionService, ServerService) {
|
||||
|
||||
@@ -193,7 +193,7 @@ module.directive('category', [function() {
|
||||
});
|
||||
var label = '';
|
||||
if (count > 0) {
|
||||
label = '(' + count + ')';
|
||||
label += count;
|
||||
}
|
||||
return label;
|
||||
};
|
||||
@@ -201,7 +201,7 @@ module.directive('category', [function() {
|
||||
$scope.feedCountLabel = function(feed) {
|
||||
var label = '';
|
||||
if (feed.unread > 0) {
|
||||
label = '(' + feed.unread + ')';
|
||||
label += feed.unread;
|
||||
}
|
||||
return label;
|
||||
};
|
||||
@@ -358,4 +358,4 @@ module.directive('metricGauge', function() {
|
||||
restrict : 'E',
|
||||
templateUrl : 'templates/_metrics.gauge.html'
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,10 +12,9 @@ app.config([
|
||||
'$translateProvider',
|
||||
function($routeProvider, $stateProvider, $urlRouterProvider, $httpProvider, $compileProvider, cfpLoadingBarProvider,
|
||||
$translateProvider) {
|
||||
|
||||
// $translateProvider.useLocalStorage();
|
||||
|
||||
$translateProvider.useStaticFilesLoader({
|
||||
prefix : '/i18n/',
|
||||
prefix : 'i18n/',
|
||||
suffix : '.js'
|
||||
});
|
||||
$translateProvider.preferredLanguage('en');
|
||||
|
||||
@@ -56,13 +56,13 @@ module.factory('SettingsService', ['$resource', '$translate', function($resource
|
||||
res.get(function(data) {
|
||||
s.settings = data;
|
||||
var lang = s.settings.language || 'en';
|
||||
$translate.use(lang);
|
||||
if (lang === 'zh') {
|
||||
lang = 'zh-cn';
|
||||
} else if (lang === 'ms') {
|
||||
lang = 'ms-my';
|
||||
}
|
||||
moment.lang(lang, {});
|
||||
$translate.use(lang);
|
||||
if (callback) {
|
||||
callback(data);
|
||||
}
|
||||
@@ -182,7 +182,7 @@ module.factory('CategoryService', ['$resource', '$http', function($resource, $ht
|
||||
var actions = {
|
||||
get : {
|
||||
method : 'GET',
|
||||
ignoreLoadingBar: true,
|
||||
ignoreLoadingBar : true,
|
||||
params : {
|
||||
_method : 'get'
|
||||
}
|
||||
@@ -243,11 +243,14 @@ module.factory('CategoryService', ['$resource', '$http', function($resource, $ht
|
||||
callback(data);
|
||||
});
|
||||
};
|
||||
res.refresh = function(callback) {
|
||||
res.refresh = function(success, error) {
|
||||
res.get(function(data) {
|
||||
_.merge(res.subscriptions, data);
|
||||
if (callback)
|
||||
callback(data);
|
||||
if (success)
|
||||
success(data);
|
||||
}, function(data) {
|
||||
if (error)
|
||||
error(data);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -265,7 +268,7 @@ module.factory('EntryService', ['$resource', '$http', function($resource, $http)
|
||||
},
|
||||
mark : {
|
||||
method : 'POST',
|
||||
ignoreLoadingBar: true,
|
||||
ignoreLoadingBar : true,
|
||||
params : {
|
||||
_method : 'mark'
|
||||
}
|
||||
|
||||
@@ -101,6 +101,14 @@
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.css-treeview .unread ~ .unread-counter::before {
|
||||
content: '(';
|
||||
}
|
||||
|
||||
.css-treeview .unread ~ .unread-counter::after {
|
||||
content: ')';
|
||||
}
|
||||
|
||||
.css-treeview a {
|
||||
cursor: pointer;
|
||||
color: black;
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<i ng-class="{'icon-star' : node.id == 'starred', 'icon-inbox': node.id == 'all', 'icon-tag' : node.isTag}" ng-show="!showChildren"></i>
|
||||
</span>
|
||||
<span ng-class="{selected: (node.id == selectedId && (node.isTag ? selectedType == 'tag' : selectedType == 'category'))}">
|
||||
<span ng-class="{unread: unreadCount({category:node})}" class="bidi-embed"> {{categoryLabel(node)}} </span>
|
||||
<span class="unread-counter"> {{categoryCountLabel(node)}} </span>
|
||||
<span ng-class="{unread: unreadCount({category:node})}" class="bidi-embed">{{categoryLabel(node)}}</span>
|
||||
<span class="unread-counter">{{categoryCountLabel(node)}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -30,8 +30,8 @@
|
||||
<a ng-click="feedClicked(feed.id, $event)" ng-dblclick="showFeedDetails(feed)" class="feed-link" href="{{feed.feedLink}}" target="_blank"
|
||||
ng-class="{error: feed.message && feed.errorCount > 10, selected: (feed.id == selectedId && selectedType == 'feed') }">
|
||||
<favicon url="feed.iconUrl" />
|
||||
<span ng-class="{unread: feed.unread}" class="bidi-embed"> {{feed.name}} </span>
|
||||
<span class="unread-counter"> {{feedCountLabel(feed)}} </span>
|
||||
<span ng-class="{unread: feed.unread}" class="bidi-embed">{{feed.name}}</span>
|
||||
<span class="unread-counter">{{feedCountLabel(feed)}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<div class="row">
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
Application settings
|
||||
Application settings -
|
||||
<small>
|
||||
<a ng-click="toUsers()" class="pointer">Manage users</a>
|
||||
</small>
|
||||
-
|
||||
<small>
|
||||
<a ng-click="toMetrics()" class="pointer">Metrics</a>
|
||||
</small>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -28,26 +32,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="feedbackButton">Feedback button</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="feedbackButton" name="feedbackButton" ng-model="settings.feedbackButton" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="googleClientId">Google client ID</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="googleClientId" class="form-control" ng-model="settings.googleClientId" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="googleClientSecret">Google client secret</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="googleClientSecret" class="form-control" ng-model="settings.googleClientSecret" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="googleAnalyticsTrackingCode">Google Analytics tracking code</label>
|
||||
<div class="col-sm-9">
|
||||
@@ -134,14 +118,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="logLevel">Logging level</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="logLevel" ng-model="settings.logLevel" class="form-control"
|
||||
ng-options="level for level in ['DEBUG', 'INFO', 'WARN', 'ERROR']">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="logLevel">Database query timeout (ms)</label>
|
||||
<div class="col-sm-9">
|
||||
@@ -173,8 +149,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="text-center form-group">
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
|
||||
<button type="button" class="btn btn-default" ng-click="cancel()">Back</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" class="btn btn-primary" ng-if="!isMeta()">{{ 'global.save' | translate }}</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="deleteCategory()" ng-show="!isMeta()"
|
||||
confirm-click="{{ 'details.delete_category_confirmation}">{{ 'global.delete' | translate }}</button>
|
||||
confirm-click="'details.delete_category_confirmation' | translate">{{ 'global.delete' | translate }}</button>
|
||||
<button type="button" class="btn btn-default" ng-click="back()">{{ 'global.cancel' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
</h4>
|
||||
<p>{{ 'about.rest_api.line1' | translate }}</p>
|
||||
<p>
|
||||
<a href="api" target="_blank">{{ 'about.rest_api.link_to_documentation' | translate }}</a>
|
||||
<a href="api/" target="_blank">{{ 'about.rest_api.link_to_documentation' | translate }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<div infinite-scroll="loadMoreEntries()" infinite-scroll-disabled="busy || !settingsService.settings.readingMode"
|
||||
infinite-scroll-distance="1" id="feed-accordion" ng-class="{'expanded' : settingsService.settings.viewMode == 'expanded' }">
|
||||
<div ng-show="message && errorCount > 10">{{ 'view.error_while_loading_feed} : {{message}' | translate }}</div>
|
||||
<div ng-show="message && errorCount > 10">{{ 'view.error_while_loading_feed' | translate }} : {{ message }}</div>
|
||||
<div ng-repeat="entry in entries" class="entry entry-font-size-{{font_size}}" id="entry_{{entry.id}}"
|
||||
ng-class="{unread: entry.read == false, current: current==entry, open: isOpen, closed: !isOpen }">
|
||||
<div class="entry-heading" ng-swipe-right="mark(entry, !entry.read)">
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="email">{{ 'profile.email' | translate }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="email" id="email" ng-model="user.email" class="form-control" />
|
||||
<input type="email" id="email" ng-model="user.email" class="form-control" autocomplete="off" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="password">{{ 'profile.change_password' | translate }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" name="password" id="password" ng-model="user.password" class="form-control" ng-minlength="6" />
|
||||
<input type="password" name="password" id="password" ng-model="user.password" class="form-control" ng-minlength="6" autocomplete="off" />
|
||||
<span class="help-inline" ng-show="profileForm.password.$error.minlength">{{ 'profile.minimum_6_chars' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,7 +26,7 @@
|
||||
<label class="col-sm-2 control-label" for="password">{{ 'profile.confirm_password' | translate }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" class="form-control" name="password_c" id="password_c" ng-model="password_c"
|
||||
ui-validate="'$value==user.password'" ui-validate-watch="'user.password'">
|
||||
ui-validate="'$value==user.password'" ui-validate-watch="'user.password'" autocomplete="off">
|
||||
<span class="help-inline" ng-show="profileForm.password_c.$error.validator">{{ 'profile.passwords_do_not_match' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,7 +57,8 @@
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button type="submit" class="btn btn-primary">{{ 'global.save' | translate }}</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="deleteAccount()" confirm-click="'profile.delete_account_confirmation' | translate">{{ 'profile.delete_account' | translate }}</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="deleteAccount()"
|
||||
confirm-click="'profile.delete_account_confirmation' | translate">{{ 'profile.delete_account' | translate }}</button>
|
||||
<button type="button" class="btn btn-default" ng-click="cancel()">{{ 'global.cancel' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
</span>
|
||||
<span>
|
||||
- REST API
|
||||
<a href="api" target="_blank">documentation</a>
|
||||
<a href="api/" target="_blank">documentation</a>
|
||||
</span>
|
||||
<span class="pull-right">
|
||||
<a href="https://twitter.com/CommaFeed" class="twitter-follow-button" data-show-count="false" data-size="large">Follow @CommaFeed</a>
|
||||
|
||||
@@ -4,41 +4,25 @@ import io.dropwizard.Application;
|
||||
import io.dropwizard.assets.AssetsBundle;
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
import io.dropwizard.hibernate.HibernateBundle;
|
||||
import io.dropwizard.jersey.sessions.HttpSessionProvider;
|
||||
import io.dropwizard.migrations.MigrationsBundle;
|
||||
import io.dropwizard.servlets.CacheBustingFilter;
|
||||
import io.dropwizard.setup.Bootstrap;
|
||||
import io.dropwizard.setup.Environment;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.session.HashSessionManager;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.CommaFeedConfiguration.CacheType;
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.cache.NoopCacheService;
|
||||
import com.commafeed.backend.cache.RedisCacheService;
|
||||
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;
|
||||
@@ -53,24 +37,10 @@ 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.MailService;
|
||||
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.backend.task.OldStatusesCleanupTask;
|
||||
import com.commafeed.backend.task.OrphansCleanupTask;
|
||||
import com.commafeed.backend.task.SchedulingService;
|
||||
import com.commafeed.frontend.auth.SecurityCheckProvider;
|
||||
import com.commafeed.frontend.auth.SecurityCheckProvider.SecurityCheckUserServiceProvider;
|
||||
import com.commafeed.frontend.resource.AdminREST;
|
||||
@@ -84,6 +54,10 @@ import com.commafeed.frontend.servlet.AnalyticsServlet;
|
||||
import com.commafeed.frontend.servlet.CustomCssServlet;
|
||||
import com.commafeed.frontend.servlet.LogoutServlet;
|
||||
import com.commafeed.frontend.servlet.NextUnreadServlet;
|
||||
import com.commafeed.frontend.session.SessionHelperProvider;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.sun.jersey.api.core.ResourceConfig;
|
||||
import com.wordnik.swagger.config.ConfigFactory;
|
||||
import com.wordnik.swagger.config.ScannerFactory;
|
||||
import com.wordnik.swagger.config.SwaggerConfig;
|
||||
@@ -94,154 +68,83 @@ import com.wordnik.swagger.jaxrs.listing.ResourceListingProvider;
|
||||
import com.wordnik.swagger.jaxrs.reader.DefaultJaxrsApiReader;
|
||||
import com.wordnik.swagger.reader.ClassReaders;
|
||||
|
||||
@Slf4j
|
||||
public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
||||
|
||||
public static final String USERNAME_ADMIN = "admin";
|
||||
public static final String USERNAME_DEMO = "demo";
|
||||
|
||||
public static final String SESSION_USER = "user";
|
||||
|
||||
public static final Date STARTUP_TIME = new Date();
|
||||
|
||||
private HibernateBundle<CommaFeedConfiguration> hibernateBundle;
|
||||
private MigrationsBundle<CommaFeedConfiguration> migrationsBundle;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CommaFeed";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Bootstrap<CommaFeedConfiguration> bootstrap) {
|
||||
hibernateBundle = new HibernateBundle<CommaFeedConfiguration>(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class,
|
||||
FeedEntryContent.class, FeedEntryStatus.class, FeedEntryTag.class, FeedSubscription.class, User.class, UserRole.class,
|
||||
UserSettings.class) {
|
||||
bootstrap.addBundle(hibernateBundle = new HibernateBundle<CommaFeedConfiguration>(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<CommaFeedConfiguration>() {
|
||||
bootstrap.addBundle(new MigrationsBundle<CommaFeedConfiguration>() {
|
||||
@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();
|
||||
// configure context path
|
||||
environment.getApplicationContext().setContextPath(config.getApplicationSettings().getContextPath());
|
||||
|
||||
CacheService cacheService = config.getApplicationSettings().getCache() == CacheType.NOOP ? new NoopCacheService()
|
||||
: new RedisCacheService();
|
||||
log.info("using cache {}", cacheService.getClass());
|
||||
|
||||
// DAOs
|
||||
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);
|
||||
|
||||
// Queuing system
|
||||
FeedQueues queues = new FeedQueues(feedDAO, config, metrics);
|
||||
|
||||
// Services
|
||||
ApplicationPropertiesService applicationPropertiesService = new ApplicationPropertiesService();
|
||||
DatabaseCleaningService cleaningService = new DatabaseCleaningService(sessionFactory, feedDAO, feedEntryDAO, feedEntryContentDAO,
|
||||
feedEntryStatusDAO);
|
||||
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);
|
||||
MailService mailService = new MailService(config);
|
||||
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);
|
||||
|
||||
// Feed fetching/parsing
|
||||
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);
|
||||
// guice init
|
||||
Injector injector = Guice.createInjector(new CommaFeedModule(hibernateBundle.getSessionFactory(), config, environment.metrics()));
|
||||
|
||||
// Auth/session management
|
||||
HashSessionManager sessionManager = new HashSessionManager();
|
||||
sessionManager.setHttpOnly(true);
|
||||
sessionManager.getSessionCookieConfig().setHttpOnly(true);
|
||||
|
||||
sessionManager.setStoreDirectory(new File("sessions"));
|
||||
sessionManager.getSessionCookieConfig().setMaxAge((int) TimeUnit.DAYS.toSeconds(30));
|
||||
sessionManager.setMaxInactiveInterval((int) TimeUnit.DAYS.toSeconds(30));
|
||||
|
||||
sessionManager.setDeleteUnrestorableSessions(true);
|
||||
sessionManager.setIdleSavePeriod((int) TimeUnit.HOURS.toSeconds(2));
|
||||
sessionManager.setRefreshCookieAge((int) TimeUnit.DAYS.toSeconds(1));
|
||||
sessionManager.setSavePeriod((int) TimeUnit.MINUTES.toSeconds(5));
|
||||
sessionManager.setScavengePeriod((int) TimeUnit.MINUTES.toSeconds(5));
|
||||
|
||||
environment.servlets().setSessionHandler(new SessionHandler(sessionManager));
|
||||
environment.jersey().register(new SecurityCheckUserServiceProvider(userService));
|
||||
environment.servlets().setSessionHandler(new SessionHandler(config.getSessionManagerFactory().build()));
|
||||
environment.jersey().register(new SecurityCheckUserServiceProvider(injector.getInstance(UserService.class)));
|
||||
environment.jersey().register(SecurityCheckProvider.class);
|
||||
environment.jersey().register(HttpSessionProvider.class);
|
||||
environment.jersey().register(SessionHelperProvider.class);
|
||||
|
||||
// REST resources
|
||||
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, mailService, config));
|
||||
environment.jersey().register(injector.getInstance(AdminREST.class));
|
||||
environment.jersey().register(injector.getInstance(CategoryREST.class));
|
||||
environment.jersey().register(injector.getInstance(EntryREST.class));
|
||||
environment.jersey().register(injector.getInstance(FeedREST.class));
|
||||
environment.jersey().register(injector.getInstance(PubSubHubbubCallbackREST.class));
|
||||
environment.jersey().register(injector.getInstance(ServerREST.class));
|
||||
environment.jersey().register(injector.getInstance(UserREST.class));
|
||||
|
||||
// Servlets
|
||||
NextUnreadServlet nextUnreadServlet = new NextUnreadServlet(sessionFactory, feedSubscriptionDAO, feedEntryStatusDAO,
|
||||
feedCategoryDAO, config);
|
||||
LogoutServlet logoutServlet = new LogoutServlet(config);
|
||||
CustomCssServlet customCssServlet = new CustomCssServlet(sessionFactory, userSettingsDAO);
|
||||
AnalyticsServlet analyticsServlet = new AnalyticsServlet(config);
|
||||
environment.servlets().addServlet("next", nextUnreadServlet).addMapping("/next");
|
||||
environment.servlets().addServlet("logout", logoutServlet).addMapping("/logout");
|
||||
environment.servlets().addServlet("customCss", customCssServlet).addMapping("/custom_css.css");
|
||||
environment.servlets().addServlet("analytics.js", analyticsServlet).addMapping("/analytics.js");
|
||||
environment.servlets().addServlet("next", injector.getInstance(NextUnreadServlet.class)).addMapping("/next");
|
||||
environment.servlets().addServlet("logout", injector.getInstance(LogoutServlet.class)).addMapping("/logout");
|
||||
environment.servlets().addServlet("customCss", injector.getInstance(CustomCssServlet.class)).addMapping("/custom_css.css");
|
||||
environment.servlets().addServlet("analytics.js", injector.getInstance(AnalyticsServlet.class)).addMapping("/analytics.js");
|
||||
|
||||
// Tasks
|
||||
SchedulingService schedulingService = new SchedulingService();
|
||||
schedulingService.register(new OldStatusesCleanupTask(config, cleaningService));
|
||||
schedulingService.register(new OrphansCleanupTask(cleaningService));
|
||||
// Scheduled tasks
|
||||
ScheduledExecutorService executor = environment.lifecycle().scheduledExecutorService("task-scheduler").build();
|
||||
injector.getInstance(OldStatusesCleanupTask.class).register(executor);
|
||||
injector.getInstance(OrphansCleanupTask.class).register(executor);
|
||||
|
||||
// Managed objects
|
||||
environment.lifecycle().manage(startupService);
|
||||
environment.lifecycle().manage(taskGiver);
|
||||
environment.lifecycle().manage(feedWorker);
|
||||
environment.lifecycle().manage(feedUpdater);
|
||||
environment.lifecycle().manage(schedulingService);
|
||||
// database init/changelogs
|
||||
environment.lifecycle().manage(injector.getInstance(StartupService.class));
|
||||
|
||||
// background feed fetching
|
||||
environment.lifecycle().manage(injector.getInstance(FeedRefreshTaskGiver.class));
|
||||
environment.lifecycle().manage(injector.getInstance(FeedRefreshWorker.class));
|
||||
environment.lifecycle().manage(injector.getInstance(FeedRefreshUpdater.class));
|
||||
|
||||
// Swagger
|
||||
environment.jersey().register(new ApiListingResourceJSON());
|
||||
@@ -252,6 +155,23 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
||||
SwaggerConfig swaggerConfig = ConfigFactory.config();
|
||||
swaggerConfig.setApiVersion("1");
|
||||
swaggerConfig.setBasePath("/rest");
|
||||
|
||||
// cache configuration
|
||||
// prevent caching on REST resources, except for favicons
|
||||
environment.servlets().addFilter("cache-filter", new CacheBustingFilter() {
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
String path = ((HttpServletRequest) request).getRequestURI();
|
||||
if (path.contains("/feed/favicon")) {
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
super.doFilter(request, response, chain);
|
||||
}
|
||||
}
|
||||
}).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/rest/*");
|
||||
|
||||
// enable wadl
|
||||
environment.jersey().disable(ResourceConfig.FEATURE_DISABLE_WADL);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
@@ -4,14 +4,19 @@ import io.dropwizard.Configuration;
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
|
||||
import com.commafeed.backend.cache.RedisPoolFactory;
|
||||
import com.commafeed.frontend.session.SessionManagerFactory;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@Getter
|
||||
@@ -21,70 +26,98 @@ public class CommaFeedConfiguration extends Configuration {
|
||||
NOOP, REDIS
|
||||
}
|
||||
|
||||
private ResourceBundle bundle;
|
||||
|
||||
public CommaFeedConfiguration() {
|
||||
bundle = ResourceBundle.getBundle("application");
|
||||
}
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty("database")
|
||||
private DataSourceFactory database = new DataSourceFactory();
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty("redis")
|
||||
private RedisPoolFactory redisPoolFactory = new RedisPoolFactory();
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty("session")
|
||||
private SessionManagerFactory sessionManagerFactory = new SessionManagerFactory();
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty("app")
|
||||
private ApplicationSettings applicationSettings;
|
||||
|
||||
public String getVersion() {
|
||||
return bundle.getString("version");
|
||||
}
|
||||
|
||||
public String getGitCommit() {
|
||||
return bundle.getString("git.commit");
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class ApplicationSettings {
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@NotBlank
|
||||
private String contextPath;
|
||||
|
||||
@NotNull
|
||||
@NotBlank
|
||||
private String publicUrl;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
private boolean allowRegistrations;
|
||||
|
||||
@JsonProperty
|
||||
private String googleAnalyticsTrackingCode;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@Min(1)
|
||||
private int backgroundThreads;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@Min(1)
|
||||
private int databaseUpdateThreads;
|
||||
|
||||
@JsonProperty
|
||||
private String smtpHost;
|
||||
|
||||
@JsonProperty
|
||||
private int smtpPort;
|
||||
|
||||
@JsonProperty
|
||||
private boolean smtpTls;
|
||||
|
||||
@JsonProperty
|
||||
private String smtpUserName;
|
||||
|
||||
@JsonProperty
|
||||
private String smtpPassword;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
private boolean heavyLoad;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
private boolean pubsubhubbub;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
private boolean imageProxyEnabled;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@Min(0)
|
||||
private int queryTimeout;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@Min(0)
|
||||
private int keepStatusDays;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@Min(0)
|
||||
private int refreshIntervalMinutes;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
private CacheType cache;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
private String announcement;
|
||||
|
||||
public Date getUnreadThreshold() {
|
||||
|
||||
45
src/main/java/com/commafeed/CommaFeedModule.java
Normal file
45
src/main/java/com/commafeed/CommaFeedModule.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package com.commafeed;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.CommaFeedConfiguration.CacheType;
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.cache.NoopCacheService;
|
||||
import com.commafeed.backend.cache.RedisCacheService;
|
||||
import com.commafeed.backend.favicon.DefaultFaviconFetcher;
|
||||
import com.commafeed.backend.favicon.AbstractFaviconFetcher;
|
||||
import com.commafeed.backend.favicon.YoutubeFaviconFetcher;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.multibindings.Multibinder;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CommaFeedModule extends AbstractModule {
|
||||
|
||||
@Getter(onMethod = @__({ @Provides }))
|
||||
private final SessionFactory sessionFactory;
|
||||
|
||||
@Getter(onMethod = @__({ @Provides }))
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
@Getter(onMethod = @__({ @Provides }))
|
||||
private final MetricRegistry metrics;
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
CacheService cacheService = config.getApplicationSettings().getCache() == CacheType.NOOP ? new NoopCacheService()
|
||||
: new RedisCacheService(config.getRedisPoolFactory().build());
|
||||
log.info("using cache {}", cacheService.getClass());
|
||||
bind(CacheService.class).toInstance(cacheService);
|
||||
|
||||
Multibinder<AbstractFaviconFetcher> multibinder = Multibinder.newSetBinder(binder(), AbstractFaviconFetcher.class);
|
||||
multibinder.addBinding().to(YoutubeFaviconFetcher.class);
|
||||
multibinder.addBinding().to(DefaultFaviconFetcher.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.commafeed.backend;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HeaderElement;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpResponseInterceptor;
|
||||
import org.apache.http.entity.HttpEntityWrapper;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
class ContentEncodingInterceptor implements HttpResponseInterceptor {
|
||||
|
||||
private static final Set<String> ALLOWED_CONTENT_ENCODINGS = new HashSet<>(Arrays.asList("gzip", "x-gzip", "deflate", "identity"));
|
||||
|
||||
@Override
|
||||
public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
|
||||
if (hasContent(response)) {
|
||||
Header contentEncodingHeader = response.getEntity().getContentEncoding();
|
||||
if (contentEncodingHeader != null && containsUnsupportedEncodings(contentEncodingHeader)) {
|
||||
overrideContentEncoding(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsUnsupportedEncodings(Header contentEncodingHeader) {
|
||||
HeaderElement[] codecs = contentEncodingHeader.getElements();
|
||||
|
||||
for (final HeaderElement codec : codecs) {
|
||||
String codecName = codec.getName().toLowerCase(Locale.US);
|
||||
if (!ALLOWED_CONTENT_ENCODINGS.contains(codecName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void overrideContentEncoding(HttpResponse response) {
|
||||
HttpEntity wrapped = new HttpEntityWrapper(response.getEntity()) {
|
||||
@Override
|
||||
public Header getContentEncoding() {
|
||||
return null;
|
||||
};
|
||||
};
|
||||
|
||||
response.setEntity(wrapped);
|
||||
}
|
||||
|
||||
private boolean hasContent(HttpResponse response) {
|
||||
return response.getEntity() != null && response.getEntity().getContentLength() != 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,27 +4,25 @@ import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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;
|
||||
import org.apache.http.HeaderElement;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpResponseInterceptor;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
@@ -37,50 +35,26 @@ import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.config.ConnectionConfig;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.entity.HttpEntityWrapper;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
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 com.commafeed.CommaFeedConfiguration;
|
||||
|
||||
/**
|
||||
* Smart HTTP getter: handles gzip, ssl, last modified and etag headers
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class HttpGetter {
|
||||
|
||||
private static final String USER_AGENT = "CommaFeed/1.0 (http://www.commafeed.com)";
|
||||
private static final String ACCEPT_LANGUAGE = "en";
|
||||
private static final String PRAGMA_NO_CACHE = "No-cache";
|
||||
private static final String CACHE_CONTROL_NO_CACHE = "no-cache";
|
||||
|
||||
private static final List<String> ALLOWED_CONTENT_ENCODINGS = Arrays.asList("gzip", "x-gzip", "deflate", "identity");
|
||||
private static final HttpResponseInterceptor REMOVE_INCORRECT_CONTENT_ENCODING = new HttpResponseInterceptor() {
|
||||
|
||||
@Override
|
||||
public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null && entity.getContentLength() != 0) {
|
||||
Header header = entity.getContentEncoding();
|
||||
if (header != null) {
|
||||
HeaderElement[] codecs = header.getElements();
|
||||
for (final HeaderElement codec : codecs) {
|
||||
String codecName = codec.getName().toLowerCase(Locale.US);
|
||||
if (!ALLOWED_CONTENT_ENCODINGS.contains(codecName)) {
|
||||
response.setEntity(new HttpEntityWrapper(entity) {
|
||||
@Override
|
||||
public Header getContentEncoding() {
|
||||
return null;
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static final HttpResponseInterceptor REMOVE_INCORRECT_CONTENT_ENCODING = new ContentEncodingInterceptor();
|
||||
|
||||
private static SSLContext SSL_CONTEXT = null;
|
||||
static {
|
||||
@@ -92,6 +66,13 @@ public class HttpGetter {
|
||||
}
|
||||
}
|
||||
|
||||
private String userAgent;
|
||||
|
||||
@Inject
|
||||
public HttpGetter(CommaFeedConfiguration config) {
|
||||
this.userAgent = String.format("CommaFeed/%s (https://www.commafeed.com)", config.getVersion());
|
||||
}
|
||||
|
||||
public HttpResult getBinary(String url, int timeout) throws ClientProtocolException, IOException, NotModifiedException {
|
||||
return getBinary(url, null, null, timeout);
|
||||
}
|
||||
@@ -124,7 +105,7 @@ public class HttpGetter {
|
||||
httpget.addHeader(HttpHeaders.ACCEPT_LANGUAGE, ACCEPT_LANGUAGE);
|
||||
httpget.addHeader(HttpHeaders.PRAGMA, PRAGMA_NO_CACHE);
|
||||
httpget.addHeader(HttpHeaders.CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
httpget.addHeader(HttpHeaders.USER_AGENT, USER_AGENT);
|
||||
httpget.addHeader(HttpHeaders.USER_AGENT, userAgent);
|
||||
|
||||
if (lastModified != null) {
|
||||
httpget.addHeader(HttpHeaders.IF_MODIFIED_SINCE, lastModified);
|
||||
@@ -183,47 +164,15 @@ public class HttpGetter {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public static class HttpResult {
|
||||
|
||||
private byte[] content;
|
||||
private String contentType;
|
||||
private String lastModifiedSince;
|
||||
private String eTag;
|
||||
private long duration;
|
||||
private String urlAfterRedirect;
|
||||
|
||||
public HttpResult(byte[] content, String contentType, String lastModifiedSince, String eTag, long duration, String urlAfterRedirect) {
|
||||
this.content = content;
|
||||
this.contentType = contentType;
|
||||
this.lastModifiedSince = lastModifiedSince;
|
||||
this.eTag = eTag;
|
||||
this.duration = duration;
|
||||
this.urlAfterRedirect = urlAfterRedirect;
|
||||
}
|
||||
|
||||
public byte[] getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public String getLastModifiedSince() {
|
||||
return lastModifiedSince;
|
||||
}
|
||||
|
||||
public String geteTag() {
|
||||
return eTag;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public String getUrlAfterRedirect() {
|
||||
return urlAfterRedirect;
|
||||
}
|
||||
private final byte[] content;
|
||||
private final String contentType;
|
||||
private final String lastModifiedSince;
|
||||
private final String eTag;
|
||||
private final long duration;
|
||||
private final String urlAfterRedirect;
|
||||
}
|
||||
|
||||
public static CloseableHttpClient newClient(int timeout) {
|
||||
|
||||
@@ -4,10 +4,10 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import redis.clients.jedis.Pipeline;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
@@ -21,38 +21,29 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class RedisCacheService extends CacheService {
|
||||
|
||||
private static ObjectMapper mapper = new ObjectMapper();
|
||||
private static ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private JedisPool pool;
|
||||
|
||||
public RedisCacheService() {
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setBlockWhenExhausted(false);
|
||||
pool = new JedisPool(config, "localhost");
|
||||
}
|
||||
private final JedisPool pool;
|
||||
|
||||
@Override
|
||||
public List<String> getLastEntries(Feed feed) {
|
||||
List<String> list = Lists.newArrayList();
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
String key = buildRedisEntryKey(feed);
|
||||
Set<String> members = jedis.smembers(key);
|
||||
for (String member : members) {
|
||||
list.add(member);
|
||||
}
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastEntries(Feed feed, List<String> entries) {
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
String key = buildRedisEntryKey(feed);
|
||||
|
||||
Pipeline pipe = jedis.pipelined();
|
||||
@@ -62,87 +53,72 @@ public class RedisCacheService extends CacheService {
|
||||
}
|
||||
pipe.expire(key, (int) TimeUnit.DAYS.toSeconds(7));
|
||||
pipe.sync();
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category getUserRootCategory(User user) {
|
||||
Category cat = null;
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
String key = buildRedisUserRootCategoryKey(user);
|
||||
String json = jedis.get(key);
|
||||
if (json != null) {
|
||||
cat = mapper.readValue(json, Category.class);
|
||||
cat = MAPPER.readValue(json, Category.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
return cat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserRootCategory(User user, Category category) {
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
String key = buildRedisUserRootCategoryKey(user);
|
||||
|
||||
Pipeline pipe = jedis.pipelined();
|
||||
pipe.del(key);
|
||||
pipe.set(key, mapper.writeValueAsString(category));
|
||||
pipe.set(key, MAPPER.writeValueAsString(category));
|
||||
pipe.expire(key, (int) TimeUnit.MINUTES.toSeconds(30));
|
||||
pipe.sync();
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnreadCount getUnreadCount(FeedSubscription sub) {
|
||||
UnreadCount count = null;
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
String key = buildRedisUnreadCountKey(sub);
|
||||
String json = jedis.get(key);
|
||||
if (json != null) {
|
||||
count = mapper.readValue(json, UnreadCount.class);
|
||||
count = MAPPER.readValue(json, UnreadCount.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnreadCount(FeedSubscription sub, UnreadCount count) {
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
String key = buildRedisUnreadCountKey(sub);
|
||||
|
||||
Pipeline pipe = jedis.pipelined();
|
||||
pipe.del(key);
|
||||
pipe.set(key, mapper.writeValueAsString(count));
|
||||
pipe.set(key, MAPPER.writeValueAsString(count));
|
||||
pipe.expire(key, (int) TimeUnit.MINUTES.toSeconds(30));
|
||||
pipe.sync();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateUserRootCategory(User... users) {
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
Pipeline pipe = jedis.pipelined();
|
||||
if (users != null) {
|
||||
for (User user : users) {
|
||||
@@ -151,15 +127,12 @@ public class RedisCacheService extends CacheService {
|
||||
}
|
||||
}
|
||||
pipe.sync();
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateUnreadCount(FeedSubscription... subs) {
|
||||
Jedis jedis = pool.getResource();
|
||||
try {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
Pipeline pipe = jedis.pipelined();
|
||||
if (subs != null) {
|
||||
for (FeedSubscription sub : subs) {
|
||||
@@ -168,8 +141,6 @@ public class RedisCacheService extends CacheService {
|
||||
}
|
||||
}
|
||||
pipe.sync();
|
||||
} finally {
|
||||
pool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
28
src/main/java/com/commafeed/backend/cache/RedisPoolFactory.java
vendored
Normal file
28
src/main/java/com/commafeed/backend/cache/RedisPoolFactory.java
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.commafeed.backend.cache;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import redis.clients.jedis.Protocol;
|
||||
|
||||
@Getter
|
||||
public class RedisPoolFactory {
|
||||
private String host = "localhost";
|
||||
private int port = Protocol.DEFAULT_PORT;
|
||||
private String password = null;
|
||||
private int timeout = Protocol.DEFAULT_TIMEOUT;
|
||||
private int database = Protocol.DEFAULT_DATABASE;
|
||||
|
||||
private int maxTotal = 500;
|
||||
|
||||
public JedisPool build() {
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setMaxTotal(maxTotal);
|
||||
|
||||
return new JedisPool(config, host, port, timeout, StringUtils.trimToNull(password), database);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
@@ -12,10 +15,12 @@ import com.commafeed.backend.model.User;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mysema.query.types.Predicate;
|
||||
|
||||
@Singleton
|
||||
public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||
|
||||
private QFeedCategory category = QFeedCategory.feedCategory;
|
||||
|
||||
@Inject
|
||||
public FeedCategoryDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
@@ -59,7 +64,7 @@ public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||
return list;
|
||||
}
|
||||
|
||||
public boolean isChild(FeedCategory child, FeedCategory parent) {
|
||||
private boolean isChild(FeedCategory child, FeedCategory parent) {
|
||||
if (parent == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.commafeed.backend.dao;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
@@ -14,32 +17,17 @@ import com.commafeed.backend.model.QUser;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mysema.query.BooleanBuilder;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
import com.mysema.query.jpa.hibernate.HibernateSubQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedDAO extends GenericDAO<Feed> {
|
||||
|
||||
private QFeed feed = QFeed.feed;
|
||||
|
||||
@Inject
|
||||
public FeedDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public Long getUpdatableCount(Date lastLoginThreshold) {
|
||||
BooleanBuilder disabledDatePredicate = new BooleanBuilder();
|
||||
disabledDatePredicate.or(feed.disabledUntil.isNull());
|
||||
disabledDatePredicate.or(feed.disabledUntil.lt(new Date()));
|
||||
|
||||
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<Feed> findNextUpdatable(int count, Date lastLoginThreshold) {
|
||||
BooleanBuilder disabledDatePredicate = new BooleanBuilder();
|
||||
disabledDatePredicate.or(feed.disabledUntil.isNull());
|
||||
|
||||
@@ -2,25 +2,29 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntryContent;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mysema.query.types.ConstructorExpression;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> {
|
||||
|
||||
private QFeedEntryContent content = QFeedEntryContent.feedEntryContent;
|
||||
|
||||
@Inject
|
||||
public FeedEntryContentDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public Long findExisting(String contentHash, String titleHash) {
|
||||
List<Long> list = newQuery().from(content).where(content.contentHash.eq(contentHash), content.titleHash.eq(titleHash)).limit(1)
|
||||
.list(ConstructorExpression.create(Long.class, content.id));
|
||||
.list(content.id);
|
||||
return Iterables.getFirst(list, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.commafeed.backend.dao;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
@@ -12,19 +15,20 @@ 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;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
|
||||
private QFeedEntry entry = QFeedEntry.feedEntry;
|
||||
|
||||
@Inject
|
||||
public FeedEntryDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public Long findExisting(String guid, Feed feed) {
|
||||
List<Long> list = newQuery().from(entry).where(entry.guidHash.eq(DigestUtils.sha1Hex(guid)), entry.feed.eq(feed)).limit(1)
|
||||
.list(ConstructorExpression.create(Long.class, entry.id));
|
||||
.list(entry.id);
|
||||
return Iterables.getFirst(list, null);
|
||||
}
|
||||
|
||||
@@ -35,13 +39,6 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
.list(entry);
|
||||
}
|
||||
|
||||
public int delete(Feed feed, int max) {
|
||||
List<FeedEntry> 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) {
|
||||
List<FeedEntry> list = newQuery().from(entry).where(entry.inserted.lt(olderThan)).limit(max).list(entry);
|
||||
int deleted = list.size();
|
||||
|
||||
@@ -3,21 +3,13 @@ package com.commafeed.backend.dao;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
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;
|
||||
import org.hibernate.criterion.Order;
|
||||
import org.hibernate.criterion.ProjectionList;
|
||||
import org.hibernate.criterion.Projections;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.sql.JoinType;
|
||||
import org.hibernate.transform.Transformers;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.FixedSizeSortedSet;
|
||||
@@ -36,20 +28,23 @@ 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.BooleanBuilder;
|
||||
import com.mysema.query.Tuple;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
|
||||
private static final String ALIAS_STATUS = "status";
|
||||
private static final String ALIAS_ENTRY = "entry";
|
||||
private static final String ALIAS_TAG = "tag";
|
||||
|
||||
private FeedEntryDAO feedEntryDAO;
|
||||
private FeedEntryTagDAO feedEntryTagDAO;
|
||||
private CommaFeedConfiguration config;
|
||||
|
||||
private QFeedEntryStatus status = QFeedEntryStatus.feedEntryStatus;
|
||||
private QFeedEntry entry = QFeedEntry.feedEntry;
|
||||
private QFeedEntryContent content = QFeedEntryContent.feedEntryContent;
|
||||
private QFeedEntryTag entryTag = QFeedEntryTag.feedEntryTag;
|
||||
|
||||
@Inject
|
||||
public FeedEntryStatusDAO(SessionFactory sessionFactory, FeedEntryDAO feedEntryDAO, FeedEntryTagDAO feedEntryTagDAO,
|
||||
CommaFeedConfiguration config) {
|
||||
super(sessionFactory);
|
||||
@@ -112,88 +107,79 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
List<FeedEntryStatus> statuses = query.list(status);
|
||||
for (FeedEntryStatus status : statuses) {
|
||||
status = handleStatus(user, status, status.getSubscription(), status.getEntry());
|
||||
status = fetchTags(user, status);
|
||||
fetchTags(user, status);
|
||||
}
|
||||
return lazyLoadContent(includeContent, statuses);
|
||||
}
|
||||
|
||||
private Criteria buildSearchCriteria(User user, FeedSubscription sub, boolean unreadOnly, String keywords, Date newerThan, int offset,
|
||||
private HibernateQuery buildQuery(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 criteria = currentSession().createCriteria(FeedEntry.class, ALIAS_ENTRY);
|
||||
criteria.add(Restrictions.eq(entry.feed.getMetadata().getName(), sub.getFeed()));
|
||||
HibernateQuery query = newQuery().from(entry).where(entry.feed.eq(sub.getFeed()));
|
||||
|
||||
if (keywords != null) {
|
||||
Criteria contentJoin = criteria.createCriteria(entry.content.getMetadata().getName(), "content", JoinType.INNER_JOIN);
|
||||
query.join(entry.content, content);
|
||||
|
||||
for (String keyword : StringUtils.split(keywords)) {
|
||||
Disjunction or = Restrictions.disjunction();
|
||||
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);
|
||||
BooleanBuilder or = new BooleanBuilder();
|
||||
or.or(content.content.containsIgnoreCase(keyword));
|
||||
or.or(content.title.containsIgnoreCase(keyword));
|
||||
query.where(or);
|
||||
}
|
||||
}
|
||||
Criteria statusJoin = criteria.createCriteria(entry.statuses.getMetadata().getName(), ALIAS_STATUS, JoinType.LEFT_OUTER_JOIN,
|
||||
Restrictions.eq(status.subscription.getMetadata().getName(), sub));
|
||||
query.leftJoin(entry.statuses, status).on(status.subscription.id.eq(sub.getId()));
|
||||
|
||||
if (unreadOnly && tag == null) {
|
||||
|
||||
Disjunction or = Restrictions.disjunction();
|
||||
or.add(Restrictions.isNull(status.read.getMetadata().getName()));
|
||||
or.add(Restrictions.eq(status.read.getMetadata().getName(), false));
|
||||
statusJoin.add(or);
|
||||
BooleanBuilder or = new BooleanBuilder();
|
||||
or.or(status.read.isNull());
|
||||
or.or(status.read.isFalse());
|
||||
query.where(or);
|
||||
|
||||
Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
|
||||
if (unreadThreshold != null) {
|
||||
criteria.add(Restrictions.ge(entry.updated.getMetadata().getName(), unreadThreshold));
|
||||
query.where(entry.updated.goe(unreadThreshold));
|
||||
}
|
||||
}
|
||||
|
||||
if (tag != null) {
|
||||
Conjunction and = Restrictions.conjunction();
|
||||
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);
|
||||
BooleanBuilder and = new BooleanBuilder();
|
||||
and.and(entryTag.user.id.eq(user.getId()));
|
||||
and.and(entryTag.name.eq(tag));
|
||||
query.join(entry.tags, entryTag).on(and);
|
||||
}
|
||||
|
||||
if (newerThan != null) {
|
||||
criteria.add(Restrictions.ge(entry.inserted.getMetadata().getName(), newerThan));
|
||||
query.where(entry.inserted.goe(newerThan));
|
||||
}
|
||||
|
||||
if (last != null) {
|
||||
if (order == ReadingOrder.desc) {
|
||||
criteria.add(Restrictions.gt(entry.updated.getMetadata().getName(), last));
|
||||
query.where(entry.updated.gt(last));
|
||||
} else {
|
||||
criteria.add(Restrictions.lt(entry.updated.getMetadata().getName(), last));
|
||||
query.where(entry.updated.lt(last));
|
||||
}
|
||||
}
|
||||
|
||||
if (order != null) {
|
||||
if (order == ReadingOrder.asc) {
|
||||
criteria.addOrder(Order.asc(entry.updated.getMetadata().getName())).addOrder(Order.asc(entry.id.getMetadata().getName()));
|
||||
query.orderBy(entry.updated.asc(), entry.id.asc());
|
||||
} else {
|
||||
criteria.addOrder(Order.desc(entry.updated.getMetadata().getName())).addOrder(Order.desc(entry.id.getMetadata().getName()));
|
||||
query.orderBy(entry.updated.desc(), entry.id.desc());
|
||||
}
|
||||
}
|
||||
if (offset > -1) {
|
||||
criteria.setFirstResult(offset);
|
||||
query.offset(offset);
|
||||
}
|
||||
if (limit > -1) {
|
||||
criteria.setMaxResults(limit);
|
||||
query.limit(limit);
|
||||
}
|
||||
int timeout = config.getApplicationSettings().getQueryTimeout();
|
||||
if (timeout > 0) {
|
||||
// hibernate timeout is in seconds, jpa timeout is in millis
|
||||
criteria.setTimeout(timeout / 1000);
|
||||
query.setTimeout(timeout / 1000);
|
||||
}
|
||||
return criteria;
|
||||
return query;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly, String keywords,
|
||||
Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent, boolean onlyIds, String tag) {
|
||||
int capacity = offset + limit;
|
||||
@@ -201,18 +187,12 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
FixedSizeSortedSet<FeedEntryStatus> set = new FixedSizeSortedSet<FeedEntryStatus>(capacity, comparator);
|
||||
for (FeedSubscription sub : subs) {
|
||||
Date last = (order != null && set.isFull()) ? set.last().getEntryUpdated() : null;
|
||||
Criteria criteria = buildSearchCriteria(user, sub, unreadOnly, keywords, newerThan, -1, capacity, order, last, tag);
|
||||
ProjectionList projection = Projections.projectionList();
|
||||
projection.add(Projections.property("id"), "id");
|
||||
projection.add(Projections.property("updated"), "updated");
|
||||
projection.add(Projections.property(ALIAS_STATUS + ".id"), "status_id");
|
||||
criteria.setProjection(projection);
|
||||
criteria.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
|
||||
List<Map<String, Object>> list = criteria.list();
|
||||
for (Map<String, Object> map : list) {
|
||||
Long id = (Long) map.get("id");
|
||||
Date updated = (Date) map.get("updated");
|
||||
Long statusId = (Long) map.get("status_id");
|
||||
HibernateQuery query = buildQuery(user, sub, unreadOnly, keywords, newerThan, -1, capacity, order, last, tag);
|
||||
List<Tuple> tuples = query.list(entry.id, entry.updated, status.id);
|
||||
for (Tuple tuple : tuples) {
|
||||
Long id = tuple.get(entry.id);
|
||||
Date updated = tuple.get(entry.updated);
|
||||
Long statusId = tuple.get(status.id);
|
||||
|
||||
FeedEntry entry = new FeedEntry();
|
||||
entry.setId(id);
|
||||
@@ -253,19 +233,13 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
return statuses;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public UnreadCount getUnreadCount(User user, FeedSubscription subscription) {
|
||||
UnreadCount uc = null;
|
||||
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(QFeedEntry.feedEntry.updated.getMetadata().getName()), "updated");
|
||||
criteria.setProjection(projection);
|
||||
criteria.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
|
||||
List<Map<String, Object>> list = criteria.list();
|
||||
for (Map<String, Object> row : list) {
|
||||
Long count = (Long) row.get("count");
|
||||
Date updated = (Date) row.get("updated");
|
||||
HibernateQuery query = buildQuery(user, subscription, true, null, null, -1, -1, null, null, null);
|
||||
List<Tuple> tuples = query.list(entry.count(), entry.updated.max());
|
||||
for (Tuple tuple : tuples) {
|
||||
Long count = tuple.get(entry.count());
|
||||
Date updated = tuple.get(entry.updated.max());
|
||||
uc = new UnreadCount(subscription.getId(), count, updated);
|
||||
}
|
||||
return uc;
|
||||
|
||||
@@ -2,24 +2,28 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryTag;
|
||||
import com.commafeed.backend.model.QFeedEntryTag;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.mysema.query.types.ConstructorExpression;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryTagDAO extends GenericDAO<FeedEntryTag> {
|
||||
|
||||
private QFeedEntryTag tag = QFeedEntryTag.feedEntryTag;
|
||||
|
||||
@Inject
|
||||
public FeedEntryTagDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
public List<String> findByUser(User user) {
|
||||
return newQuery().from(tag).where(tag.user.eq(user)).distinct().list(ConstructorExpression.create(String.class, tag.name));
|
||||
return newQuery().from(tag).where(tag.user.eq(user)).distinct().list(tag.name);
|
||||
}
|
||||
|
||||
public List<FeedEntryTag> findByEntry(User user, FeedEntry entry) {
|
||||
|
||||
@@ -2,6 +2,9 @@ package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
@@ -15,10 +18,12 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
|
||||
|
||||
private QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||
|
||||
@Inject
|
||||
public FeedSubscriptionDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
|
||||
public abstract class GenericDAO<T extends AbstractModel> extends AbstractDAO<T> {
|
||||
|
||||
public GenericDAO(SessionFactory sessionFactory) {
|
||||
protected GenericDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
@@ -56,9 +56,4 @@ public abstract class GenericDAO<T extends AbstractModel> extends AbstractDAO<T>
|
||||
return objects.size();
|
||||
}
|
||||
|
||||
protected void setTimeout(javax.persistence.Query query, int queryTimeout) {
|
||||
if (queryTimeout > 0) {
|
||||
query.setHint("javax.persistence.query.timeout", queryTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.QUser;
|
||||
import com.commafeed.backend.model.QUserRole;
|
||||
import com.commafeed.backend.model.User;
|
||||
|
||||
@Singleton
|
||||
public class UserDAO extends GenericDAO<User> {
|
||||
|
||||
private QUser user = QUser.user;
|
||||
|
||||
@Inject
|
||||
public UserDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.commafeed.backend.dao;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.QUserRole;
|
||||
@@ -11,10 +14,12 @@ import com.commafeed.backend.model.UserRole;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
@Singleton
|
||||
public class UserRoleDAO extends GenericDAO<UserRole> {
|
||||
|
||||
private QUserRole role = QUserRole.userRole;
|
||||
|
||||
@Inject
|
||||
public UserRoleDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.QUserSettings;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserSettings;
|
||||
|
||||
@Singleton
|
||||
public class UserSettingsDAO extends GenericDAO<UserSettings> {
|
||||
|
||||
private QUserSettings settings = QUserSettings.userSettings;
|
||||
|
||||
@Inject
|
||||
public UserSettingsDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.commafeed.backend.favicon;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractFaviconFetcher {
|
||||
|
||||
private static List<String> ICON_MIMETYPE_BLACKLIST = Arrays.asList("application/xml", "text/html");
|
||||
private static long MIN_ICON_LENGTH = 100;
|
||||
private static long MAX_ICON_LENGTH = 100000;
|
||||
|
||||
protected static int TIMEOUT = 4000;
|
||||
|
||||
public abstract byte[] fetch(Feed feed);
|
||||
|
||||
protected boolean isValidIconResponse(byte[] content, String contentType) {
|
||||
if (content == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long length = content.length;
|
||||
|
||||
if (StringUtils.isNotBlank(contentType)) {
|
||||
contentType = contentType.split(";")[0];
|
||||
}
|
||||
|
||||
if (ICON_MIMETYPE_BLACKLIST.contains(contentType)) {
|
||||
log.debug("Content-Type {} is blacklisted", contentType);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length < MIN_ICON_LENGTH) {
|
||||
log.debug("Length {} below MIN_ICON_LENGTH {}", length, MIN_ICON_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length > MAX_ICON_LENGTH) {
|
||||
log.debug("Length {} greater than MAX_ICON_LENGTH {}", length, MAX_ICON_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,156 +1,123 @@
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
|
||||
/**
|
||||
* Inspired/Ported from https://github.com/potatolondon/getfavicon
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class FaviconFetcher {
|
||||
|
||||
private static long MIN_ICON_LENGTH = 100;
|
||||
private static long MAX_ICON_LENGTH = 100000;
|
||||
private static int TIMEOUT = 4000;
|
||||
|
||||
protected static List<String> ICON_MIMETYPES = Arrays.asList("image/x-icon", "image/vnd.microsoft.icon", "image/ico", "image/icon",
|
||||
"text/ico", "application/ico", "image/x-ms-bmp", "image/x-bmp", "image/gif", "image/png", "image/jpeg");
|
||||
private static List<String> ICON_MIMETYPE_BLACKLIST = Arrays.asList("application/xml", "text/html");
|
||||
|
||||
private final HttpGetter getter;
|
||||
|
||||
public byte[] fetch(String url) {
|
||||
|
||||
if (url == null) {
|
||||
log.debug("url is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
int doubleSlash = url.indexOf("//");
|
||||
if (doubleSlash == -1) {
|
||||
doubleSlash = 0;
|
||||
} else {
|
||||
doubleSlash += 2;
|
||||
}
|
||||
int firstSlash = url.indexOf('/', doubleSlash);
|
||||
if (firstSlash != -1) {
|
||||
url = url.substring(0, firstSlash);
|
||||
}
|
||||
|
||||
byte[] icon = getIconAtRoot(url);
|
||||
|
||||
if (icon == null) {
|
||||
icon = getIconInPage(url);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private byte[] getIconAtRoot(String url) {
|
||||
byte[] bytes = null;
|
||||
String contentType = null;
|
||||
|
||||
try {
|
||||
url = FeedUtils.removeTrailingSlash(url) + "/favicon.ico";
|
||||
log.debug("getting root icon at {}", url);
|
||||
HttpResult result = getter.getBinary(url, TIMEOUT);
|
||||
bytes = result.getContent();
|
||||
contentType = result.getContentType();
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to retrieve iconAtRoot: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (!isValidIconResponse(bytes, contentType)) {
|
||||
bytes = null;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private boolean isValidIconResponse(byte[] content, String contentType) {
|
||||
if (content == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long length = content.length;
|
||||
|
||||
if (StringUtils.isNotBlank(contentType)) {
|
||||
contentType = contentType.split(";")[0];
|
||||
}
|
||||
|
||||
if (ICON_MIMETYPE_BLACKLIST.contains(contentType)) {
|
||||
log.debug("Content-Type {} is blacklisted", contentType);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length < MIN_ICON_LENGTH) {
|
||||
log.debug("Length {} below MIN_ICON_LENGTH {}", length, MIN_ICON_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length > MAX_ICON_LENGTH) {
|
||||
log.debug("Length {} greater than MAX_ICON_LENGTH {}", length, MAX_ICON_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private byte[] getIconInPage(String url) {
|
||||
|
||||
Document doc = null;
|
||||
try {
|
||||
HttpResult result = getter.getBinary(url, TIMEOUT);
|
||||
doc = Jsoup.parse(new String(result.getContent()), url);
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to retrieve page to find icon");
|
||||
return null;
|
||||
}
|
||||
|
||||
Elements icons = doc.select("link[rel~=(?i)^(shortcut|icon|shortcut icon)$]");
|
||||
|
||||
if (icons.isEmpty()) {
|
||||
log.debug("No icon found in page {}", url);
|
||||
return null;
|
||||
}
|
||||
|
||||
String href = icons.get(0).attr("abs:href");
|
||||
if (StringUtils.isBlank(href)) {
|
||||
log.debug("No icon found in page");
|
||||
return null;
|
||||
}
|
||||
|
||||
log.debug("Found unconfirmed iconInPage at {}", href);
|
||||
|
||||
byte[] bytes = null;
|
||||
String contentType = null;
|
||||
try {
|
||||
HttpResult result = getter.getBinary(href, TIMEOUT);
|
||||
bytes = result.getContent();
|
||||
contentType = result.getContentType();
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to retrieve icon found in page {}", href);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isValidIconResponse(bytes, contentType)) {
|
||||
log.debug("Invalid icon found for {}", href);
|
||||
return null;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
}
|
||||
package com.commafeed.backend.favicon;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
/**
|
||||
* Inspired/Ported from https://github.com/potatolondon/getfavicon
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
||||
|
||||
private final HttpGetter getter;
|
||||
|
||||
@Override
|
||||
public byte[] fetch(Feed feed) {
|
||||
String url = feed.getLink() != null ? feed.getLink() : feed.getUrl();
|
||||
|
||||
if (url == null) {
|
||||
log.debug("url is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
int doubleSlash = url.indexOf("//");
|
||||
if (doubleSlash == -1) {
|
||||
doubleSlash = 0;
|
||||
} else {
|
||||
doubleSlash += 2;
|
||||
}
|
||||
int firstSlash = url.indexOf('/', doubleSlash);
|
||||
if (firstSlash != -1) {
|
||||
url = url.substring(0, firstSlash);
|
||||
}
|
||||
|
||||
byte[] icon = getIconAtRoot(url);
|
||||
|
||||
if (icon == null) {
|
||||
icon = getIconInPage(url);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private byte[] getIconAtRoot(String url) {
|
||||
byte[] bytes = null;
|
||||
String contentType = null;
|
||||
|
||||
try {
|
||||
url = FeedUtils.removeTrailingSlash(url) + "/favicon.ico";
|
||||
log.debug("getting root icon at {}", url);
|
||||
HttpResult result = getter.getBinary(url, TIMEOUT);
|
||||
bytes = result.getContent();
|
||||
contentType = result.getContentType();
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to retrieve iconAtRoot for url {}: ", url, e);
|
||||
}
|
||||
|
||||
if (!isValidIconResponse(bytes, contentType)) {
|
||||
bytes = null;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private byte[] getIconInPage(String url) {
|
||||
|
||||
Document doc = null;
|
||||
try {
|
||||
HttpResult result = getter.getBinary(url, TIMEOUT);
|
||||
doc = Jsoup.parse(new String(result.getContent()), url);
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to retrieve page to find icon", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
Elements icons = doc.select("link[rel~=(?i)^(shortcut|icon|shortcut icon)$]");
|
||||
|
||||
if (icons.isEmpty()) {
|
||||
log.debug("No icon found in page {}", url);
|
||||
return null;
|
||||
}
|
||||
|
||||
String href = icons.get(0).attr("abs:href");
|
||||
if (StringUtils.isBlank(href)) {
|
||||
log.debug("No icon found in page");
|
||||
return null;
|
||||
}
|
||||
|
||||
log.debug("Found unconfirmed iconInPage at {}", href);
|
||||
|
||||
byte[] bytes = null;
|
||||
String contentType = null;
|
||||
try {
|
||||
HttpResult result = getter.getBinary(href, TIMEOUT);
|
||||
bytes = result.getContent();
|
||||
contentType = result.getContentType();
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to retrieve icon found in page {}", href, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isValidIconResponse(bytes, contentType)) {
|
||||
log.debug("Invalid icon found for {}", href);
|
||||
return null;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.commafeed.backend.favicon;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
|
||||
|
||||
private final HttpGetter getter;
|
||||
|
||||
@Override
|
||||
public byte[] fetch(Feed feed) {
|
||||
String url = feed.getUrl();
|
||||
|
||||
if (!url.toLowerCase().contains("://gdata.youtube.com/")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String userName = extractUserName(url);
|
||||
if (userName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String profileUrl = "https://gdata.youtube.com/feeds/users/" + userName;
|
||||
|
||||
byte[] bytes = null;
|
||||
String contentType = null;
|
||||
|
||||
try {
|
||||
log.debug("Getting YouTube user's icon, {}", url);
|
||||
|
||||
// initial get to translate username to obscure user thumbnail URL
|
||||
HttpResult profileResult = getter.getBinary(profileUrl, TIMEOUT);
|
||||
Document doc = Jsoup.parse(new String(profileResult.getContent()), profileUrl);
|
||||
|
||||
Elements thumbnails = doc.select("media|thumbnail");
|
||||
if (thumbnails.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String thumbnailUrl = thumbnails.get(0).attr("abs:url");
|
||||
|
||||
int thumbnailStart = thumbnailUrl.indexOf("<media:thumbnail url='");
|
||||
int thumbnailEnd = thumbnailUrl.indexOf("'/>", thumbnailStart);
|
||||
if (thumbnailStart != -1) {
|
||||
thumbnailUrl = thumbnailUrl.substring(thumbnailStart + "<media:thumbnail url='".length(), thumbnailEnd);
|
||||
}
|
||||
|
||||
// final get to actually retrieve the thumbnail
|
||||
HttpResult iconResult = getter.getBinary(thumbnailUrl, TIMEOUT);
|
||||
bytes = iconResult.getContent();
|
||||
contentType = iconResult.getContentType();
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to retrieve YouTube icon", e);
|
||||
}
|
||||
|
||||
if (!isValidIconResponse(bytes, contentType)) {
|
||||
bytes = null;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private String extractUserName(String url) {
|
||||
int apiOrBase = url.indexOf("/users/");
|
||||
if (apiOrBase == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int userEndSlash = url.indexOf('/', apiOrBase + "/users/".length());
|
||||
if (userEndSlash == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return url.substring(apiOrBase + "/users/".length(), userEndSlash);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* This code is copied and simplified from GWT
|
||||
* https://github.com/google-web-toolkit/gwt/blob/master/user/src/com/google/gwt/i18n/shared/BidiUtils.java Released under Apache 2.0
|
||||
* license, credit of it goes to Google and please use GWT wherever possible instead of this
|
||||
*/
|
||||
class EstimateDirection {
|
||||
private static final float RTL_DETECTION_THRESHOLD = 0.40f;
|
||||
|
||||
private static final String LTR_CHARS = "A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF"
|
||||
+ "\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF";
|
||||
private static final String RTL_CHARS = "\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC";
|
||||
|
||||
private static final Pattern WORD_SEPARATOR_RE = Pattern.compile("\\s+");
|
||||
private static final Pattern FIRST_STRONG_IS_RTL_RE = Pattern.compile("^[^" + LTR_CHARS + "]*[" + RTL_CHARS + ']');
|
||||
private static final Pattern IS_REQUIRED_LTR_RE = Pattern.compile("^http://.*");
|
||||
private static final Pattern HAS_ANY_LTR_RE = Pattern.compile("[" + LTR_CHARS + ']');
|
||||
|
||||
private static boolean startsWithRtl(String str) {
|
||||
return FIRST_STRONG_IS_RTL_RE.matcher(str).matches();
|
||||
}
|
||||
|
||||
private static boolean hasAnyLtr(String str) {
|
||||
return HAS_ANY_LTR_RE.matcher(str).matches();
|
||||
}
|
||||
|
||||
static boolean isRTL(String str) {
|
||||
int rtlCount = 0;
|
||||
int total = 0;
|
||||
String[] tokens = WORD_SEPARATOR_RE.split(str, 20); // limit splits to 20, usually enough
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
String token = tokens[i];
|
||||
if (startsWithRtl(token)) {
|
||||
rtlCount++;
|
||||
total++;
|
||||
} else if (IS_REQUIRED_LTR_RE.matcher(token).matches()) {
|
||||
// do nothing
|
||||
} else if (hasAnyLtr(token)) {
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
return total == 0 ? false : ((float) rtlCount / total > RTL_DETECTION_THRESHOLD ? true : false);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,10 @@ package com.commafeed.backend.feed;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
@@ -17,10 +20,11 @@ import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.sun.syndication.io.FeedException;
|
||||
import com.rometools.rome.io.FeedException;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class FeedFetcher {
|
||||
|
||||
private final FeedParser parser;
|
||||
@@ -73,7 +77,7 @@ public class FeedFetcher {
|
||||
|
||||
Feed feed = fetchedFeed.getFeed();
|
||||
feed.setLastModifiedHeader(result.getLastModifiedSince());
|
||||
feed.setEtagHeader(FeedUtils.truncate(result.geteTag(), 255));
|
||||
feed.setEtagHeader(FeedUtils.truncate(result.getETag(), 255));
|
||||
feed.setLastContentHash(hash);
|
||||
fetchedFeed.setFetchDuration(result.getDuration());
|
||||
fetchedFeed.setUrlAfterRedirect(result.getUrlAfterRedirect());
|
||||
@@ -89,9 +93,9 @@ public class FeedFetcher {
|
||||
Elements atom = doc.select("link[type=application/atom+xml]");
|
||||
Elements rss = doc.select("link[type=application/rss+xml]");
|
||||
if (!atom.isEmpty()) {
|
||||
foundUrl = atom.get(0).attr("abs:href").toString();
|
||||
foundUrl = atom.get(0).attr("abs:href");
|
||||
} else if (!rss.isEmpty()) {
|
||||
foundUrl = rss.get(0).attr("abs:href").toString();
|
||||
foundUrl = rss.get(0).attr("abs:href");
|
||||
}
|
||||
}
|
||||
return foundUrl;
|
||||
|
||||
@@ -5,12 +5,16 @@ import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.SystemUtils;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.Namespace;
|
||||
import org.jdom2.Element;
|
||||
import org.jdom2.Namespace;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
@@ -19,16 +23,18 @@ import com.commafeed.backend.model.FeedEntryContent;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sun.syndication.feed.synd.SyndContent;
|
||||
import com.sun.syndication.feed.synd.SyndEnclosure;
|
||||
import com.sun.syndication.feed.synd.SyndEntry;
|
||||
import com.sun.syndication.feed.synd.SyndFeed;
|
||||
import com.sun.syndication.feed.synd.SyndLink;
|
||||
import com.sun.syndication.feed.synd.SyndLinkImpl;
|
||||
import com.sun.syndication.io.FeedException;
|
||||
import com.sun.syndication.io.SyndFeedInput;
|
||||
import com.rometools.rome.feed.synd.SyndContent;
|
||||
import com.rometools.rome.feed.synd.SyndEnclosure;
|
||||
import com.rometools.rome.feed.synd.SyndEntry;
|
||||
import com.rometools.rome.feed.synd.SyndFeed;
|
||||
import com.rometools.rome.feed.synd.SyndLink;
|
||||
import com.rometools.rome.feed.synd.SyndLinkImpl;
|
||||
import com.rometools.rome.io.FeedException;
|
||||
import com.rometools.rome.io.SyndFeedInput;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class FeedParser {
|
||||
|
||||
private static final String ATOM_10_URI = "http://www.w3.org/2005/Atom";
|
||||
@@ -38,12 +44,12 @@ public class FeedParser {
|
||||
private static final Date END = new Date(1000l * Integer.MAX_VALUE - 86400000);
|
||||
|
||||
private static final Function<SyndContent, String> CONTENT_TO_STRING = new Function<SyndContent, String>() {
|
||||
@Override
|
||||
public String apply(SyndContent content) {
|
||||
return content.getValue();
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public FetchedFeed parse(String feedUrl, byte[] xml) throws FeedException {
|
||||
FetchedFeed fetchedFeed = new FetchedFeed();
|
||||
Feed feed = fetchedFeed.getFeed();
|
||||
@@ -81,7 +87,7 @@ public class FeedParser {
|
||||
entry.setGuid(FeedUtils.truncate(guid, 2048));
|
||||
entry.setUpdated(validateDate(getEntryUpdateDate(item), true));
|
||||
entry.setUrl(FeedUtils.truncate(FeedUtils.toAbsoluteUrl(item.getLink(), feed.getLink(), feed.getUrlAfterRedirect()), 2048));
|
||||
|
||||
|
||||
// if link is empty but guid is used as url
|
||||
if (StringUtils.isBlank(entry.getUrl()) && StringUtils.startsWith(entry.getGuid(), "http")) {
|
||||
entry.setUrl(entry.getGuid());
|
||||
@@ -91,7 +97,7 @@ public class FeedParser {
|
||||
content.setContent(getContent(item));
|
||||
content.setTitle(getTitle(item));
|
||||
content.setAuthor(StringUtils.trimToNull(item.getAuthor()));
|
||||
SyndEnclosure enclosure = (SyndEnclosure) Iterables.getFirst(item.getEnclosures(), null);
|
||||
SyndEnclosure enclosure = Iterables.getFirst(item.getEnclosures(), null);
|
||||
if (enclosure != null) {
|
||||
content.setEnclosureUrl(FeedUtils.truncate(enclosure.getUrl(), 2048));
|
||||
content.setEnclosureType(enclosure.getType());
|
||||
@@ -121,24 +127,17 @@ public class FeedParser {
|
||||
/**
|
||||
* Adds atom links for rss feeds
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private void handleForeignMarkup(SyndFeed feed) {
|
||||
Object foreignMarkup = feed.getForeignMarkup();
|
||||
List<Element> foreignMarkup = feed.getForeignMarkup();
|
||||
if (foreignMarkup == null) {
|
||||
return;
|
||||
}
|
||||
if (foreignMarkup instanceof List) {
|
||||
List elements = (List) foreignMarkup;
|
||||
for (Object object : elements) {
|
||||
if (object instanceof Element) {
|
||||
Element element = (Element) object;
|
||||
if ("link".equals(element.getName()) && ATOM_10_NS.equals(element.getNamespace())) {
|
||||
SyndLink link = new SyndLinkImpl();
|
||||
link.setRel(element.getAttributeValue("rel"));
|
||||
link.setHref(element.getAttributeValue("href"));
|
||||
feed.getLinks().add(link);
|
||||
}
|
||||
}
|
||||
for (Element element : foreignMarkup) {
|
||||
if ("link".equals(element.getName()) && ATOM_10_NS.equals(element.getNamespace())) {
|
||||
SyndLink link = new SyndLinkImpl();
|
||||
link.setRel(element.getAttributeValue("rel"));
|
||||
link.setHref(element.getAttributeValue("href"));
|
||||
feed.getLinks().add(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +168,6 @@ public class FeedParser {
|
||||
return date;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String getContent(SyndEntry item) {
|
||||
String content = null;
|
||||
if (item.getContents().isEmpty()) {
|
||||
@@ -193,9 +191,8 @@ public class FeedParser {
|
||||
return StringUtils.trimToNull(title);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String findHub(SyndFeed feed) {
|
||||
for (SyndLink l : (List<SyndLink>) feed.getLinks()) {
|
||||
for (SyndLink l : feed.getLinks()) {
|
||||
if ("hub".equalsIgnoreCase(l.getRel())) {
|
||||
log.debug("found hub {} for feed {}", l.getHref(), feed.getLink());
|
||||
return l.getHref();
|
||||
@@ -204,9 +201,8 @@ public class FeedParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String findSelf(SyndFeed feed) {
|
||||
for (SyndLink l : (List<SyndLink>) feed.getLinks()) {
|
||||
for (SyndLink l : feed.getLinks()) {
|
||||
if ("self".equalsIgnoreCase(l.getRel())) {
|
||||
log.debug("found self {} for feed {}", l.getHref(), feed.getLink());
|
||||
return l.getHref();
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
@@ -20,6 +21,7 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Queues;
|
||||
|
||||
@Singleton
|
||||
public class FeedQueues {
|
||||
|
||||
private final FeedDAO feedDAO;
|
||||
@@ -76,7 +78,16 @@ public class FeedQueues {
|
||||
public void add(Feed feed, boolean urgent) {
|
||||
int refreshInterval = config.getApplicationSettings().getRefreshIntervalMinutes();
|
||||
if (feed.getLastUpdated() == null || feed.getLastUpdated().before(DateUtils.addMinutes(new Date(), -1 * refreshInterval))) {
|
||||
addQueue.add(new FeedRefreshContext(feed, urgent));
|
||||
boolean alreadyQueued = false;
|
||||
for (FeedRefreshContext context : addQueue) {
|
||||
if (context.getFeed().getId().equals(feed.getId())) {
|
||||
alreadyQueued = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!alreadyQueued) {
|
||||
addQueue.add(new FeedRefreshContext(feed, urgent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -22,6 +23,7 @@ import com.commafeed.backend.dao.UnitOfWork;
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class FeedRefreshTaskGiver implements Managed {
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
@@ -69,15 +71,13 @@ public class FeedRefreshTaskGiver implements Managed {
|
||||
FeedRefreshContext context = new UnitOfWork<FeedRefreshContext>(sessionFactory) {
|
||||
@Override
|
||||
protected FeedRefreshContext runInSession() throws Exception {
|
||||
FeedRefreshContext context = queues.take();
|
||||
if (context != null) {
|
||||
feedRefreshed.mark();
|
||||
worker.updateFeed(context);
|
||||
}
|
||||
return context;
|
||||
return queues.take();
|
||||
}
|
||||
}.run();
|
||||
if (context == null) {
|
||||
if (context != null) {
|
||||
feedRefreshed.mark();
|
||||
worker.updateFeed(context);
|
||||
} else {
|
||||
log.debug("nothing to do, sleeping for 15s");
|
||||
threadWaited.mark();
|
||||
try {
|
||||
|
||||
@@ -9,10 +9,13 @@ import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
@@ -36,6 +39,7 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.Striped;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class FeedRefreshUpdater implements Managed {
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
@@ -54,6 +58,7 @@ public class FeedRefreshUpdater implements Managed {
|
||||
private Meter feedUpdated;
|
||||
private Meter entryInserted;
|
||||
|
||||
@Inject
|
||||
public FeedRefreshUpdater(SessionFactory sessionFactory, FeedUpdateService feedUpdateService, PubSubService pubSubService,
|
||||
FeedQueues queues, CommaFeedConfiguration config, MetricRegistry metrics, FeedSubscriptionDAO feedSubscriptionDAO,
|
||||
CacheService cache) {
|
||||
@@ -100,18 +105,8 @@ public class FeedRefreshUpdater implements Managed {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
new UnitOfWork<Void>(sessionFactory) {
|
||||
@Override
|
||||
protected Void runInSession() throws Exception {
|
||||
internalRun();
|
||||
return null;
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
public void internalRun() {
|
||||
boolean ok = true;
|
||||
Feed feed = context.getFeed();
|
||||
final Feed feed = context.getFeed();
|
||||
List<FeedEntry> entries = context.getEntries();
|
||||
if (entries.isEmpty()) {
|
||||
feed.setMessage("Feed has no entries");
|
||||
@@ -125,7 +120,12 @@ public class FeedRefreshUpdater implements Managed {
|
||||
if (!lastEntries.contains(cacheKey)) {
|
||||
log.debug("cache miss for {}", entry.getUrl());
|
||||
if (subscriptions == null) {
|
||||
subscriptions = feedSubscriptionDAO.findByFeed(feed);
|
||||
subscriptions = new UnitOfWork<List<FeedSubscription>>(sessionFactory) {
|
||||
@Override
|
||||
protected List<FeedSubscription> runInSession() throws Exception {
|
||||
return feedSubscriptionDAO.findByFeed(feed);
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
ok &= addEntry(feed, entry, subscriptions);
|
||||
entryCacheMiss.mark();
|
||||
@@ -190,7 +190,12 @@ public class FeedRefreshUpdater implements Managed {
|
||||
locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
|
||||
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
||||
if (locked1 && locked2) {
|
||||
boolean inserted = feedUpdateService.addEntry(feed, entry);
|
||||
boolean inserted = new UnitOfWork<Boolean>(sessionFactory) {
|
||||
@Override
|
||||
protected Boolean runInSession() throws Exception {
|
||||
return feedUpdateService.addEntry(feed, entry);
|
||||
}
|
||||
}.run();
|
||||
if (inserted) {
|
||||
entryInserted.mark();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import io.dropwizard.lifecycle.Managed;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
@@ -24,6 +27,7 @@ import com.google.common.base.Optional;
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class FeedRefreshWorker implements Managed {
|
||||
|
||||
private final FeedRefreshUpdater feedRefreshUpdater;
|
||||
@@ -32,6 +36,7 @@ public class FeedRefreshWorker implements Managed {
|
||||
private final CommaFeedConfiguration config;
|
||||
private final FeedRefreshExecutor pool;
|
||||
|
||||
@Inject
|
||||
public FeedRefreshWorker(FeedRefreshUpdater feedRefreshUpdater, FeedFetcher fetcher, FeedQueues queues, CommaFeedConfiguration config,
|
||||
MetricRegistry metrics) {
|
||||
this.feedRefreshUpdater = feedRefreshUpdater;
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.apache.commons.math.stat.descriptive.SummaryStatistics;
|
||||
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Document.OutputSettings;
|
||||
@@ -33,8 +33,6 @@ import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.frontend.model.Entry;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gwt.i18n.client.HasDirection.Direction;
|
||||
import com.google.gwt.i18n.shared.BidiUtils;
|
||||
import com.steadystate.css.parser.CSSOMParser;
|
||||
|
||||
import edu.uci.ics.crawler4j.url.URLCanonicalizer;
|
||||
@@ -132,7 +130,7 @@ public class FeedUtils {
|
||||
public static String replaceHtmlEntitiesWithNumericEntities(String source) {
|
||||
String result = source;
|
||||
for (String entity : HtmlEntities.NUMERIC_MAPPING.keySet()) {
|
||||
result = result.replace(entity, HtmlEntities.NUMERIC_MAPPING.get(entity));
|
||||
result = StringUtils.replace(result, entity, HtmlEntities.NUMERIC_MAPPING.get(entity));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -291,8 +289,7 @@ public class FeedUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
Direction direction = BidiUtils.get().estimateDirection(text);
|
||||
return direction == Direction.RTL;
|
||||
return EstimateDirection.isRTL(text);
|
||||
}
|
||||
|
||||
public static String trimInvalidXmlCharacters(String xml) {
|
||||
@@ -520,5 +517,4 @@ public class FeedUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.commafeed.backend.feed;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.thirdparty.guava.common.collect.Maps;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class HtmlEntities {
|
||||
public static final Map<String, String> NUMERIC_MAPPING = Collections.unmodifiableMap(loadMap());
|
||||
@@ -260,7 +260,7 @@ public class HtmlEntities {
|
||||
map.put("ζ", "ζ");
|
||||
map.put("‍", "‍");
|
||||
map.put("‌", "‌");
|
||||
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
@@ -25,9 +23,6 @@ import com.google.common.collect.Lists;
|
||||
@SuppressWarnings("serial")
|
||||
@Getter
|
||||
@Setter
|
||||
@NamedQueries(@NamedQuery(
|
||||
name = "Statuses.deleteOld",
|
||||
query = "delete from FeedEntryStatus s where s.entryInserted < :date and s.starred = false"))
|
||||
public class FeedEntryStatus extends AbstractModel {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
|
||||
@@ -15,6 +15,7 @@ import javax.persistence.TemporalType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.hibernate.annotations.Cascade;
|
||||
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
@@ -77,5 +78,13 @@ public class User extends AbstractModel {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldRefreshFeedsAt(Date when) {
|
||||
return (lastFullRefresh == null || lastFullRefreshMoreThan30MinutesBefore(when));
|
||||
}
|
||||
|
||||
private boolean lastFullRefreshMoreThan30MinutesBefore(Date when) {
|
||||
return lastFullRefresh.before(DateUtils.addMinutes(when, -30));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,24 +3,27 @@ package com.commafeed.backend.opml;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.sun.syndication.feed.opml.Attribute;
|
||||
import com.sun.syndication.feed.opml.Opml;
|
||||
import com.sun.syndication.feed.opml.Outline;
|
||||
import com.rometools.opml.feed.opml.Attribute;
|
||||
import com.rometools.opml.feed.opml.Opml;
|
||||
import com.rometools.opml.feed.opml.Outline;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class OPMLExporter {
|
||||
|
||||
private final FeedCategoryDAO feedCategoryDAO;
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Opml export(User user) {
|
||||
Opml opml = new Opml();
|
||||
opml.setFeedType("opml_1.1");
|
||||
@@ -48,7 +51,6 @@ public class OPMLExporter {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Outline buildCategoryOutline(FeedCategory cat, List<FeedSubscription> subscriptions) {
|
||||
Outline outline = new Outline();
|
||||
outline.setText(cat.getName());
|
||||
@@ -66,7 +68,6 @@ public class OPMLExporter {
|
||||
return outline;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Outline buildSubscriptionOutline(FeedSubscription sub) {
|
||||
Outline outline = new Outline();
|
||||
outline.setText(sub.getTitle());
|
||||
|
||||
@@ -3,9 +3,13 @@ package com.commafeed.backend.opml;
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
@@ -15,25 +19,19 @@ import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.service.FeedSubscriptionService;
|
||||
import com.commafeed.backend.service.FeedSubscriptionService.FeedSubscriptionException;
|
||||
import com.sun.syndication.feed.opml.Opml;
|
||||
import com.sun.syndication.feed.opml.Outline;
|
||||
import com.sun.syndication.io.WireFeedInput;
|
||||
import com.rometools.opml.feed.opml.Opml;
|
||||
import com.rometools.opml.feed.opml.Outline;
|
||||
import com.rometools.rome.io.WireFeedInput;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class OPMLImporter {
|
||||
|
||||
private FeedCategoryDAO feedCategoryDAO;
|
||||
private FeedSubscriptionService feedSubscriptionService;
|
||||
private CacheService cache;
|
||||
private final FeedCategoryDAO feedCategoryDAO;
|
||||
private final FeedSubscriptionService feedSubscriptionService;
|
||||
private final CacheService cache;
|
||||
|
||||
public OPMLImporter(FeedCategoryDAO feedCategoryDAO, FeedSubscriptionService feedSubscriptionService, CacheService cache) {
|
||||
super();
|
||||
this.feedCategoryDAO = feedCategoryDAO;
|
||||
this.feedSubscriptionService = feedSubscriptionService;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void importOpml(User user, String xml) {
|
||||
xml = xml.substring(xml.indexOf('<'));
|
||||
WireFeedInput input = new WireFeedInput();
|
||||
@@ -49,7 +47,6 @@ public class OPMLImporter {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleOutline(User user, Outline outline, FeedCategory parent) {
|
||||
List<Outline> children = outline.getChildren();
|
||||
if (CollectionUtils.isNotEmpty(children)) {
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package com.commafeed.backend.rome;
|
||||
|
||||
import org.jdom.Element;
|
||||
import org.jdom2.Element;
|
||||
|
||||
import com.sun.syndication.feed.opml.Opml;
|
||||
import com.rometools.opml.feed.opml.Opml;
|
||||
|
||||
/**
|
||||
* Add missing title to the generated OPML
|
||||
*
|
||||
*/
|
||||
public class OPML11Generator extends com.sun.syndication.io.impl.OPML10Generator {
|
||||
public class OPML11Generator extends com.rometools.opml.io.impl.OPML10Generator {
|
||||
|
||||
public OPML11Generator() {
|
||||
super("opml_1.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Element generateHead(Opml opml) {
|
||||
Element head = new Element("head");
|
||||
addNotNullSimpleElement(head, "title", opml.getTitle());
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.commafeed.backend.rome;
|
||||
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jdom2.Document;
|
||||
import org.jdom2.Element;
|
||||
|
||||
import com.sun.syndication.io.impl.OPML10Parser;
|
||||
import com.rometools.opml.io.impl.OPML10Parser;
|
||||
|
||||
/**
|
||||
* Support for OPML 1.1 parsing
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.commafeed.backend.rome;
|
||||
|
||||
import com.sun.syndication.feed.rss.Description;
|
||||
import com.sun.syndication.feed.rss.Item;
|
||||
import com.sun.syndication.feed.synd.SyndContentImpl;
|
||||
import com.sun.syndication.feed.synd.SyndEntry;
|
||||
import com.sun.syndication.feed.synd.impl.ConverterForRSS090;
|
||||
import com.rometools.rome.feed.rss.Description;
|
||||
import com.rometools.rome.feed.rss.Item;
|
||||
import com.rometools.rome.feed.synd.SyndContentImpl;
|
||||
import com.rometools.rome.feed.synd.SyndEntry;
|
||||
import com.rometools.rome.feed.synd.impl.ConverterForRSS090;
|
||||
|
||||
/**
|
||||
* Support description tag for RSS09
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.commafeed.backend.rome;
|
||||
|
||||
import org.jdom.Element;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.sun.syndication.feed.rss.Description;
|
||||
import com.sun.syndication.feed.rss.Item;
|
||||
import com.sun.syndication.io.impl.RSS090Parser;
|
||||
import org.jdom2.Element;
|
||||
|
||||
import com.rometools.rome.feed.rss.Description;
|
||||
import com.rometools.rome.feed.rss.Item;
|
||||
import com.rometools.rome.io.impl.RSS090Parser;
|
||||
|
||||
/**
|
||||
* Support description tag for RSS09
|
||||
@@ -13,9 +15,8 @@ import com.sun.syndication.io.impl.RSS090Parser;
|
||||
public class RSS090DescriptionParser extends RSS090Parser {
|
||||
|
||||
@Override
|
||||
protected Item parseItem(Element rssRoot, Element eItem) {
|
||||
Item item = super.parseItem(rssRoot, eItem);
|
||||
|
||||
protected Item parseItem(Element rssRoot, Element eItem, Locale locale) {
|
||||
Item item = super.parseItem(rssRoot, eItem, locale);
|
||||
Element e = eItem.getChild("description", getRSSNamespace());
|
||||
if (e != null) {
|
||||
Description desc = new Description();
|
||||
@@ -25,5 +26,4 @@ public class RSS090DescriptionParser extends RSS090Parser {
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ package com.commafeed.backend.rome;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.Namespace;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.jdom2.Document;
|
||||
import org.jdom2.Element;
|
||||
import org.jdom2.Namespace;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sun.syndication.io.impl.RSS10Parser;
|
||||
import com.rometools.rome.io.impl.RSS10Parser;
|
||||
|
||||
public class RSSRDF10Parser extends RSS10Parser {
|
||||
|
||||
@@ -19,14 +19,13 @@ public class RSSRDF10Parser extends RSS10Parser {
|
||||
super("rss_1.0", RSS_NS);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public boolean isMyType(Document document) {
|
||||
boolean ok = false;
|
||||
|
||||
Element rssRoot = document.getRootElement();
|
||||
Namespace defaultNS = rssRoot.getNamespace();
|
||||
List additionalNSs = Lists.newArrayList(rssRoot.getAdditionalNamespaces());
|
||||
List<Namespace> additionalNSs = Lists.newArrayList(rssRoot.getAdditionalNamespaces());
|
||||
List<Element> children = rssRoot.getChildren();
|
||||
if (CollectionUtils.isNotEmpty(children)) {
|
||||
Element child = children.get(0);
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class ApplicationPropertiesService {
|
||||
|
||||
private ResourceBundle bundle;
|
||||
|
||||
public ApplicationPropertiesService() {
|
||||
bundle = ResourceBundle.getBundle("application");
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return bundle.getString("version");
|
||||
}
|
||||
|
||||
public String getGitCommit() {
|
||||
return bundle.getString("git.commit");
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -16,7 +19,6 @@ import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.UnitOfWork;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryStatus;
|
||||
|
||||
/**
|
||||
@@ -24,7 +26,8 @@ import com.commafeed.backend.model.FeedEntryStatus;
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class DatabaseCleaningService {
|
||||
|
||||
private static final int BATCH_SIZE = 100;
|
||||
@@ -35,25 +38,6 @@ public class DatabaseCleaningService {
|
||||
private final FeedEntryContentDAO feedEntryContentDAO;
|
||||
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
|
||||
public long cleanEntriesWithoutSubscriptions() {
|
||||
log.info("cleaning entries without subscriptions");
|
||||
long total = 0;
|
||||
int deleted = 0;
|
||||
do {
|
||||
deleted = new UnitOfWork<Integer>(sessionFactory) {
|
||||
@Override
|
||||
protected Integer runInSession() throws Exception {
|
||||
List<FeedEntry> entries = feedEntryDAO.findWithoutSubscriptions(BATCH_SIZE);
|
||||
return feedEntryDAO.delete(entries);
|
||||
}
|
||||
}.run();
|
||||
total += deleted;
|
||||
log.info("removed {} entries without subscriptions", total);
|
||||
} while (deleted != 0);
|
||||
log.info("cleanup done: {} entries without subscriptions deleted", total);
|
||||
return total;
|
||||
}
|
||||
|
||||
public long cleanFeedsWithoutSubscriptions() {
|
||||
log.info("cleaning feeds without subscriptions");
|
||||
long total = 0;
|
||||
@@ -62,7 +46,7 @@ public class DatabaseCleaningService {
|
||||
deleted = new UnitOfWork<Integer>(sessionFactory) {
|
||||
@Override
|
||||
protected Integer runInSession() throws Exception {
|
||||
List<Feed> feeds = feedDAO.findWithoutSubscriptions(BATCH_SIZE);
|
||||
List<Feed> feeds = feedDAO.findWithoutSubscriptions(1);
|
||||
return feedDAO.delete(feeds);
|
||||
};
|
||||
}.run();
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
@@ -9,7 +12,8 @@ import com.commafeed.backend.dao.FeedEntryContentDAO;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class FeedEntryContentService {
|
||||
|
||||
private final FeedEntryContentDAO feedEntryContentDAO;
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.commafeed.backend.service;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
@@ -15,7 +18,8 @@ import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class FeedEntryService {
|
||||
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.commafeed.backend.service;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
@@ -14,7 +17,8 @@ import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class FeedEntryTagService {
|
||||
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@@ -1,19 +1,39 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.favicon.AbstractFaviconFetcher;
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Singleton
|
||||
public class FeedService {
|
||||
|
||||
private final FeedDAO feedDAO;
|
||||
private final Set<AbstractFaviconFetcher> faviconFetchers;
|
||||
|
||||
private byte[] defaultFavicon;
|
||||
|
||||
@Inject
|
||||
public FeedService(FeedDAO feedDAO, Set<AbstractFaviconFetcher> faviconFetchers) {
|
||||
this.feedDAO = feedDAO;
|
||||
this.faviconFetchers = faviconFetchers;
|
||||
|
||||
try {
|
||||
defaultFavicon = IOUtils.toByteArray(getClass().getResource("/images/default_favicon.gif"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("could not load default favicon", e);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Feed findOrCreate(String url) {
|
||||
String normalized = FeedUtils.normalizeURL(url);
|
||||
@@ -29,4 +49,19 @@ public class FeedService {
|
||||
return feed;
|
||||
}
|
||||
|
||||
public byte[] fetchFavicon(Feed feed) {
|
||||
|
||||
byte[] icon = null;
|
||||
for (AbstractFaviconFetcher faviconFetcher : faviconFetchers) {
|
||||
icon = faviconFetcher.fetch(feed);
|
||||
if (icon != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (icon == null) {
|
||||
icon = defaultFavicon;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.commafeed.backend.service;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -23,12 +26,13 @@ import com.commafeed.frontend.model.UnreadCount;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class FeedSubscriptionService {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class FeedSubscriptionException extends RuntimeException {
|
||||
public FeedSubscriptionException(String msg) {
|
||||
private FeedSubscriptionException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -87,16 +91,6 @@ public class FeedSubscriptionService {
|
||||
}
|
||||
}
|
||||
|
||||
public UnreadCount getUnreadCount(User user, FeedSubscription sub) {
|
||||
UnreadCount count = cache.getUnreadCount(sub);
|
||||
if (count == null) {
|
||||
log.debug("unread count cache miss for {}", Models.getId(sub));
|
||||
count = feedEntryStatusDAO.getUnreadCount(user, sub);
|
||||
cache.setUnreadCount(sub, count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public Map<Long, UnreadCount> getUnreadCount(User user) {
|
||||
Map<Long, UnreadCount> map = Maps.newHashMap();
|
||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
||||
@@ -106,4 +100,14 @@ public class FeedSubscriptionService {
|
||||
return map;
|
||||
}
|
||||
|
||||
private UnreadCount getUnreadCount(User user, FeedSubscription sub) {
|
||||
UnreadCount count = cache.getUnreadCount(sub);
|
||||
if (count == null) {
|
||||
log.debug("unread count cache miss for {}", Models.getId(sub));
|
||||
count = feedEntryStatusDAO.getUnreadCount(user, sub);
|
||||
cache.setUnreadCount(sub, count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package com.commafeed.backend.service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
@@ -11,7 +14,8 @@ import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class FeedUpdateService {
|
||||
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
@@ -21,9 +22,9 @@ import com.commafeed.backend.model.User;
|
||||
* Mailing service
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@RequiredArgsConstructor
|
||||
public class MailService implements Serializable {
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class MailService {
|
||||
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
// taken from http://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html
|
||||
@SuppressWarnings("serial")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class PasswordEncryptionService implements Serializable {
|
||||
|
||||
public boolean authenticate(String attemptedPassword, byte[] encryptedPassword, byte[] salt) {
|
||||
if (StringUtils.isBlank(attemptedPassword)) {
|
||||
return false;
|
||||
}
|
||||
// Encrypt the clear-text password using the same salt that was used to
|
||||
// encrypt the original password
|
||||
byte[] encryptedAttemptedPassword = null;
|
||||
@@ -28,9 +38,13 @@ public class PasswordEncryptionService implements Serializable {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (encryptedAttemptedPassword == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Authentication succeeds if encrypted password that the user entered
|
||||
// is equal to the stored hash
|
||||
return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);
|
||||
return MessageDigest.isEqual(encryptedPassword, encryptedAttemptedPassword);
|
||||
}
|
||||
|
||||
public byte[] getEncryptedPassword(String password, byte[] salt) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.commafeed.backend.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -31,7 +33,8 @@ import com.google.common.collect.Lists;
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class PubSubService {
|
||||
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
@@ -5,8 +5,8 @@ import io.dropwizard.lifecycle.Managed;
|
||||
import java.sql.Connection;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import liquibase.Liquibase;
|
||||
@@ -17,6 +17,7 @@ import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||
import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.structure.DatabaseObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
@@ -30,17 +31,13 @@ import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class StartupService implements Managed {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
private UserDAO userDAO;
|
||||
private UserService userService;
|
||||
|
||||
public StartupService(SessionFactory sessionFactory, UserDAO userDAO, UserService userService) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.userDAO = userDAO;
|
||||
this.userService = userService;
|
||||
}
|
||||
private final SessionFactory sessionFactory;
|
||||
private final UserDAO userDAO;
|
||||
private final UserService userService;
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
@@ -58,14 +55,12 @@ public class StartupService implements Managed {
|
||||
|
||||
private void updateSchema() {
|
||||
try {
|
||||
Context context = null;
|
||||
Connection connection = null;
|
||||
try {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader classLoader = currentThread.getContextClassLoader();
|
||||
ResourceAccessor accessor = new ClassLoaderResourceAccessor(classLoader);
|
||||
|
||||
context = new InitialContext();
|
||||
DataSource dataSource = getDataSource(sessionFactory);
|
||||
connection = dataSource.getConnection();
|
||||
JdbcConnection jdbcConnection = new JdbcConnection(connection);
|
||||
@@ -85,9 +80,6 @@ public class StartupService implements Managed {
|
||||
Liquibase liq = new Liquibase("migrations.xml", accessor, database);
|
||||
liq.update("prod");
|
||||
} finally {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@ import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
@@ -17,20 +19,26 @@ import com.commafeed.backend.dao.UserSettingsDAO;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.backend.service.internal.PostLoginActivities;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class UserService {
|
||||
|
||||
private final FeedCategoryDAO feedCategoryDAO;
|
||||
private final UserDAO userDAO;
|
||||
private final UserSettingsDAO userSettingsDAO;
|
||||
|
||||
private final FeedSubscriptionService feedSubscriptionService;
|
||||
private final PasswordEncryptionService encryptionService;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
private final PostLoginActivities postLoginActivities;
|
||||
|
||||
/**
|
||||
* try to log in with given credentials
|
||||
*/
|
||||
public Optional<User> login(String nameOrEmail, String password) {
|
||||
if (nameOrEmail == null || password == null) {
|
||||
return Optional.absent();
|
||||
@@ -43,31 +51,16 @@ public class UserService {
|
||||
if (user != null && !user.isDisabled()) {
|
||||
boolean authenticated = encryptionService.authenticate(password, user.getPassword(), user.getSalt());
|
||||
if (authenticated) {
|
||||
Date lastLogin = user.getLastLogin();
|
||||
Date now = new Date();
|
||||
|
||||
boolean saveUser = false;
|
||||
// only update lastLogin field every hour in order to not
|
||||
// invalidate the cache everytime someone logs in
|
||||
if (lastLogin == null || lastLogin.before(DateUtils.addHours(now, -1))) {
|
||||
user.setLastLogin(now);
|
||||
saveUser = true;
|
||||
}
|
||||
if (config.getApplicationSettings().isHeavyLoad()
|
||||
&& (user.getLastFullRefresh() == null || user.getLastFullRefresh().before(DateUtils.addMinutes(now, -30)))) {
|
||||
user.setLastFullRefresh(now);
|
||||
saveUser = true;
|
||||
feedSubscriptionService.refreshAll(user);
|
||||
}
|
||||
if (saveUser) {
|
||||
userDAO.saveOrUpdate(user);
|
||||
}
|
||||
return Optional.fromNullable(user);
|
||||
performPostLoginActivities(user);
|
||||
return Optional.of(user);
|
||||
}
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* try to log in with given api key
|
||||
*/
|
||||
public Optional<User> login(String apiKey) {
|
||||
if (apiKey == null) {
|
||||
return Optional.absent();
|
||||
@@ -75,11 +68,19 @@ public class UserService {
|
||||
|
||||
User user = userDAO.findByApiKey(apiKey);
|
||||
if (user != null && !user.isDisabled()) {
|
||||
return Optional.fromNullable(user);
|
||||
performPostLoginActivities(user);
|
||||
return Optional.of(user);
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
/**
|
||||
* should triggers after successful login
|
||||
*/
|
||||
public void performPostLoginActivities(User user) {
|
||||
postLoginActivities.executeFor(user);
|
||||
}
|
||||
|
||||
public User register(String name, String password, String email, Collection<Role> roles) {
|
||||
return register(name, password, email, roles, false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.commafeed.backend.service.internal;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.service.FeedSubscriptionService;
|
||||
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class PostLoginActivities {
|
||||
|
||||
private final UserDAO userDAO;
|
||||
private final FeedSubscriptionService feedSubscriptionService;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
public void executeFor(User user) {
|
||||
Date lastLogin = user.getLastLogin();
|
||||
Date now = new Date();
|
||||
|
||||
boolean saveUser = false;
|
||||
// only update lastLogin field every hour in order to not
|
||||
// invalidate the cache every time someone logs in
|
||||
if (lastLogin == null || lastLogin.before(DateUtils.addHours(now, -1))) {
|
||||
user.setLastLogin(now);
|
||||
saveUser = true;
|
||||
}
|
||||
if (config.getApplicationSettings().isHeavyLoad() && user.shouldRefreshFeedsAt(now)) {
|
||||
feedSubscriptionService.refreshAll(user);
|
||||
user.setLastFullRefresh(now);
|
||||
saveUser = true;
|
||||
}
|
||||
if (saveUser) {
|
||||
userDAO.merge(user);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,14 +3,17 @@ package com.commafeed.backend.task;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.service.DatabaseCleaningService;
|
||||
import com.commafeed.backend.task.SchedulingService.ScheduledTask;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class OldStatusesCleanupTask implements ScheduledTask {
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class OldStatusesCleanupTask extends ScheduledTask {
|
||||
|
||||
private final CommaFeedConfiguration config;
|
||||
private final DatabaseCleaningService cleaner;
|
||||
@@ -25,7 +28,7 @@ public class OldStatusesCleanupTask implements ScheduledTask {
|
||||
|
||||
@Override
|
||||
public long getInitialDelay() {
|
||||
return 5;
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,26 +2,28 @@ package com.commafeed.backend.task;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.commafeed.backend.service.DatabaseCleaningService;
|
||||
import com.commafeed.backend.task.SchedulingService.ScheduledTask;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class OrphansCleanupTask implements ScheduledTask {
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@Singleton
|
||||
public class OrphansCleanupTask extends ScheduledTask {
|
||||
|
||||
private final DatabaseCleaningService cleaner;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
cleaner.cleanEntriesWithoutSubscriptions();
|
||||
cleaner.cleanFeedsWithoutSubscriptions();
|
||||
cleaner.cleanContentsWithoutEntries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInitialDelay() {
|
||||
return 30;
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
32
src/main/java/com/commafeed/backend/task/ScheduledTask.java
Normal file
32
src/main/java/com/commafeed/backend/task/ScheduledTask.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package com.commafeed.backend.task;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public abstract class ScheduledTask {
|
||||
protected abstract void run();
|
||||
|
||||
protected abstract long getInitialDelay();
|
||||
|
||||
protected abstract long getPeriod();
|
||||
|
||||
protected abstract TimeUnit getTimeUnit();
|
||||
|
||||
public void register(ScheduledExecutorService executor) {
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ScheduledTask.this.run();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.scheduleWithFixedDelay(runnable, getInitialDelay(), getPeriod(), getTimeUnit());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.commafeed.backend.task;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@Slf4j
|
||||
public class SchedulingService implements Managed {
|
||||
|
||||
public static interface ScheduledTask {
|
||||
void run();
|
||||
|
||||
long getInitialDelay();
|
||||
|
||||
long getPeriod();
|
||||
|
||||
TimeUnit getTimeUnit();
|
||||
}
|
||||
|
||||
private List<ScheduledTask> tasks = Lists.newArrayList();
|
||||
private ScheduledExecutorService executor;
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
executor = Executors.newScheduledThreadPool(tasks.size());
|
||||
for (final ScheduledTask task : tasks) {
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
task.run();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.scheduleWithFixedDelay(runnable, task.getInitialDelay(), task.getPeriod(), task.getTimeUnit());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
public void register(ScheduledTask task) {
|
||||
tasks.add(task);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.commafeed.frontend.auth;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
@@ -13,10 +12,10 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
import com.commafeed.CommaFeedApplication;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.backend.service.UserService;
|
||||
import com.commafeed.frontend.session.SessionHelper;
|
||||
import com.google.common.base.Optional;
|
||||
import com.sun.jersey.api.core.HttpContext;
|
||||
import com.sun.jersey.api.model.Parameter;
|
||||
@@ -37,39 +36,43 @@ public class SecurityCheckProvider implements InjectableProvider<SecurityCheck,
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class SecurityCheckInjectable<T> extends AbstractHttpContextInjectable<User> {
|
||||
static class SecurityCheckInjectable extends AbstractHttpContextInjectable<User> {
|
||||
private static final String PREFIX = "Basic";
|
||||
|
||||
private final HttpServletRequest request;
|
||||
private final SessionHelper sessionHelper;
|
||||
private final UserService userService;
|
||||
private final Role role;
|
||||
private final boolean apiKeyAllowed;
|
||||
|
||||
@Override
|
||||
public User getValue(HttpContext c) {
|
||||
Optional<User> user = cookieSessionLogin();
|
||||
Optional<User> user = apiKeyLogin(c);
|
||||
if (!user.isPresent()) {
|
||||
user = basicAuthenticationLogin(c);
|
||||
}
|
||||
if (!user.isPresent()) {
|
||||
user = apiKeyLogin(c);
|
||||
user = cookieSessionLogin();
|
||||
}
|
||||
|
||||
if (user.isPresent()) {
|
||||
return user.get();
|
||||
if (user.get().hasRole(role)) {
|
||||
return user.get();
|
||||
} else {
|
||||
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN)
|
||||
.entity("You don't have the required role to access this resource.").type(MediaType.TEXT_PLAIN_TYPE).build());
|
||||
}
|
||||
} else {
|
||||
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED)
|
||||
.entity("Credentials are required to access this resource.").type(MediaType.TEXT_PLAIN_TYPE).build());
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<User> cookieSessionLogin() {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
User user = (User) session.getAttribute(CommaFeedApplication.SESSION_USER);
|
||||
return Optional.fromNullable(user);
|
||||
Optional<User> cookieSessionLogin() {
|
||||
Optional<User> loggedInUser = sessionHelper.getLoggedInUser();
|
||||
if (loggedInUser.isPresent()) {
|
||||
userService.performPostLoginActivities(loggedInUser.get());
|
||||
}
|
||||
return Optional.absent();
|
||||
return loggedInUser;
|
||||
}
|
||||
|
||||
private Optional<User> basicAuthenticationLogin(HttpContext c) {
|
||||
@@ -84,10 +87,7 @@ public class SecurityCheckProvider implements InjectableProvider<SecurityCheck,
|
||||
if (i > 0) {
|
||||
String username = decoded.substring(0, i);
|
||||
String password = decoded.substring(i + 1);
|
||||
Optional<User> user = userService.login(username, password);
|
||||
if (user.isPresent() && user.get().hasRole(role)) {
|
||||
return user;
|
||||
}
|
||||
return userService.login(username, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,22 +96,19 @@ public class SecurityCheckProvider implements InjectableProvider<SecurityCheck,
|
||||
}
|
||||
|
||||
private Optional<User> apiKeyLogin(HttpContext c) {
|
||||
String apiKey = c.getUriInfo().getPathParameters().getFirst("apiKey");
|
||||
String apiKey = c.getUriInfo().getQueryParameters().getFirst("apiKey");
|
||||
if (apiKey != null && apiKeyAllowed) {
|
||||
Optional<User> user = userService.login(apiKey);
|
||||
if (user.isPresent() && user.get().hasRole(role)) {
|
||||
return user;
|
||||
}
|
||||
return userService.login(apiKey);
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
private HttpServletRequest request;
|
||||
private SessionHelper sessionHelper;
|
||||
private UserService userService;
|
||||
|
||||
public SecurityCheckProvider(@Context HttpServletRequest request, @Context UserService userService) {
|
||||
this.request = request;
|
||||
public SecurityCheckProvider(@Context HttpServletRequest req, @Context UserService userService) {
|
||||
this.sessionHelper = new SessionHelper(req);
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@@ -122,6 +119,6 @@ public class SecurityCheckProvider implements InjectableProvider<SecurityCheck,
|
||||
|
||||
@Override
|
||||
public Injectable<?> getInjectable(ComponentContext ic, SecurityCheck sc, Parameter c) {
|
||||
return new SecurityCheckInjectable<>(request, userService, sc.value(), sc.apiKeyAllowed());
|
||||
return new SecurityCheckInjectable(sessionHelper, userService, sc.value(), sc.apiKeyAllowed());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@ import com.commafeed.backend.model.FeedEntryStatus;
|
||||
import com.commafeed.backend.model.FeedEntryTag;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sun.syndication.feed.synd.SyndContentImpl;
|
||||
import com.sun.syndication.feed.synd.SyndEntry;
|
||||
import com.sun.syndication.feed.synd.SyndEntryImpl;
|
||||
import com.rometools.rome.feed.synd.SyndContent;
|
||||
import com.rometools.rome.feed.synd.SyndContentImpl;
|
||||
import com.rometools.rome.feed.synd.SyndEntry;
|
||||
import com.rometools.rome.feed.synd.SyndEntryImpl;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@@ -72,7 +73,7 @@ public class Entry implements Serializable {
|
||||
|
||||
SyndContentImpl content = new SyndContentImpl();
|
||||
content.setValue(getContent());
|
||||
entry.setContents(Arrays.asList(content));
|
||||
entry.setContents(Arrays.<SyndContent> asList(content));
|
||||
entry.setLink(getUrl());
|
||||
entry.setPublishedDate(getDate());
|
||||
return entry;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user